xref: /freebsd/contrib/llvm-project/compiler-rt/include/profile/MemProfData.inc (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
14824e7fdSDimitry Andric#ifndef MEMPROF_DATA_INC
24824e7fdSDimitry Andric#define MEMPROF_DATA_INC
34824e7fdSDimitry Andric/*===-- MemProfData.inc - MemProf profiling runtime structures -*- C++ -*-=== *\
44824e7fdSDimitry Andric|*
54824e7fdSDimitry Andric|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
64824e7fdSDimitry Andric|* See https://llvm.org/LICENSE.txt for license information.
74824e7fdSDimitry Andric|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
84824e7fdSDimitry Andric|*
94824e7fdSDimitry Andric\*===----------------------------------------------------------------------===*/
104824e7fdSDimitry Andric/*
114824e7fdSDimitry Andric * This is the main file that defines all the data structure, signature,
124824e7fdSDimitry Andric * constant literals that are shared across profiling runtime library,
134824e7fdSDimitry Andric * and host tools (reader/writer).
144824e7fdSDimitry Andric *
154824e7fdSDimitry Andric * This file has two identical copies. The primary copy lives in LLVM and
164824e7fdSDimitry Andric * the other one sits in compiler-rt/include/profile directory. To make changes
174824e7fdSDimitry Andric * in this file, first modify the primary copy and copy it over to compiler-rt.
184824e7fdSDimitry Andric * Testing of any change in this file can start only after the two copies are
194824e7fdSDimitry Andric * synced up.
204824e7fdSDimitry Andric *
214824e7fdSDimitry Andric\*===----------------------------------------------------------------------===*/
2206c3fb27SDimitry Andric#include <string.h>
234824e7fdSDimitry Andric
244824e7fdSDimitry Andric#ifdef _MSC_VER
251fd87a68SDimitry Andric#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
264824e7fdSDimitry Andric#else
271fd87a68SDimitry Andric#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
284824e7fdSDimitry Andric#endif
294824e7fdSDimitry Andric
304824e7fdSDimitry Andric// A 64-bit magic number to uniquely identify the raw binary memprof profile file.
314824e7fdSDimitry Andric#define MEMPROF_RAW_MAGIC_64                                                                        \
324824e7fdSDimitry Andric  ((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 |          \
334824e7fdSDimitry Andric   (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
344824e7fdSDimitry Andric
354824e7fdSDimitry Andric// The version number of the raw binary format.
36*0fca6ea1SDimitry Andric#define MEMPROF_RAW_VERSION 4ULL
37*0fca6ea1SDimitry Andric
38*0fca6ea1SDimitry Andric// Currently supported versions.
39*0fca6ea1SDimitry Andric#define MEMPROF_RAW_SUPPORTED_VERSIONS                                         \
40*0fca6ea1SDimitry Andric  { 3ULL, 4ULL }
41*0fca6ea1SDimitry Andric
42*0fca6ea1SDimitry Andric#define MEMPROF_V3_MIB_SIZE 132ULL;
4306c3fb27SDimitry Andric
4406c3fb27SDimitry Andric#define MEMPROF_BUILDID_MAX_SIZE 32ULL
454824e7fdSDimitry Andric
464824e7fdSDimitry Andricnamespace llvm {
474824e7fdSDimitry Andricnamespace memprof {
484824e7fdSDimitry Andric// A struct describing the header used for the raw binary memprof profile format.
494824e7fdSDimitry AndricPACKED(struct Header {
504824e7fdSDimitry Andric  uint64_t Magic;
514824e7fdSDimitry Andric  uint64_t Version;
524824e7fdSDimitry Andric  uint64_t TotalSize;
534824e7fdSDimitry Andric  uint64_t SegmentOffset;
544824e7fdSDimitry Andric  uint64_t MIBOffset;
554824e7fdSDimitry Andric  uint64_t StackOffset;
564824e7fdSDimitry Andric});
574824e7fdSDimitry Andric
584824e7fdSDimitry Andric// A struct describing the information necessary to describe a /proc/maps
594824e7fdSDimitry Andric// segment entry for a particular binary/library identified by its build id.
604824e7fdSDimitry AndricPACKED(struct SegmentEntry {
614824e7fdSDimitry Andric  uint64_t Start;
624824e7fdSDimitry Andric  uint64_t End;
634824e7fdSDimitry Andric  uint64_t Offset;
6406c3fb27SDimitry Andric  uint64_t BuildIdSize;
6506c3fb27SDimitry Andric  uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};
661fd87a68SDimitry Andric
6706c3fb27SDimitry Andric  // This constructor is only used in tests so don't set the BuildId.
6806c3fb27SDimitry Andric  SegmentEntry(uint64_t S, uint64_t E, uint64_t O)
6906c3fb27SDimitry Andric      : Start(S), End(E), Offset(O), BuildIdSize(0) {}
701fd87a68SDimitry Andric
711fd87a68SDimitry Andric  SegmentEntry(const SegmentEntry& S) {
721fd87a68SDimitry Andric    Start = S.Start;
731fd87a68SDimitry Andric    End = S.End;
741fd87a68SDimitry Andric    Offset = S.Offset;
7506c3fb27SDimitry Andric    BuildIdSize = S.BuildIdSize;
7606c3fb27SDimitry Andric    memcpy(BuildId, S.BuildId, S.BuildIdSize);
771fd87a68SDimitry Andric  }
781fd87a68SDimitry Andric
791fd87a68SDimitry Andric  SegmentEntry& operator=(const SegmentEntry& S) {
801fd87a68SDimitry Andric    Start = S.Start;
811fd87a68SDimitry Andric    End = S.End;
821fd87a68SDimitry Andric    Offset = S.Offset;
8306c3fb27SDimitry Andric    BuildIdSize = S.BuildIdSize;
8406c3fb27SDimitry Andric    memcpy(BuildId, S.BuildId, S.BuildIdSize);
851fd87a68SDimitry Andric    return *this;
861fd87a68SDimitry Andric  }
871fd87a68SDimitry Andric
881fd87a68SDimitry Andric  bool operator==(const SegmentEntry& S) const {
8906c3fb27SDimitry Andric    return Start == S.Start && End == S.End && Offset == S.Offset &&
9006c3fb27SDimitry Andric           BuildIdSize == S.BuildIdSize &&
9106c3fb27SDimitry Andric           memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;
921fd87a68SDimitry Andric  }
934824e7fdSDimitry Andric});
941fd87a68SDimitry Andric
9581ad6265SDimitry Andric// Packed struct definition for MSVC. We can't use the PACKED macro defined in
9681ad6265SDimitry Andric// MemProfData.inc since it would mean we are embedding a directive (the
9781ad6265SDimitry Andric// #include for MIBEntryDef) into the macros which is undefined behaviour.
9881ad6265SDimitry Andric#ifdef _MSC_VER
9981ad6265SDimitry Andric__pragma(pack(push,1))
10081ad6265SDimitry Andric#endif
10181ad6265SDimitry Andric
1021fd87a68SDimitry Andric// A struct representing the heap allocation characteristics of a particular
1031fd87a68SDimitry Andric// runtime context. This struct is shared between the compiler-rt runtime and
1041fd87a68SDimitry Andric// the raw profile reader. The indexed format uses a separate, self-describing
1051fd87a68SDimitry Andric// backwards compatible format.
10681ad6265SDimitry Andricstruct MemInfoBlock{
1071fd87a68SDimitry Andric
10881ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) Type Name;
10981ad6265SDimitry Andric#include "MIBEntryDef.inc"
11081ad6265SDimitry Andric#undef MIBEntryDef
1111fd87a68SDimitry Andric
11281ad6265SDimitry Andricbool operator==(const MemInfoBlock& Other) const {
11381ad6265SDimitry Andric  bool IsEqual = true;
11481ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) \
11581ad6265SDimitry Andric  IsEqual = (IsEqual && Name == Other.Name);
11681ad6265SDimitry Andric#include "MIBEntryDef.inc"
11781ad6265SDimitry Andric#undef MIBEntryDef
11881ad6265SDimitry Andric  return IsEqual;
11981ad6265SDimitry Andric}
1201fd87a68SDimitry Andric
12181ad6265SDimitry AndricMemInfoBlock() {
12281ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) Name = Type();
12381ad6265SDimitry Andric#include "MIBEntryDef.inc"
12481ad6265SDimitry Andric#undef MIBEntryDef
12581ad6265SDimitry Andric}
1261fd87a68SDimitry Andric
12781ad6265SDimitry AndricMemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs,
128*0fca6ea1SDimitry Andric             uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu,
129*0fca6ea1SDimitry Andric             uintptr_t Histogram, uint32_t HistogramSize)
13081ad6265SDimitry Andric    : MemInfoBlock() {
13181ad6265SDimitry Andric  AllocCount = 1U;
13281ad6265SDimitry Andric  TotalAccessCount = AccessCount;
13381ad6265SDimitry Andric  MinAccessCount = AccessCount;
13481ad6265SDimitry Andric  MaxAccessCount = AccessCount;
13581ad6265SDimitry Andric  TotalSize = Size;
13681ad6265SDimitry Andric  MinSize = Size;
13781ad6265SDimitry Andric  MaxSize = Size;
13881ad6265SDimitry Andric  AllocTimestamp = AllocTs;
13981ad6265SDimitry Andric  DeallocTimestamp = DeallocTs;
14081ad6265SDimitry Andric  TotalLifetime = DeallocTimestamp - AllocTimestamp;
14181ad6265SDimitry Andric  MinLifetime = TotalLifetime;
14281ad6265SDimitry Andric  MaxLifetime = TotalLifetime;
143bdd1243dSDimitry Andric  // Access density is accesses per byte. Multiply by 100 to include the
144bdd1243dSDimitry Andric  // fractional part.
145bdd1243dSDimitry Andric  TotalAccessDensity = AccessCount * 100 / Size;
146bdd1243dSDimitry Andric  MinAccessDensity = TotalAccessDensity;
147bdd1243dSDimitry Andric  MaxAccessDensity = TotalAccessDensity;
148bdd1243dSDimitry Andric  // Lifetime access density is the access density per second of lifetime.
149bdd1243dSDimitry Andric  // Multiply by 1000 to convert denominator lifetime to seconds (using a
150bdd1243dSDimitry Andric  // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first
151bdd1243dSDimitry Andric  // to reduce truncations to 0.
152bdd1243dSDimitry Andric  TotalLifetimeAccessDensity =
153bdd1243dSDimitry Andric      TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1);
154bdd1243dSDimitry Andric  MinLifetimeAccessDensity = TotalLifetimeAccessDensity;
155bdd1243dSDimitry Andric  MaxLifetimeAccessDensity = TotalLifetimeAccessDensity;
15681ad6265SDimitry Andric  AllocCpuId = AllocCpu;
15781ad6265SDimitry Andric  DeallocCpuId = DeallocCpu;
15881ad6265SDimitry Andric  NumMigratedCpu = AllocCpuId != DeallocCpuId;
159*0fca6ea1SDimitry Andric  AccessHistogramSize = HistogramSize;
160*0fca6ea1SDimitry Andric  AccessHistogram = Histogram;
1611fd87a68SDimitry Andric}
1621fd87a68SDimitry Andric
1631fd87a68SDimitry Andricvoid Merge(const MemInfoBlock &newMIB) {
16481ad6265SDimitry Andric  AllocCount += newMIB.AllocCount;
1651fd87a68SDimitry Andric
16681ad6265SDimitry Andric  TotalAccessCount += newMIB.TotalAccessCount;
16781ad6265SDimitry Andric  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
168bdd1243dSDimitry Andric  MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;
1691fd87a68SDimitry Andric
17081ad6265SDimitry Andric  TotalSize += newMIB.TotalSize;
17181ad6265SDimitry Andric  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
172bdd1243dSDimitry Andric  MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize;
1731fd87a68SDimitry Andric
17481ad6265SDimitry Andric  TotalLifetime += newMIB.TotalLifetime;
17581ad6265SDimitry Andric  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
17681ad6265SDimitry Andric  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;
1771fd87a68SDimitry Andric
178bdd1243dSDimitry Andric  TotalAccessDensity += newMIB.TotalAccessDensity;
179bdd1243dSDimitry Andric  MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity
180bdd1243dSDimitry Andric                         ? newMIB.MinAccessDensity
181bdd1243dSDimitry Andric                         : MinAccessDensity;
182bdd1243dSDimitry Andric  MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity
183bdd1243dSDimitry Andric                         ? newMIB.MaxAccessDensity
184bdd1243dSDimitry Andric                         : MaxAccessDensity;
185bdd1243dSDimitry Andric
186bdd1243dSDimitry Andric  TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity;
187bdd1243dSDimitry Andric  MinLifetimeAccessDensity =
188bdd1243dSDimitry Andric      newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity
189bdd1243dSDimitry Andric          ? newMIB.MinLifetimeAccessDensity
190bdd1243dSDimitry Andric          : MinLifetimeAccessDensity;
191bdd1243dSDimitry Andric  MaxLifetimeAccessDensity =
192bdd1243dSDimitry Andric      newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity
193bdd1243dSDimitry Andric          ? newMIB.MaxLifetimeAccessDensity
194bdd1243dSDimitry Andric          : MaxLifetimeAccessDensity;
195bdd1243dSDimitry Andric
1961fd87a68SDimitry Andric  // We know newMIB was deallocated later, so just need to check if it was
1971fd87a68SDimitry Andric  // allocated before last one deallocated.
19881ad6265SDimitry Andric  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
19981ad6265SDimitry Andric  AllocTimestamp = newMIB.AllocTimestamp;
20081ad6265SDimitry Andric  DeallocTimestamp = newMIB.DeallocTimestamp;
2011fd87a68SDimitry Andric
20281ad6265SDimitry Andric  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
20381ad6265SDimitry Andric  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
20481ad6265SDimitry Andric  AllocCpuId = newMIB.AllocCpuId;
20581ad6265SDimitry Andric  DeallocCpuId = newMIB.DeallocCpuId;
206*0fca6ea1SDimitry Andric
207*0fca6ea1SDimitry Andric  // For merging histograms, we always keep the longer histogram, and add
208*0fca6ea1SDimitry Andric  // values of shorter histogram to larger one.
209*0fca6ea1SDimitry Andric  uintptr_t ShorterHistogram;
210*0fca6ea1SDimitry Andric  uint32_t ShorterHistogramSize;
211*0fca6ea1SDimitry Andric  if (newMIB.AccessHistogramSize > AccessHistogramSize) {
212*0fca6ea1SDimitry Andric    ShorterHistogram = AccessHistogram;
213*0fca6ea1SDimitry Andric    ShorterHistogramSize = AccessHistogramSize;
214*0fca6ea1SDimitry Andric    // Swap histogram of current to larger histogram
215*0fca6ea1SDimitry Andric    AccessHistogram = newMIB.AccessHistogram;
216*0fca6ea1SDimitry Andric    AccessHistogramSize = newMIB.AccessHistogramSize;
217*0fca6ea1SDimitry Andric  } else {
218*0fca6ea1SDimitry Andric    ShorterHistogram = newMIB.AccessHistogram;
219*0fca6ea1SDimitry Andric    ShorterHistogramSize = newMIB.AccessHistogramSize;
220*0fca6ea1SDimitry Andric  }
221*0fca6ea1SDimitry Andric  for (size_t i = 0; i < ShorterHistogramSize; ++i) {
222*0fca6ea1SDimitry Andric    ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i];
223*0fca6ea1SDimitry Andric  }
2241fd87a68SDimitry Andric}
22581ad6265SDimitry Andric
22681ad6265SDimitry Andric#ifdef _MSC_VER
22781ad6265SDimitry Andric} __pragma(pack(pop));
22881ad6265SDimitry Andric#else
22981ad6265SDimitry Andric} __attribute__((__packed__));
23081ad6265SDimitry Andric#endif
2311fd87a68SDimitry Andric
2324824e7fdSDimitry Andric} // namespace memprof
2334824e7fdSDimitry Andric} // namespace llvm
2344824e7fdSDimitry Andric
2354824e7fdSDimitry Andric#endif
236