xref: /freebsd/contrib/llvm-project/compiler-rt/include/profile/MemProfData.inc (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 4ULL
37
38// Currently supported versions.
39#define MEMPROF_RAW_SUPPORTED_VERSIONS                                         \
40  { 3ULL, 4ULL }
41
42#define MEMPROF_V3_MIB_SIZE 132ULL;
43
44#define MEMPROF_BUILDID_MAX_SIZE 32ULL
45
46namespace llvm {
47namespace memprof {
48// A struct describing the header used for the raw binary memprof profile format.
49PACKED(struct Header {
50  uint64_t Magic;
51  uint64_t Version;
52  uint64_t TotalSize;
53  uint64_t SegmentOffset;
54  uint64_t MIBOffset;
55  uint64_t StackOffset;
56});
57
58// A struct describing the information necessary to describe a /proc/maps
59// segment entry for a particular binary/library identified by its build id.
60PACKED(struct SegmentEntry {
61  uint64_t Start;
62  uint64_t End;
63  uint64_t Offset;
64  uint64_t BuildIdSize;
65  uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};
66
67  // This constructor is only used in tests so don't set the BuildId.
68  SegmentEntry(uint64_t S, uint64_t E, uint64_t O)
69      : Start(S), End(E), Offset(O), BuildIdSize(0) {}
70
71  SegmentEntry(const SegmentEntry& S) {
72    Start = S.Start;
73    End = S.End;
74    Offset = S.Offset;
75    BuildIdSize = S.BuildIdSize;
76    memcpy(BuildId, S.BuildId, S.BuildIdSize);
77  }
78
79  SegmentEntry& operator=(const SegmentEntry& S) {
80    Start = S.Start;
81    End = S.End;
82    Offset = S.Offset;
83    BuildIdSize = S.BuildIdSize;
84    memcpy(BuildId, S.BuildId, S.BuildIdSize);
85    return *this;
86  }
87
88  bool operator==(const SegmentEntry& S) const {
89    return Start == S.Start && End == S.End && Offset == S.Offset &&
90           BuildIdSize == S.BuildIdSize &&
91           memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;
92  }
93});
94
95// Packed struct definition for MSVC. We can't use the PACKED macro defined in
96// MemProfData.inc since it would mean we are embedding a directive (the
97// #include for MIBEntryDef) into the macros which is undefined behaviour.
98#ifdef _MSC_VER
99__pragma(pack(push,1))
100#endif
101
102// A struct representing the heap allocation characteristics of a particular
103// runtime context. This struct is shared between the compiler-rt runtime and
104// the raw profile reader. The indexed format uses a separate, self-describing
105// backwards compatible format.
106struct MemInfoBlock{
107
108#define MIBEntryDef(NameTag, Name, Type) Type Name;
109#include "MIBEntryDef.inc"
110#undef MIBEntryDef
111
112bool operator==(const MemInfoBlock& Other) const {
113  bool IsEqual = true;
114#define MIBEntryDef(NameTag, Name, Type) \
115  IsEqual = (IsEqual && Name == Other.Name);
116#include "MIBEntryDef.inc"
117#undef MIBEntryDef
118  return IsEqual;
119}
120
121MemInfoBlock() {
122#define MIBEntryDef(NameTag, Name, Type) Name = Type();
123#include "MIBEntryDef.inc"
124#undef MIBEntryDef
125}
126
127MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs,
128             uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu,
129             uintptr_t Histogram, uint32_t HistogramSize)
130    : MemInfoBlock() {
131  AllocCount = 1U;
132  TotalAccessCount = AccessCount;
133  MinAccessCount = AccessCount;
134  MaxAccessCount = AccessCount;
135  TotalSize = Size;
136  MinSize = Size;
137  MaxSize = Size;
138  AllocTimestamp = AllocTs;
139  DeallocTimestamp = DeallocTs;
140  TotalLifetime = DeallocTimestamp - AllocTimestamp;
141  MinLifetime = TotalLifetime;
142  MaxLifetime = TotalLifetime;
143  // Access density is accesses per byte. Multiply by 100 to include the
144  // fractional part.
145  TotalAccessDensity = AccessCount * 100 / Size;
146  MinAccessDensity = TotalAccessDensity;
147  MaxAccessDensity = TotalAccessDensity;
148  // Lifetime access density is the access density per second of lifetime.
149  // Multiply by 1000 to convert denominator lifetime to seconds (using a
150  // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first
151  // to reduce truncations to 0.
152  TotalLifetimeAccessDensity =
153      TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1);
154  MinLifetimeAccessDensity = TotalLifetimeAccessDensity;
155  MaxLifetimeAccessDensity = TotalLifetimeAccessDensity;
156  AllocCpuId = AllocCpu;
157  DeallocCpuId = DeallocCpu;
158  NumMigratedCpu = AllocCpuId != DeallocCpuId;
159  AccessHistogramSize = HistogramSize;
160  AccessHistogram = Histogram;
161}
162
163void Merge(const MemInfoBlock &newMIB) {
164  AllocCount += newMIB.AllocCount;
165
166  TotalAccessCount += newMIB.TotalAccessCount;
167  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
168  MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;
169
170  TotalSize += newMIB.TotalSize;
171  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
172  MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize;
173
174  TotalLifetime += newMIB.TotalLifetime;
175  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
176  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;
177
178  TotalAccessDensity += newMIB.TotalAccessDensity;
179  MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity
180                         ? newMIB.MinAccessDensity
181                         : MinAccessDensity;
182  MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity
183                         ? newMIB.MaxAccessDensity
184                         : MaxAccessDensity;
185
186  TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity;
187  MinLifetimeAccessDensity =
188      newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity
189          ? newMIB.MinLifetimeAccessDensity
190          : MinLifetimeAccessDensity;
191  MaxLifetimeAccessDensity =
192      newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity
193          ? newMIB.MaxLifetimeAccessDensity
194          : MaxLifetimeAccessDensity;
195
196  // We know newMIB was deallocated later, so just need to check if it was
197  // allocated before last one deallocated.
198  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
199  AllocTimestamp = newMIB.AllocTimestamp;
200  DeallocTimestamp = newMIB.DeallocTimestamp;
201
202  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
203  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
204  AllocCpuId = newMIB.AllocCpuId;
205  DeallocCpuId = newMIB.DeallocCpuId;
206
207  // For merging histograms, we always keep the longer histogram, and add
208  // values of shorter histogram to larger one.
209  uintptr_t ShorterHistogram;
210  uint32_t ShorterHistogramSize;
211  if (newMIB.AccessHistogramSize > AccessHistogramSize) {
212    ShorterHistogram = AccessHistogram;
213    ShorterHistogramSize = AccessHistogramSize;
214    // Swap histogram of current to larger histogram
215    AccessHistogram = newMIB.AccessHistogram;
216    AccessHistogramSize = newMIB.AccessHistogramSize;
217  } else {
218    ShorterHistogram = newMIB.AccessHistogram;
219    ShorterHistogramSize = newMIB.AccessHistogramSize;
220  }
221  for (size_t i = 0; i < ShorterHistogramSize; ++i) {
222    ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i];
223  }
224}
225
226#ifdef _MSC_VER
227} __pragma(pack(pop));
228#else
229} __attribute__((__packed__));
230#endif
231
232} // namespace memprof
233} // namespace llvm
234
235#endif
236