xref: /freebsd/contrib/llvm-project/compiler-rt/include/profile/MemProfData.inc (revision 02e9120893770924227138ba49df1edb3896112a)
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
40namespace llvm {
41namespace memprof {
42// A struct describing the header used for the raw binary memprof profile format.
43PACKED(struct Header {
44  uint64_t Magic;
45  uint64_t Version;
46  uint64_t TotalSize;
47  uint64_t SegmentOffset;
48  uint64_t MIBOffset;
49  uint64_t StackOffset;
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.
54PACKED(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.
100struct MemInfoBlock{
101
102#define MIBEntryDef(NameTag, Name, Type) Type Name;
103#include "MIBEntryDef.inc"
104#undef MIBEntryDef
105
106bool 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
115MemInfoBlock() {
116#define MIBEntryDef(NameTag, Name, Type) Name = Type();
117#include "MIBEntryDef.inc"
118#undef MIBEntryDef
119}
120
121MemInfoBlock(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
154void 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