[memprof] Use a new constructor of IndexedAllocationInfo (NFC) (#116920)
[llvm-project.git] / openmp / libompd / src / TargetValue.cpp
blob8818121cf4f3a1ec9e9e96fb9249a28bdc7568aa
1 /*
2 * TargetValue.cpp -- Access to target values using OMPD callbacks
3 */
5 //===----------------------------------------------------------------------===//
6 //
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11 //===----------------------------------------------------------------------===//
13 #include "TargetValue.h"
14 #include "Debug.h"
15 #include <cstring>
16 #include <fstream>
17 #include <iostream>
18 #include <sstream>
20 const ompd_callbacks_t *TValue::callbacks = NULL;
21 ompd_device_type_sizes_t TValue::type_sizes;
23 inline int ompd_sizeof(ompd_target_prim_types_t t) {
24 assert(t != ompd_type_max && "ompd_type_max should not be used anywhere");
25 assert(t != ompd_type_invalid && "request size of invalid type");
27 return (((char *)&TValue::type_sizes)[(int)t]);
30 TType &TTypeFactory::getType(ompd_address_space_context_t *context,
31 const char *typeName, ompd_addr_t segment) {
32 TType empty(true);
34 if (ttypes.find(context) == ttypes.end()) {
35 std::map<const char *, TType> empty;
36 ttypes[context] = empty;
39 auto t = ttypes.find(context);
40 auto i = t->second.find(typeName);
41 if (i == t->second.end())
42 i = t->second.insert(
43 i, std::make_pair(typeName, TType(context, typeName, segment)));
44 else
45 i->second.context = context;
47 return i->second;
50 TType::TType(ompd_address_space_context_t *_context, const char *_typeName,
51 ompd_addr_t _segment)
52 : typeSize(0), fieldOffsets(), descSegment(_segment), typeName(_typeName),
53 context(_context), isvoid(false) {}
55 ompd_rc_t TType::getSize(ompd_size_t *size) {
56 ompd_rc_t ret = ompd_rc_ok;
57 if (typeSize == 0) {
58 ompd_address_t symbolAddr;
59 ompd_size_t tmpSize;
60 std::stringstream ss;
61 ss << "ompd_sizeof__" << typeName;
63 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
64 &symbolAddr, NULL);
65 if (ret != ompd_rc_ok) {
66 dout << "missing symbol " << ss.str()
67 << " add this to ompd-specific.h:\nOMPD_SIZEOF(" << typeName
68 << ") \\" << std::endl;
69 return ret;
72 symbolAddr.segment = descSegment;
74 ret = TValue::callbacks->read_memory(
75 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
76 &(tmpSize));
77 if (ret != ompd_rc_ok)
78 return ret;
79 ret = TValue::callbacks->device_to_host(
80 context, &tmpSize, TValue::type_sizes.sizeof_long_long, 1, &(typeSize));
82 *size = typeSize;
83 return ret;
86 ompd_rc_t TType::getBitfieldMask(const char *fieldName,
87 uint64_t *bitfieldmask) {
88 ompd_rc_t ret = ompd_rc_ok;
89 auto i = bitfieldMasks.find(fieldName);
90 if (i == bitfieldMasks.end()) {
91 uint64_t tmpMask, bitfieldMask;
92 ompd_address_t symbolAddr;
93 std::stringstream ss;
94 ss << "ompd_bitfield__" << typeName << "__" << fieldName;
95 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
96 &symbolAddr, NULL);
97 if (ret != ompd_rc_ok) {
98 dout << "missing symbol " << ss.str()
99 << " add this to ompd-specific.h:\nOMPD_BITFIELD(" << typeName << ","
100 << fieldName << ") \\" << std::endl;
101 return ret;
103 symbolAddr.segment = descSegment;
105 ret = TValue::callbacks->read_memory(
106 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
107 &(tmpMask));
108 if (ret != ompd_rc_ok)
109 return ret;
110 ret = TValue::callbacks->device_to_host(context, &(tmpMask),
111 TValue::type_sizes.sizeof_long_long,
112 1, &(bitfieldMask));
113 if (ret != ompd_rc_ok) {
114 return ret;
116 i = bitfieldMasks.insert(i, std::make_pair(fieldName, bitfieldMask));
118 *bitfieldmask = i->second;
119 return ret;
122 ompd_rc_t TType::getElementOffset(const char *fieldName, ompd_size_t *offset) {
123 ompd_rc_t ret = ompd_rc_ok;
124 auto i = fieldOffsets.find(fieldName);
125 if (i == fieldOffsets.end()) {
126 ompd_size_t tmpOffset, fieldOffset;
127 ompd_address_t symbolAddr;
128 std::stringstream ss;
129 ss << "ompd_access__" << typeName << "__" << fieldName;
131 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
132 &symbolAddr, NULL);
133 if (ret != ompd_rc_ok) {
134 dout << "missing symbol " << ss.str()
135 << " add this to ompd-specific.h:\nOMPD_ACCESS(" << typeName << ","
136 << fieldName << ") \\" << std::endl;
137 return ret;
139 symbolAddr.segment = descSegment;
141 ret = TValue::callbacks->read_memory(
142 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
143 &(tmpOffset));
144 if (ret != ompd_rc_ok)
145 return ret;
146 ret = TValue::callbacks->device_to_host(context, &(tmpOffset),
147 TValue::type_sizes.sizeof_long_long,
148 1, &fieldOffset);
149 if (ret != ompd_rc_ok) {
150 return ret;
152 i = fieldOffsets.insert(i, std::make_pair(fieldName, fieldOffset));
154 *offset = i->second;
155 return ret;
158 ompd_rc_t TType::getElementSize(const char *fieldName, ompd_size_t *size) {
159 ompd_rc_t ret = ompd_rc_ok;
160 auto i = fieldSizes.find(fieldName);
161 if (i == fieldSizes.end()) {
162 ompd_size_t tmpOffset, fieldSize;
163 ompd_address_t symbolAddr;
164 std::stringstream ss;
165 ss << "ompd_sizeof__" << typeName << "__" << fieldName;
167 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
168 &symbolAddr, NULL);
169 if (ret != ompd_rc_ok) {
170 dout << "missing symbol " << ss.str()
171 << " add this to ompd-specific.h:\nOMPD_ACCESS(" << typeName << ","
172 << fieldName << ") \\" << std::endl;
173 return ret;
175 symbolAddr.segment = descSegment;
177 ret = TValue::callbacks->read_memory(
178 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
179 &(tmpOffset));
180 if (ret != ompd_rc_ok)
181 return ret;
182 ret = TValue::callbacks->device_to_host(context, &tmpOffset,
183 TValue::type_sizes.sizeof_long_long,
184 1, &fieldSize);
185 if (ret != ompd_rc_ok) {
186 return ret;
188 i = fieldSizes.insert(i, std::make_pair(fieldName, fieldSize));
190 *size = i->second;
191 return ret;
194 TValue::TValue(ompd_address_space_context_t *_context,
195 ompd_thread_context_t *_tcontext, const char *_valueName,
196 ompd_addr_t segment)
197 : errorState(ompd_rc_ok), type(&nullType), pointerLevel(0),
198 context(_context), tcontext(_tcontext), fieldSize(0) {
199 errorState.errorCode = callbacks->symbol_addr_lookup(
200 context, tcontext, _valueName, &symbolAddr, NULL);
201 symbolAddr.segment = segment;
204 TValue::TValue(ompd_address_space_context_t *_context,
205 ompd_thread_context_t *_tcontext, ompd_address_t addr)
206 : errorState(ompd_rc_ok), type(&nullType), pointerLevel(0),
207 context(_context), tcontext(_tcontext), symbolAddr(addr), fieldSize(0) {
208 if (addr.address == 0)
209 errorState.errorCode = ompd_rc_bad_input;
212 TValue &TValue::cast(const char *typeName) {
213 if (gotError())
214 return *this;
215 type = &tf.getType(context, typeName, symbolAddr.segment);
216 pointerLevel = 0;
217 assert(!type->isVoid() && "cast to invalid type failed");
218 return *this;
221 TValue &TValue::cast(const char *typeName, int _pointerLevel,
222 ompd_addr_t segment) {
223 if (gotError())
224 return *this;
225 type = &tf.getType(context, typeName, symbolAddr.segment);
226 pointerLevel = _pointerLevel;
227 symbolAddr.segment = segment;
228 assert(!type->isVoid() && "cast to invalid type failed");
229 return *this;
232 TValue TValue::dereference() const {
233 if (gotError())
234 return *this;
235 ompd_address_t tmpAddr;
236 assert(!type->isVoid() && "cannot work with void");
237 assert(pointerLevel > 0 && "cannot dereference non-pointer");
238 TValue ret = *this;
239 ret.pointerLevel--;
240 ret.errorState.errorCode = callbacks->read_memory(
241 context, tcontext, &symbolAddr, 1 * TValue::type_sizes.sizeof_pointer,
242 &(tmpAddr.address));
243 if (ret.errorState.errorCode != ompd_rc_ok)
244 return ret;
246 ret.errorState.errorCode = callbacks->device_to_host(
247 context, &(tmpAddr.address), TValue::type_sizes.sizeof_pointer, 1,
248 &(ret.symbolAddr.address));
249 if (ret.errorState.errorCode != ompd_rc_ok) {
250 return ret;
252 if (ret.symbolAddr.address == 0)
253 ret.errorState.errorCode = ompd_rc_unsupported;
254 return ret;
257 ompd_rc_t TValue::getAddress(ompd_address_t *addr) const {
258 *addr = symbolAddr;
259 if (symbolAddr.address == 0)
260 return ompd_rc_unsupported;
261 return errorState.errorCode;
264 ompd_rc_t TValue::getRawValue(void *buf, int count) {
265 if (errorState.errorCode != ompd_rc_ok)
266 return errorState.errorCode;
267 ompd_size_t size;
268 errorState.errorCode = type->getSize(&size);
269 if (errorState.errorCode != ompd_rc_ok)
270 return errorState.errorCode;
272 errorState.errorCode =
273 callbacks->read_memory(context, tcontext, &symbolAddr, size, buf);
274 return errorState.errorCode;
277 ompd_rc_t TValue::getString(const char **buf) {
278 *buf = 0;
279 if (gotError())
280 return getError();
282 TValue strValue = dereference();
283 if (strValue.gotError()) {
284 return strValue.getError();
287 if (!callbacks) {
288 return ompd_rc_error;
290 ompd_rc_t ret;
291 #define BUF_LEN 512
292 char *string_buffer;
294 // Allocate an extra byte, but pass only BUF_LEN to the tool
295 // so that we can detect truncation later.
296 ret = callbacks->alloc_memory(BUF_LEN + 1, (void **)&string_buffer);
297 if (ret != ompd_rc_ok) {
298 return ret;
300 string_buffer[BUF_LEN] = '\0';
302 // TODO: if we have not read in the complete string, we need to realloc
303 // 'string_buffer' and attempt reading again repeatedly till the entire string
304 // is read in.
305 ret = callbacks->read_string(context, tcontext, &strValue.symbolAddr, BUF_LEN,
306 (void *)string_buffer);
307 *buf = string_buffer;
308 // Check for truncation. The standard specifies that if a null byte is not
309 // among the first 'nbytes' bytes, the string placed in the buffer is not
310 // null-terminated. 'nbytes' is BUF_LEN in this case.
311 if (ret == ompd_rc_ok && strlen(string_buffer) == BUF_LEN) {
312 return ompd_rc_error;
314 return ret;
317 TBaseValue TValue::castBase(const char *varName) {
318 ompd_size_t size;
319 errorState.errorCode =
320 tf.getType(context, varName, symbolAddr.segment).getSize(&size);
321 return TBaseValue(*this, size);
324 TBaseValue TValue::castBase() const {
325 if (pointerLevel > 0)
326 return TBaseValue(*this, type_sizes.sizeof_pointer);
327 return TBaseValue(*this, fieldSize);
330 TBaseValue TValue::castBase(ompd_target_prim_types_t baseType) const {
331 return TBaseValue(*this, baseType);
334 TValue TValue::access(const char *fieldName) const {
335 if (gotError())
336 return *this;
337 TValue ret = *this;
338 assert(pointerLevel < 2 && "access to field element of pointer array failed");
339 if (pointerLevel == 1) // -> operator
340 ret = ret.dereference();
341 // we use *this for . operator
342 ompd_size_t offset;
343 ret.errorState.errorCode = type->getElementOffset(fieldName, &offset);
344 ret.errorState.errorCode = type->getElementSize(fieldName, &(ret.fieldSize));
345 ret.symbolAddr.address += offset;
347 return ret;
350 ompd_rc_t TValue::check(const char *bitfieldName, ompd_word_t *isSet) const {
351 if (gotError())
352 return getError();
353 int bitfield;
354 uint64_t bitfieldmask;
355 ompd_rc_t ret = this->castBase(ompd_type_int).getValue(&bitfield, 1);
356 if (ret != ompd_rc_ok)
357 return ret;
358 ret = type->getBitfieldMask(bitfieldName, &bitfieldmask);
359 *isSet = ((bitfield & bitfieldmask) != 0);
360 return ret;
363 TValue TValue::getArrayElement(int elemNumber) const {
364 if (gotError())
365 return *this;
366 TValue ret;
367 if (pointerLevel > 0) {
368 ret = dereference();
369 } else {
370 ret = *this;
372 if (ret.pointerLevel == 0) {
373 ompd_size_t size;
374 ret.errorState.errorCode = type->getSize(&size);
375 ret.symbolAddr.address += elemNumber * size;
376 } else {
377 ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
379 return ret;
382 TValue TValue::getPtrArrayElement(int elemNumber) const {
383 if (gotError()) {
384 return *this;
386 assert(pointerLevel > 0 && "This only works on arrays of pointers");
387 TValue ret = *this;
388 ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
389 return ret;
392 TBaseValue::TBaseValue(const TValue &_tvalue,
393 ompd_target_prim_types_t _baseType)
394 : TValue(_tvalue), baseTypeSize(ompd_sizeof(_baseType)) {}
395 TBaseValue::TBaseValue(const TValue &_tvalue, ompd_size_t _baseTypeSize)
396 : TValue(_tvalue), baseTypeSize(_baseTypeSize) {}
398 ompd_rc_t TBaseValue::getValue(void *buf, int count) {
399 if (errorState.errorCode != ompd_rc_ok)
400 return errorState.errorCode;
401 errorState.errorCode = callbacks->read_memory(context, tcontext, &symbolAddr,
402 count * baseTypeSize, buf);
403 if (errorState.errorCode != ompd_rc_ok)
404 return errorState.errorCode;
405 errorState.errorCode =
406 callbacks->device_to_host(context, buf, baseTypeSize, count, buf);
407 return errorState.errorCode;