Skip to content

Commit 8306968

Browse files
committed
[memprof] Move the meminfo block struct to MemProfData.inc.
The definition of the MemInfoBlock is shared between the memprof compiler-rt runtime and llvm/lib/ProfileData/. This change removes the memprof_meminfoblock header and moves the struct to the shared include file. To enable this sharing, the Print method is moved to the memprof_allocator (the only place it is used) and the remaining uses are updated to refer to the MemInfoBlock defined in the MemProfData.inc file. Also a couple of other minor changes which improve usability of the types in MemProfData.inc. * Update the PACKED macro to handle commas. * Add constructors and equality operators. * Don't initialize the buildid field. Differential Revision: https://reviews.llvm.org/D116780
1 parent 702c0cf commit 8306968

File tree

8 files changed

+265
-159
lines changed

8 files changed

+265
-159
lines changed

compiler-rt/include/profile/MemProfData.inc

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@
2020
*
2121
\*===----------------------------------------------------------------------===*/
2222

23-
2423
#ifdef _MSC_VER
25-
#define PACKED(__decl__) __pragma(pack(push,1)) __decl__ __pragma(pack(pop))
24+
#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
2625
#else
27-
#define PACKED(__decl__) __decl__ __attribute__((__packed__))
26+
#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
2827
#endif
2928

3029
// A 64-bit magic number to uniquely identify the raw binary memprof profile file.
@@ -47,14 +46,106 @@ PACKED(struct Header {
4746
uint64_t StackOffset;
4847
});
4948

49+
5050
// A struct describing the information necessary to describe a /proc/maps
5151
// segment entry for a particular binary/library identified by its build id.
5252
PACKED(struct SegmentEntry {
5353
uint64_t Start;
5454
uint64_t End;
5555
uint64_t Offset;
56-
uint8_t BuildId[32];
56+
// This field is unused until sanitizer procmaps support for build ids for
57+
// Linux-Elf is implemented.
58+
uint8_t BuildId[32] = {0};
59+
60+
SegmentEntry(uint64_t S, uint64_t E, uint64_t O) :
61+
Start(S), End(E), Offset(O) {}
62+
63+
SegmentEntry(const SegmentEntry& S) {
64+
Start = S.Start;
65+
End = S.End;
66+
Offset = S.Offset;
67+
}
68+
69+
SegmentEntry& operator=(const SegmentEntry& S) {
70+
Start = S.Start;
71+
End = S.End;
72+
Offset = S.Offset;
73+
return *this;
74+
}
75+
76+
bool operator==(const SegmentEntry& S) const {
77+
return Start == S.Start &&
78+
End == S.End &&
79+
Offset == S.Offset;
80+
}
5781
});
82+
83+
// A struct representing the heap allocation characteristics of a particular
84+
// runtime context. This struct is shared between the compiler-rt runtime and
85+
// the raw profile reader. The indexed format uses a separate, self-describing
86+
// backwards compatible format.
87+
PACKED(struct MemInfoBlock {
88+
uint32_t alloc_count;
89+
uint64_t total_access_count, min_access_count, max_access_count;
90+
uint64_t total_size;
91+
uint32_t min_size, max_size;
92+
uint32_t alloc_timestamp, dealloc_timestamp;
93+
uint64_t total_lifetime;
94+
uint32_t min_lifetime, max_lifetime;
95+
uint32_t alloc_cpu_id, dealloc_cpu_id;
96+
uint32_t num_migrated_cpu;
97+
98+
// Only compared to prior deallocated object currently.
99+
uint32_t num_lifetime_overlaps;
100+
uint32_t num_same_alloc_cpu;
101+
uint32_t num_same_dealloc_cpu;
102+
103+
uint64_t data_type_id; // TODO: hash of type name
104+
105+
MemInfoBlock() : alloc_count(0) {}
106+
107+
MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
108+
uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
109+
: alloc_count(1), total_access_count(access_count),
110+
min_access_count(access_count), max_access_count(access_count),
111+
total_size(size), min_size(size), max_size(size),
112+
alloc_timestamp(alloc_timestamp), dealloc_timestamp(dealloc_timestamp),
113+
total_lifetime(dealloc_timestamp - alloc_timestamp),
114+
min_lifetime(total_lifetime), max_lifetime(total_lifetime),
115+
alloc_cpu_id(alloc_cpu), dealloc_cpu_id(dealloc_cpu),
116+
num_lifetime_overlaps(0), num_same_alloc_cpu(0),
117+
num_same_dealloc_cpu(0) {
118+
num_migrated_cpu = alloc_cpu_id != dealloc_cpu_id;
119+
}
120+
121+
void Merge(const MemInfoBlock &newMIB) {
122+
alloc_count += newMIB.alloc_count;
123+
124+
total_access_count += newMIB.total_access_count;
125+
min_access_count = newMIB.min_access_count < min_access_count ? newMIB.min_access_count : min_access_count;
126+
max_access_count = newMIB.max_access_count < max_access_count ? newMIB.max_access_count : max_access_count;
127+
128+
total_size += newMIB.total_size;
129+
min_size = newMIB.min_size < min_size ? newMIB.min_size : min_size;
130+
max_size = newMIB.max_size < max_size ? newMIB.max_size : max_size;
131+
132+
total_lifetime += newMIB.total_lifetime;
133+
min_lifetime = newMIB.min_lifetime < min_lifetime ? newMIB.min_lifetime : min_lifetime;
134+
max_lifetime = newMIB.max_lifetime > max_lifetime ? newMIB.max_lifetime : max_lifetime;
135+
136+
// We know newMIB was deallocated later, so just need to check if it was
137+
// allocated before last one deallocated.
138+
num_lifetime_overlaps += newMIB.alloc_timestamp < dealloc_timestamp;
139+
alloc_timestamp = newMIB.alloc_timestamp;
140+
dealloc_timestamp = newMIB.dealloc_timestamp;
141+
142+
num_same_alloc_cpu += alloc_cpu_id == newMIB.alloc_cpu_id;
143+
num_same_dealloc_cpu += dealloc_cpu_id == newMIB.dealloc_cpu_id;
144+
alloc_cpu_id = newMIB.alloc_cpu_id;
145+
dealloc_cpu_id = newMIB.dealloc_cpu_id;
146+
}
147+
});
148+
58149
} // namespace memprof
59150
} // namespace llvm
60151

compiler-rt/lib/memprof/memprof_allocator.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515

1616
#include "memprof_allocator.h"
1717
#include "memprof_mapping.h"
18-
#include "memprof_meminfoblock.h"
1918
#include "memprof_mibmap.h"
2019
#include "memprof_rawprofile.h"
2120
#include "memprof_stack.h"
2221
#include "memprof_thread.h"
22+
#include "profile/MemProfData.inc"
2323
#include "sanitizer_common/sanitizer_allocator_checks.h"
2424
#include "sanitizer_common/sanitizer_allocator_interface.h"
2525
#include "sanitizer_common/sanitizer_allocator_report.h"
@@ -36,6 +36,42 @@
3636
#include <time.h>
3737

3838
namespace __memprof {
39+
namespace {
40+
using ::llvm::memprof::MemInfoBlock;
41+
42+
void Print(const MemInfoBlock &M, const u64 id, bool print_terse) {
43+
u64 p;
44+
45+
if (print_terse) {
46+
p = M.total_size * 100 / M.alloc_count;
47+
Printf("MIB:%llu/%u/%llu.%02llu/%u/%u/", id, M.alloc_count, p / 100,
48+
p % 100, M.min_size, M.max_size);
49+
p = M.total_access_count * 100 / M.alloc_count;
50+
Printf("%llu.%02llu/%llu/%llu/", p / 100, p % 100, M.min_access_count,
51+
M.max_access_count);
52+
p = M.total_lifetime * 100 / M.alloc_count;
53+
Printf("%llu.%02llu/%u/%u/", p / 100, p % 100, M.min_lifetime,
54+
M.max_lifetime);
55+
Printf("%u/%u/%u/%u\n", M.num_migrated_cpu, M.num_lifetime_overlaps,
56+
M.num_same_alloc_cpu, M.num_same_dealloc_cpu);
57+
} else {
58+
p = M.total_size * 100 / M.alloc_count;
59+
Printf("Memory allocation stack id = %llu\n", id);
60+
Printf("\talloc_count %u, size (ave/min/max) %llu.%02llu / %u / %u\n",
61+
M.alloc_count, p / 100, p % 100, M.min_size, M.max_size);
62+
p = M.total_access_count * 100 / M.alloc_count;
63+
Printf("\taccess_count (ave/min/max): %llu.%02llu / %llu / %llu\n", p / 100,
64+
p % 100, M.min_access_count, M.max_access_count);
65+
p = M.total_lifetime * 100 / M.alloc_count;
66+
Printf("\tlifetime (ave/min/max): %llu.%02llu / %u / %u\n", p / 100,
67+
p % 100, M.min_lifetime, M.max_lifetime);
68+
Printf("\tnum migrated: %u, num lifetime overlaps: %u, num same alloc "
69+
"cpu: %u, num same dealloc_cpu: %u\n",
70+
M.num_migrated_cpu, M.num_lifetime_overlaps, M.num_same_alloc_cpu,
71+
M.num_same_dealloc_cpu);
72+
}
73+
}
74+
} // namespace
3975

4076
static int GetCpuId(void) {
4177
// _memprof_preinit is called via the preinit_array, which subsequently calls
@@ -240,7 +276,7 @@ struct Allocator {
240276
static void PrintCallback(const uptr Key, LockedMemInfoBlock *const &Value,
241277
void *Arg) {
242278
SpinMutexLock(&Value->mutex);
243-
Value->mib.Print(Key, bool(Arg));
279+
Print(Value->mib, Key, bool(Arg));
244280
}
245281

246282
void FinishAndWrite() {

compiler-rt/lib/memprof/memprof_meminfoblock.h

Lines changed: 0 additions & 116 deletions
This file was deleted.

compiler-rt/lib/memprof/memprof_mibmap.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "memprof_mibmap.h"
14+
#include "profile/MemProfData.inc"
1415
#include "sanitizer_common/sanitizer_allocator_internal.h"
1516
#include "sanitizer_common/sanitizer_mutex.h"
1617

1718
namespace __memprof {
19+
using ::llvm::memprof::MemInfoBlock;
1820

1921
void InsertOrMerge(const uptr Id, const MemInfoBlock &Block, MIBMapTy &Map) {
2022
MIBMapTy::Handle h(&Map, static_cast<uptr>(Id), /*remove=*/false,

compiler-rt/lib/memprof/memprof_mibmap.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
#ifndef MEMPROF_MIBMAP_H_
22
#define MEMPROF_MIBMAP_H_
33

4-
#include "memprof_meminfoblock.h"
4+
#include <stdint.h>
5+
6+
#include "profile/MemProfData.inc"
57
#include "sanitizer_common/sanitizer_addrhashmap.h"
68
#include "sanitizer_common/sanitizer_mutex.h"
79

810
namespace __memprof {
911

1012
struct LockedMemInfoBlock {
1113
__sanitizer::StaticSpinMutex mutex;
12-
MemInfoBlock mib;
14+
::llvm::memprof::MemInfoBlock mib;
1315
};
1416

1517
// The MIB map stores a mapping from stack ids to MemInfoBlocks.
1618
typedef __sanitizer::AddrHashMap<LockedMemInfoBlock *, 200003> MIBMapTy;
1719

1820
// Insert a new MemInfoBlock or merge with an existing block identified by the
1921
// stack id.
20-
void InsertOrMerge(const uptr Id, const MemInfoBlock &Block, MIBMapTy &Map);
22+
void InsertOrMerge(const uptr Id, const ::llvm::memprof::MemInfoBlock &Block,
23+
MIBMapTy &Map);
2124

2225
} // namespace __memprof
2326

compiler-rt/lib/memprof/memprof_rawprofile.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#include <stdlib.h>
33
#include <string.h>
44

5-
#include "memprof_meminfoblock.h"
65
#include "memprof_rawprofile.h"
76
#include "profile/MemProfData.inc"
87
#include "sanitizer_common/sanitizer_allocator_internal.h"
@@ -16,6 +15,7 @@
1615

1716
namespace __memprof {
1817
using ::__sanitizer::Vector;
18+
using ::llvm::memprof::MemInfoBlock;
1919
using SegmentEntry = ::llvm::memprof::SegmentEntry;
2020
using Header = ::llvm::memprof::Header;
2121

@@ -65,11 +65,8 @@ void SerializeSegmentsToBuffer(MemoryMappingLayoutBase &Layout,
6565

6666
for (Layout.Reset(); Layout.Next(&segment);) {
6767
if (segment.IsReadable() && segment.IsExecutable()) {
68-
SegmentEntry Entry{};
69-
Entry.Start = segment.start;
70-
Entry.End = segment.end;
71-
Entry.Offset = segment.offset;
72-
memcpy(Entry.BuildId, segment.uuid, sizeof(segment.uuid));
68+
// TODO: Record segment.uuid when it is implemented for Linux-Elf.
69+
SegmentEntry Entry(segment.start, segment.end, segment.offset);
7370
memcpy(Ptr, &Entry, sizeof(SegmentEntry));
7471
Ptr += sizeof(SegmentEntry);
7572
NumSegmentsRecorded++;

0 commit comments

Comments
 (0)