1 | #ifndef MEMPROF_DATA_INC |
2 | #define MEMPROF_DATA_INC |
3 | /*===-- MemProfData.inc - MemProf profiling runtime structures -*- C++ -*-=== *\ |
4 | |* |
5 | |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
6 | |* See https://llvm.org/LICENSE.txt for license information. |
7 | |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
8 | |* |
9 | \*===----------------------------------------------------------------------===*/ |
10 | /* |
11 | * This is the main file that defines all the data structure, signature, |
12 | * constant literals that are shared across profiling runtime library, |
13 | * and host tools (reader/writer). |
14 | * |
15 | * This file has two identical copies. The primary copy lives in LLVM and |
16 | * the other one sits in compiler-rt/include/profile directory. To make changes |
17 | * in this file, first modify the primary copy and copy it over to compiler-rt. |
18 | * Testing of any change in this file can start only after the two copies are |
19 | * synced up. |
20 | * |
21 | \*===----------------------------------------------------------------------===*/ |
22 | #include <string.h> |
23 | |
24 | #ifdef _MSC_VER |
25 | #define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop)) |
26 | #else |
27 | #define PACKED(...) __VA_ARGS__ __attribute__((__packed__)) |
28 | #endif |
29 | |
30 | // A 64-bit magic number to uniquely identify the raw binary memprof profile file. |
31 | #define MEMPROF_RAW_MAGIC_64 \ |
32 | ((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | \ |
33 | (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129) |
34 | |
35 | // The version number of the raw binary format. |
36 | #define MEMPROF_RAW_VERSION 3ULL |
37 | |
38 | #define MEMPROF_BUILDID_MAX_SIZE 32ULL |
39 | |
40 | namespace llvm { |
41 | namespace memprof { |
42 | // A struct describing the header used for the raw binary memprof profile format. |
43 | PACKED(struct { |
44 | uint64_t ; |
45 | uint64_t ; |
46 | uint64_t ; |
47 | uint64_t ; |
48 | uint64_t ; |
49 | uint64_t ; |
50 | }); |
51 | |
52 | // A struct describing the information necessary to describe a /proc/maps |
53 | // segment entry for a particular binary/library identified by its build id. |
54 | PACKED(struct SegmentEntry { |
55 | uint64_t Start; |
56 | uint64_t End; |
57 | uint64_t Offset; |
58 | uint64_t BuildIdSize; |
59 | uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0}; |
60 | |
61 | // This constructor is only used in tests so don't set the BuildId. |
62 | SegmentEntry(uint64_t S, uint64_t E, uint64_t O) |
63 | : Start(S), End(E), Offset(O), BuildIdSize(0) {} |
64 | |
65 | SegmentEntry(const SegmentEntry& S) { |
66 | Start = S.Start; |
67 | End = S.End; |
68 | Offset = S.Offset; |
69 | BuildIdSize = S.BuildIdSize; |
70 | memcpy(BuildId, S.BuildId, S.BuildIdSize); |
71 | } |
72 | |
73 | SegmentEntry& operator=(const SegmentEntry& S) { |
74 | Start = S.Start; |
75 | End = S.End; |
76 | Offset = S.Offset; |
77 | BuildIdSize = S.BuildIdSize; |
78 | memcpy(BuildId, S.BuildId, S.BuildIdSize); |
79 | return *this; |
80 | } |
81 | |
82 | bool operator==(const SegmentEntry& S) const { |
83 | return Start == S.Start && End == S.End && Offset == S.Offset && |
84 | BuildIdSize == S.BuildIdSize && |
85 | memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0; |
86 | } |
87 | }); |
88 | |
89 | // Packed struct definition for MSVC. We can't use the PACKED macro defined in |
90 | // MemProfData.inc since it would mean we are embedding a directive (the |
91 | // #include for MIBEntryDef) into the macros which is undefined behaviour. |
92 | #ifdef _MSC_VER |
93 | __pragma(pack(push,1)) |
94 | #endif |
95 | |
96 | // A struct representing the heap allocation characteristics of a particular |
97 | // runtime context. This struct is shared between the compiler-rt runtime and |
98 | // the raw profile reader. The indexed format uses a separate, self-describing |
99 | // backwards compatible format. |
100 | struct MemInfoBlock{ |
101 | |
102 | #define MIBEntryDef(NameTag, Name, Type) Type Name; |
103 | #include "MIBEntryDef.inc" |
104 | #undef MIBEntryDef |
105 | |
106 | bool operator==(const MemInfoBlock& Other) const { |
107 | bool IsEqual = true; |
108 | #define MIBEntryDef(NameTag, Name, Type) \ |
109 | IsEqual = (IsEqual && Name == Other.Name); |
110 | #include "MIBEntryDef.inc" |
111 | #undef MIBEntryDef |
112 | return IsEqual; |
113 | } |
114 | |
115 | MemInfoBlock() { |
116 | #define MIBEntryDef(NameTag, Name, Type) Name = Type(); |
117 | #include "MIBEntryDef.inc" |
118 | #undef MIBEntryDef |
119 | } |
120 | |
121 | MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs, |
122 | uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu) |
123 | : MemInfoBlock() { |
124 | AllocCount = 1U; |
125 | TotalAccessCount = AccessCount; |
126 | MinAccessCount = AccessCount; |
127 | MaxAccessCount = AccessCount; |
128 | TotalSize = Size; |
129 | MinSize = Size; |
130 | MaxSize = Size; |
131 | AllocTimestamp = AllocTs; |
132 | DeallocTimestamp = DeallocTs; |
133 | TotalLifetime = DeallocTimestamp - AllocTimestamp; |
134 | MinLifetime = TotalLifetime; |
135 | MaxLifetime = TotalLifetime; |
136 | // Access density is accesses per byte. Multiply by 100 to include the |
137 | // fractional part. |
138 | TotalAccessDensity = AccessCount * 100 / Size; |
139 | MinAccessDensity = TotalAccessDensity; |
140 | MaxAccessDensity = TotalAccessDensity; |
141 | // Lifetime access density is the access density per second of lifetime. |
142 | // Multiply by 1000 to convert denominator lifetime to seconds (using a |
143 | // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first |
144 | // to reduce truncations to 0. |
145 | TotalLifetimeAccessDensity = |
146 | TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1); |
147 | MinLifetimeAccessDensity = TotalLifetimeAccessDensity; |
148 | MaxLifetimeAccessDensity = TotalLifetimeAccessDensity; |
149 | AllocCpuId = AllocCpu; |
150 | DeallocCpuId = DeallocCpu; |
151 | NumMigratedCpu = AllocCpuId != DeallocCpuId; |
152 | } |
153 | |
154 | void Merge(const MemInfoBlock &newMIB) { |
155 | AllocCount += newMIB.AllocCount; |
156 | |
157 | TotalAccessCount += newMIB.TotalAccessCount; |
158 | MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount; |
159 | MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount; |
160 | |
161 | TotalSize += newMIB.TotalSize; |
162 | MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize; |
163 | MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize; |
164 | |
165 | TotalLifetime += newMIB.TotalLifetime; |
166 | MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime; |
167 | MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime; |
168 | |
169 | TotalAccessDensity += newMIB.TotalAccessDensity; |
170 | MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity |
171 | ? newMIB.MinAccessDensity |
172 | : MinAccessDensity; |
173 | MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity |
174 | ? newMIB.MaxAccessDensity |
175 | : MaxAccessDensity; |
176 | |
177 | TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity; |
178 | MinLifetimeAccessDensity = |
179 | newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity |
180 | ? newMIB.MinLifetimeAccessDensity |
181 | : MinLifetimeAccessDensity; |
182 | MaxLifetimeAccessDensity = |
183 | newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity |
184 | ? newMIB.MaxLifetimeAccessDensity |
185 | : MaxLifetimeAccessDensity; |
186 | |
187 | // We know newMIB was deallocated later, so just need to check if it was |
188 | // allocated before last one deallocated. |
189 | NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp; |
190 | AllocTimestamp = newMIB.AllocTimestamp; |
191 | DeallocTimestamp = newMIB.DeallocTimestamp; |
192 | |
193 | NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId; |
194 | NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId; |
195 | AllocCpuId = newMIB.AllocCpuId; |
196 | DeallocCpuId = newMIB.DeallocCpuId; |
197 | } |
198 | |
199 | #ifdef _MSC_VER |
200 | } __pragma(pack(pop)); |
201 | #else |
202 | } __attribute__((__packed__)); |
203 | #endif |
204 | |
205 | } // namespace memprof |
206 | } // namespace llvm |
207 | |
208 | #endif |
209 | |