1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
#ifndef MEMPROF_DATA_INC
#define MEMPROF_DATA_INC
/*===-- MemProfData.inc - MemProf profiling runtime structures -*- C++ -*-=== *\
|*
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|* See https://llvm.org/LICENSE.txt for license information.
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|*
\*===----------------------------------------------------------------------===*/
/*
* This is the main file that defines all the data structure, signature,
* constant literals that are shared across profiling runtime library,
* and host tools (reader/writer).
*
* This file has two identical copies. The primary copy lives in LLVM and
* the other one sits in compiler-rt/include/profile directory. To make changes
* in this file, first modify the primary copy and copy it over to compiler-rt.
* Testing of any change in this file can start only after the two copies are
* synced up.
*
\*===----------------------------------------------------------------------===*/
#ifdef _MSC_VER
#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
#else
#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
#endif
// A 64-bit magic number to uniquely identify the raw binary memprof profile file.
#define MEMPROF_RAW_MAGIC_64 \
((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | \
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
// The version number of the raw binary format.
#define MEMPROF_RAW_VERSION 1ULL
namespace llvm {
namespace memprof {
// A struct describing the header used for the raw binary memprof profile format.
PACKED(struct Header {
uint64_t Magic;
uint64_t Version;
uint64_t TotalSize;
uint64_t SegmentOffset;
uint64_t MIBOffset;
uint64_t StackOffset;
});
// A struct describing the information necessary to describe a /proc/maps
// segment entry for a particular binary/library identified by its build id.
PACKED(struct SegmentEntry {
uint64_t Start;
uint64_t End;
uint64_t Offset;
// This field is unused until sanitizer procmaps support for build ids for
// Linux-Elf is implemented.
uint8_t BuildId[32] = {0};
SegmentEntry(uint64_t S, uint64_t E, uint64_t O) :
Start(S), End(E), Offset(O) {}
SegmentEntry(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
}
SegmentEntry& operator=(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
return *this;
}
bool operator==(const SegmentEntry& S) const {
return Start == S.Start &&
End == S.End &&
Offset == S.Offset;
}
});
// A struct representing the heap allocation characteristics of a particular
// runtime context. This struct is shared between the compiler-rt runtime and
// the raw profile reader. The indexed format uses a separate, self-describing
// backwards compatible format.
PACKED(struct MemInfoBlock {
uint32_t alloc_count;
uint64_t total_access_count, min_access_count, max_access_count;
uint64_t total_size;
uint32_t min_size, max_size;
uint32_t alloc_timestamp, dealloc_timestamp;
uint64_t total_lifetime;
uint32_t min_lifetime, max_lifetime;
uint32_t alloc_cpu_id, dealloc_cpu_id;
uint32_t num_migrated_cpu;
// Only compared to prior deallocated object currently.
uint32_t num_lifetime_overlaps;
uint32_t num_same_alloc_cpu;
uint32_t num_same_dealloc_cpu;
uint64_t data_type_id; // TODO: hash of type name
MemInfoBlock() : alloc_count(0) {}
MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp,
uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu)
: alloc_count(1), total_access_count(access_count),
min_access_count(access_count), max_access_count(access_count),
total_size(size), min_size(size), max_size(size),
alloc_timestamp(alloc_timestamp), dealloc_timestamp(dealloc_timestamp),
total_lifetime(dealloc_timestamp - alloc_timestamp),
min_lifetime(total_lifetime), max_lifetime(total_lifetime),
alloc_cpu_id(alloc_cpu), dealloc_cpu_id(dealloc_cpu),
num_lifetime_overlaps(0), num_same_alloc_cpu(0),
num_same_dealloc_cpu(0) {
num_migrated_cpu = alloc_cpu_id != dealloc_cpu_id;
}
void Merge(const MemInfoBlock &newMIB) {
alloc_count += newMIB.alloc_count;
total_access_count += newMIB.total_access_count;
min_access_count = newMIB.min_access_count < min_access_count ? newMIB.min_access_count : min_access_count;
max_access_count = newMIB.max_access_count < max_access_count ? newMIB.max_access_count : max_access_count;
total_size += newMIB.total_size;
min_size = newMIB.min_size < min_size ? newMIB.min_size : min_size;
max_size = newMIB.max_size < max_size ? newMIB.max_size : max_size;
total_lifetime += newMIB.total_lifetime;
min_lifetime = newMIB.min_lifetime < min_lifetime ? newMIB.min_lifetime : min_lifetime;
max_lifetime = newMIB.max_lifetime > max_lifetime ? newMIB.max_lifetime : max_lifetime;
// We know newMIB was deallocated later, so just need to check if it was
// allocated before last one deallocated.
num_lifetime_overlaps += newMIB.alloc_timestamp < dealloc_timestamp;
alloc_timestamp = newMIB.alloc_timestamp;
dealloc_timestamp = newMIB.dealloc_timestamp;
num_same_alloc_cpu += alloc_cpu_id == newMIB.alloc_cpu_id;
num_same_dealloc_cpu += dealloc_cpu_id == newMIB.dealloc_cpu_id;
alloc_cpu_id = newMIB.alloc_cpu_id;
dealloc_cpu_id = newMIB.dealloc_cpu_id;
}
});
} // namespace memprof
} // namespace llvm
#endif
|