Skip to content

Commit de3bc14

Browse files
authored
Merge PR #172 from tudasc/devel
2 parents 8166cec + f4d0ba9 commit de3bc14

File tree

17 files changed

+272
-153
lines changed

17 files changed

+272
-153
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cmake_minimum_required(VERSION 3.20)
22

33
project(typeart
4-
VERSION 2.0
4+
VERSION 2.1
55
HOMEPAGE_URL https://github.com/tudasc/TypeART
66
DESCRIPTION "LLVM-based type and memory allocation tracking sanitizer"
77
)

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ its [project page](https://itc.rwth-aachen.de/must/).
6262
6363
Using TypeART involves two phases:
6464
65-
1. Compilation: Compile your code with Clang/LLVM (version 14) using the TypeART LLVM pass plugin. The plugin (1) serializes static type information to a file and (2) instruments relevant allocations. See [Section 1.1](#11-compiling-a-target-code).
65+
1. Compilation: Compile your code with Clang/LLVM using the TypeART LLVM pass plugin. The plugin (1) serializes static type information to a file and (2) instruments relevant allocations. See [Section 1.1](#11-compiling-a-target-code).
6666
2. Execution: Run the instrumented program with a TypeART runtime client, which uses the callback data to perform analysis facilitating the static type information. See [Section 1.2](#12-executing-an-instrumented-target-code).
6767
6868
### 1.1 Compiling a target code
@@ -279,7 +279,7 @@ To compile and run the demo targets:
279279

280280
## 2. Building TypeART
281281

282-
TypeART supports LLVM version 14 and 18 and CMake version >= 3.20.
282+
TypeART supports LLVM version 14, 18 and 19, and CMake version >= 3.20.
283283

284284
### 2.1 Optional software requirements
285285

@@ -378,7 +378,7 @@ Example using CMake [FetchContent](https://cmake.org/cmake/help/latest/module/Fe
378378
FetchContent_Declare(
379379
typeart
380380
GIT_REPOSITORY https://github.com/tudasc/TypeART
381-
GIT_TAG v1.9.1
381+
GIT_TAG v2.1
382382
GIT_SHALLOW 1
383383
)
384384
FetchContent_MakeAvailable(typeart)

externals/dimeta/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FetchContent_Declare(
22
llvm-dimeta
33
GIT_REPOSITORY https://github.com/ahueck/llvm-dimeta
4-
GIT_TAG v0.2.0
4+
GIT_TAG v0.3.0
55
GIT_SHALLOW 1
66
)
77

lib/passes/typegen/dimeta/DimetaTypeGen.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ std::optional<typeart_builtin_type> get_builtin_typeid(const dimeta::QualifiedFu
231231
const auto extent = type.type.extent;
232232
const auto encoding = type.type.encoding;
233233

234+
if (type.type.name == "wchar_t" || type.typedef_name == "wchar_t") {
235+
// Clang 18 typedef's wchar_t
236+
return TYPEART_WCHAR;
237+
}
238+
234239
switch (encoding) {
235240
case FundamentalType::Encoding::kVtablePtr:
236241
return TYPEART_VTABLE_POINTER;

lib/runtime/AccessCountPrinter.h

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -54,30 +54,33 @@ void serialize(const Recorder& r, std::ostringstream& buf) {
5454
if constexpr (std::is_same_v<Recorder, NoneRecorder>) {
5555
return;
5656
} else {
57-
const auto memory_use = memory::estimate(r.getMaxStackAllocs(), r.getMaxHeapAllocs(), r.getGlobalAllocs());
58-
59-
Table t("Alloc Stats from softcounters");
60-
t.wrap_length_ = true;
61-
t.put(Row::make("Total heap", r.getHeapAllocs(), r.getHeapArray()));
62-
t.put(Row::make("Total stack", r.getStackAllocs(), r.getStackArray()));
63-
t.put(Row::make("Total global", r.getGlobalAllocs(), r.getGlobalArray()));
64-
t.put(Row::make("Max. Heap Allocs", r.getMaxHeapAllocs()));
65-
t.put(Row::make("Max. Stack Allocs", r.getMaxStackAllocs()));
66-
t.put(Row::make("Addresses checked", r.getAddrChecked()));
67-
t.put(Row::make("Distinct Addresses checked", r.getSeen().size()));
68-
t.put(Row::make("Addresses re-used", r.getAddrReuses()));
69-
t.put(Row::make("Addresses missed", r.getAddrMissing()));
70-
t.put(Row::make("Distinct Addresses missed", r.getMissing().size()));
71-
t.put(Row::make("Total free heap", r.getHeapAllocsFree(), r.getHeapArrayFree()));
72-
t.put(Row::make("Total free stack", r.getStackAllocsFree(), r.getStackArrayFree()));
73-
t.put(Row::make("OMP Stack/Heap/Free", r.getOmpStackCalls(), r.getOmpHeapCalls(), r.getOmpFreeCalls()));
74-
t.put(Row::make("Null/Zero/NullZero Addr", r.getNullAlloc(), r.getZeroAlloc(), r.getNullAndZeroAlloc()));
75-
t.put(Row::make("User-def. types", r.getNumUDefTypes()));
76-
t.put(Row::make("Estimated memory use (KiB)", size_t(std::round(memory_use.map + memory_use.stack))));
77-
t.put(Row::make("Bytes per node map/stack", memory::MemOverhead::perNodeSizeMap,
78-
memory::MemOverhead::perNodeSizeStack));
79-
80-
t.print(buf);
57+
// const auto memory_use = memory::estimate(r.getMaxStackAllocs(), r.getMaxHeapAllocs(), r.getGlobalAllocs());
58+
59+
Table overview_table("Alloc Stats from softcounters");
60+
overview_table.wrap_length_ = true;
61+
overview_table.put(Row::make("Total heap", r.getHeapAllocs(), r.getHeapArray()));
62+
overview_table.put(Row::make("Total stack", r.getStackAllocs(), r.getStackArray()));
63+
overview_table.put(Row::make("Total global", r.getGlobalAllocs(), r.getGlobalArray()));
64+
overview_table.put(Row::make("Max. heap", r.getMaxHeapAllocs()));
65+
overview_table.put(Row::make("Max. stack", r.getMaxStackAllocs()));
66+
overview_table.put(Row::make("Addresses checked", r.getAddrChecked()));
67+
overview_table.put(Row::make("Distinct addresses checked", r.getSeen().size()));
68+
overview_table.put(Row::make("Addresses re-used", r.getAddrReuses()));
69+
overview_table.put(Row::make("Addresses missed", r.getAddrMissing()));
70+
overview_table.put(Row::make("Distinct addresses missed", r.getMissing().size()));
71+
overview_table.put(Row::make("Total free heap", r.getHeapAllocsFree(), r.getHeapArrayFree()));
72+
overview_table.put(Row::make("Total free stack", r.getStackAllocsFree(), r.getStackArrayFree()));
73+
overview_table.put(
74+
Row::make("OMP stack/heap/free", r.getOmpStackCalls(), r.getOmpHeapCalls(), r.getOmpFreeCalls()));
75+
overview_table.put(
76+
Row::make("Null/Zero/NullZero addr", r.getNullAlloc(), r.getZeroAlloc(), r.getNullAndZeroAlloc()));
77+
overview_table.put(Row::make("User-def. types", r.getNumUDefTypes()));
78+
overview_table.put(Row::make("Distinct query types", r.getTypeQuery().size()));
79+
// t.put(Row::make("Estimated memory use (KiB)", size_t(std::round(memory_use.map + memory_use.stack))));
80+
// t.put(Row::make("Bytes per node map/stack", memory::MemOverhead::perNodeSizeMap,
81+
// memory::MemOverhead::perNodeSizeStack));
82+
83+
overview_table.print(buf);
8184

8285
std::set<int> type_id_set;
8386
const auto fill_set = [&type_id_set](const auto& map) {
@@ -98,27 +101,52 @@ void serialize(const Recorder& r, std::ostringstream& buf) {
98101
}
99102
return 0LL;
100103
};
101-
102-
Table type_table("Allocation type detail (heap, stack, global)");
103-
type_table.table_header_ = '#';
104-
for (auto type_id : type_id_set) {
105-
type_table.put(Row::make(std::to_string(type_id), count(r.getHeapAlloc(), type_id),
106-
count(r.getStackAlloc(), type_id), count(r.getGlobalAlloc(), type_id),
107-
typeart_get_type_name(type_id)));
104+
{
105+
Table type_table("Allocation type detail (heap, stack, global)");
106+
type_table.table_header_ = '#';
107+
for (auto type_id : type_id_set) {
108+
type_table.put(Row::make(std::to_string(type_id), count(r.getHeapAlloc(), type_id),
109+
count(r.getStackAlloc(), type_id), count(r.getGlobalAlloc(), type_id),
110+
typeart_get_type_name(type_id)));
111+
}
112+
type_table.print(buf);
108113
}
114+
{
115+
Table type_table_free("Free allocation type detail (heap, stack)");
116+
type_table_free.table_header_ = '#';
117+
for (auto type_id : type_id_set) {
118+
const auto count_type_h = count(r.getHeapFree(), type_id);
119+
const auto count_type_s = count(r.getStackFree(), type_id);
120+
if (count_type_h == 0 && count_type_s == 0) {
121+
continue;
122+
}
123+
type_table_free.put(
124+
Row::make(std::to_string(type_id), count_type_h, count_type_s, typeart_get_type_name(type_id)));
125+
}
109126

110-
type_table.print(buf);
111-
112-
Table type_table_free("Free allocation type detail (heap, stack)");
113-
type_table_free.table_header_ = '#';
114-
for (auto type_id : type_id_set) {
115-
type_table_free.put(Row::make(std::to_string(type_id), count(r.getHeapFree(), type_id),
116-
count(r.getStackFree(), type_id), typeart_get_type_name(type_id)));
127+
type_table_free.print(buf);
117128
}
129+
{
130+
Table type_table_query("Query type detail");
131+
type_table_query.table_header_ = '#';
132+
const auto& query_map = r.getTypeQuery();
133+
std::set<int> query_id_set;
134+
for (const auto& [key, val] : query_map) {
135+
query_id_set.insert(key);
136+
}
137+
for (auto query_type_id : query_id_set) {
138+
const auto count_type = count(query_map, query_type_id);
139+
type_table_query.put(
140+
Row::make(std::to_string(query_type_id), count_type, typeart_get_type_name(query_type_id)));
141+
}
118142

119-
type_table_free.print(buf);
143+
type_table_query.print(buf);
144+
}
120145

121146
const auto numThreads = r.getNumThreads();
147+
if (numThreads < 2) {
148+
return;
149+
}
122150
std::stringstream ss;
123151
ss << "Per-thread counter values (" << numThreads << " threads)";
124152
Table thread_table(ss.str());

lib/runtime/AccessCounter.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ class AccessRecorder {
193193

194194
~AccessRecorder() = default;
195195

196+
inline void incTypeQuery(int type_id) {
197+
std::lock_guard lock(typeQueryMutex);
198+
++typeQuery[type_id];
199+
}
200+
196201
inline void incHeapAlloc(int typeId, size_t count) {
197202
++curHeapAllocs;
198203

@@ -446,6 +451,10 @@ class AccessRecorder {
446451
std::shared_lock slock(seenMutex);
447452
return seen;
448453
}
454+
TypeCountMap getTypeQuery() const {
455+
std::shared_lock slock(typeQueryMutex);
456+
return typeQuery;
457+
}
449458
TypeCountMap getStackAlloc() const {
450459
std::shared_lock slock(stackAllocMutex);
451460
return stackAlloc;
@@ -524,13 +533,18 @@ class AccessRecorder {
524533

525534
TypeCountMap heapFree;
526535
mutable MutexT heapFreeMutex;
536+
537+
TypeCountMap typeQuery;
538+
mutable MutexT typeQueryMutex;
527539
};
528540

529541
/**
530542
* Used for no-operations in counter methods when not using softcounters.
531543
*/
532544
class NoneRecorder {
533545
public:
546+
[[maybe_unused]] inline void incTypeQuery(int) {
547+
}
534548
[[maybe_unused]] inline void incHeapAlloc(int, size_t) {
535549
}
536550
[[maybe_unused]] inline void incStackAlloc(int, size_t) {

lib/runtime/RuntimeInterface.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ typedef struct typeart_type_info_t {
5959
typeart_base_type_info base_type_info; // API dependent
6060
} typeart_type_info;
6161

62+
typedef struct typeart_source_loc_t {
63+
char* file;
64+
char* function;
65+
unsigned line;
66+
} typeart_source_location;
67+
6268
/**
6369
* Determines the type and array element count at the given address.
6470
* For nested types with classes/structs, the containing type is resolved recursively, until an exact with the address
@@ -194,16 +200,25 @@ typeart_status typeart_get_return_address(const void* addr, const void** return_
194200
* caller.
195201
*
196202
* \param[in] addr The address.
197-
* \param[out] file The file where the address was created at.
198-
* \param[out] function The function where the address was created at.
199-
* \param[out] line The approximate line where the address was created at.
203+
* \param[out] source_loc The file/function/line where the address was created at.
200204
*
201205
* \return One of the following status codes:
202206
* - TYPEART_OK: Success.
203207
* - TYPEART_UNKNOWN_ADDRESS: The given address is either not allocated, or was not recorded by the runtime.
204208
* - TYPEART_ERROR: Memory could not be allocated.
205209
*/
206-
typeart_status typeart_get_source_location(const void* addr, char** file, char** function, char** line);
210+
typeart_status typeart_get_source_location(const void* addr, typeart_source_location* source_loc);
211+
212+
/**
213+
* Free previously allocated typeart_source_location.
214+
*
215+
* \param[in] source_loc The file/function/line where the address was created at.
216+
*
217+
* \return One of the following status codes:
218+
* - TYPEART_OK: Success.
219+
* - TYPEART_ERROR: source_loc was NULL.
220+
*/
221+
typeart_status typeart_free_source_location(typeart_source_location* source_loc);
207222

208223
/**
209224
* Given a type ID, this function provides information about the corresponding struct type.

0 commit comments

Comments
 (0)