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\*===----------------------------------------------------------------------===*/
22*06c3fb27SDimitry 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*06c3fb27SDimitry Andric#define MEMPROF_RAW_VERSION 3ULL
37*06c3fb27SDimitry Andric
38*06c3fb27SDimitry Andric#define MEMPROF_BUILDID_MAX_SIZE 32ULL
394824e7fdSDimitry Andric
404824e7fdSDimitry Andricnamespace llvm {
414824e7fdSDimitry Andricnamespace memprof {
424824e7fdSDimitry Andric// A struct describing the header used for the raw binary memprof profile format.
434824e7fdSDimitry AndricPACKED(struct Header {
444824e7fdSDimitry Andric  uint64_t Magic;
454824e7fdSDimitry Andric  uint64_t Version;
464824e7fdSDimitry Andric  uint64_t TotalSize;
474824e7fdSDimitry Andric  uint64_t SegmentOffset;
484824e7fdSDimitry Andric  uint64_t MIBOffset;
494824e7fdSDimitry Andric  uint64_t StackOffset;
504824e7fdSDimitry Andric});
514824e7fdSDimitry Andric
524824e7fdSDimitry Andric// A struct describing the information necessary to describe a /proc/maps
534824e7fdSDimitry Andric// segment entry for a particular binary/library identified by its build id.
544824e7fdSDimitry AndricPACKED(struct SegmentEntry {
554824e7fdSDimitry Andric  uint64_t Start;
564824e7fdSDimitry Andric  uint64_t End;
574824e7fdSDimitry Andric  uint64_t Offset;
58*06c3fb27SDimitry Andric  uint64_t BuildIdSize;
59*06c3fb27SDimitry Andric  uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};
601fd87a68SDimitry Andric
61*06c3fb27SDimitry Andric  // This constructor is only used in tests so don't set the BuildId.
62*06c3fb27SDimitry Andric  SegmentEntry(uint64_t S, uint64_t E, uint64_t O)
63*06c3fb27SDimitry Andric      : Start(S), End(E), Offset(O), BuildIdSize(0) {}
641fd87a68SDimitry Andric
651fd87a68SDimitry Andric  SegmentEntry(const SegmentEntry& S) {
661fd87a68SDimitry Andric    Start = S.Start;
671fd87a68SDimitry Andric    End = S.End;
681fd87a68SDimitry Andric    Offset = S.Offset;
69*06c3fb27SDimitry Andric    BuildIdSize = S.BuildIdSize;
70*06c3fb27SDimitry Andric    memcpy(BuildId, S.BuildId, S.BuildIdSize);
711fd87a68SDimitry Andric  }
721fd87a68SDimitry Andric
731fd87a68SDimitry Andric  SegmentEntry& operator=(const SegmentEntry& S) {
741fd87a68SDimitry Andric    Start = S.Start;
751fd87a68SDimitry Andric    End = S.End;
761fd87a68SDimitry Andric    Offset = S.Offset;
77*06c3fb27SDimitry Andric    BuildIdSize = S.BuildIdSize;
78*06c3fb27SDimitry Andric    memcpy(BuildId, S.BuildId, S.BuildIdSize);
791fd87a68SDimitry Andric    return *this;
801fd87a68SDimitry Andric  }
811fd87a68SDimitry Andric
821fd87a68SDimitry Andric  bool operator==(const SegmentEntry& S) const {
83*06c3fb27SDimitry Andric    return Start == S.Start && End == S.End && Offset == S.Offset &&
84*06c3fb27SDimitry Andric           BuildIdSize == S.BuildIdSize &&
85*06c3fb27SDimitry Andric           memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;
861fd87a68SDimitry Andric  }
874824e7fdSDimitry Andric});
881fd87a68SDimitry Andric
8981ad6265SDimitry Andric// Packed struct definition for MSVC. We can't use the PACKED macro defined in
9081ad6265SDimitry Andric// MemProfData.inc since it would mean we are embedding a directive (the
9181ad6265SDimitry Andric// #include for MIBEntryDef) into the macros which is undefined behaviour.
9281ad6265SDimitry Andric#ifdef _MSC_VER
9381ad6265SDimitry Andric__pragma(pack(push,1))
9481ad6265SDimitry Andric#endif
9581ad6265SDimitry Andric
961fd87a68SDimitry Andric// A struct representing the heap allocation characteristics of a particular
971fd87a68SDimitry Andric// runtime context. This struct is shared between the compiler-rt runtime and
981fd87a68SDimitry Andric// the raw profile reader. The indexed format uses a separate, self-describing
991fd87a68SDimitry Andric// backwards compatible format.
10081ad6265SDimitry Andricstruct MemInfoBlock{
1011fd87a68SDimitry Andric
10281ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) Type Name;
10381ad6265SDimitry Andric#include "MIBEntryDef.inc"
10481ad6265SDimitry Andric#undef MIBEntryDef
1051fd87a68SDimitry Andric
10681ad6265SDimitry Andricbool operator==(const MemInfoBlock& Other) const {
10781ad6265SDimitry Andric  bool IsEqual = true;
10881ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) \
10981ad6265SDimitry Andric  IsEqual = (IsEqual && Name == Other.Name);
11081ad6265SDimitry Andric#include "MIBEntryDef.inc"
11181ad6265SDimitry Andric#undef MIBEntryDef
11281ad6265SDimitry Andric  return IsEqual;
11381ad6265SDimitry Andric}
1141fd87a68SDimitry Andric
11581ad6265SDimitry AndricMemInfoBlock() {
11681ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) Name = Type();
11781ad6265SDimitry Andric#include "MIBEntryDef.inc"
11881ad6265SDimitry Andric#undef MIBEntryDef
11981ad6265SDimitry Andric}
1201fd87a68SDimitry Andric
12181ad6265SDimitry AndricMemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs,
12281ad6265SDimitry Andric             uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu)
12381ad6265SDimitry Andric    : MemInfoBlock() {
12481ad6265SDimitry Andric  AllocCount = 1U;
12581ad6265SDimitry Andric  TotalAccessCount = AccessCount;
12681ad6265SDimitry Andric  MinAccessCount = AccessCount;
12781ad6265SDimitry Andric  MaxAccessCount = AccessCount;
12881ad6265SDimitry Andric  TotalSize = Size;
12981ad6265SDimitry Andric  MinSize = Size;
13081ad6265SDimitry Andric  MaxSize = Size;
13181ad6265SDimitry Andric  AllocTimestamp = AllocTs;
13281ad6265SDimitry Andric  DeallocTimestamp = DeallocTs;
13381ad6265SDimitry Andric  TotalLifetime = DeallocTimestamp - AllocTimestamp;
13481ad6265SDimitry Andric  MinLifetime = TotalLifetime;
13581ad6265SDimitry Andric  MaxLifetime = TotalLifetime;
136bdd1243dSDimitry Andric  // Access density is accesses per byte. Multiply by 100 to include the
137bdd1243dSDimitry Andric  // fractional part.
138bdd1243dSDimitry Andric  TotalAccessDensity = AccessCount * 100 / Size;
139bdd1243dSDimitry Andric  MinAccessDensity = TotalAccessDensity;
140bdd1243dSDimitry Andric  MaxAccessDensity = TotalAccessDensity;
141bdd1243dSDimitry Andric  // Lifetime access density is the access density per second of lifetime.
142bdd1243dSDimitry Andric  // Multiply by 1000 to convert denominator lifetime to seconds (using a
143bdd1243dSDimitry Andric  // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first
144bdd1243dSDimitry Andric  // to reduce truncations to 0.
145bdd1243dSDimitry Andric  TotalLifetimeAccessDensity =
146bdd1243dSDimitry Andric      TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1);
147bdd1243dSDimitry Andric  MinLifetimeAccessDensity = TotalLifetimeAccessDensity;
148bdd1243dSDimitry Andric  MaxLifetimeAccessDensity = TotalLifetimeAccessDensity;
14981ad6265SDimitry Andric  AllocCpuId = AllocCpu;
15081ad6265SDimitry Andric  DeallocCpuId = DeallocCpu;
15181ad6265SDimitry Andric  NumMigratedCpu = AllocCpuId != DeallocCpuId;
1521fd87a68SDimitry Andric}
1531fd87a68SDimitry Andric
1541fd87a68SDimitry Andricvoid Merge(const MemInfoBlock &newMIB) {
15581ad6265SDimitry Andric  AllocCount += newMIB.AllocCount;
1561fd87a68SDimitry Andric
15781ad6265SDimitry Andric  TotalAccessCount += newMIB.TotalAccessCount;
15881ad6265SDimitry Andric  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
159bdd1243dSDimitry Andric  MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;
1601fd87a68SDimitry Andric
16181ad6265SDimitry Andric  TotalSize += newMIB.TotalSize;
16281ad6265SDimitry Andric  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
163bdd1243dSDimitry Andric  MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize;
1641fd87a68SDimitry Andric
16581ad6265SDimitry Andric  TotalLifetime += newMIB.TotalLifetime;
16681ad6265SDimitry Andric  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
16781ad6265SDimitry Andric  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;
1681fd87a68SDimitry Andric
169bdd1243dSDimitry Andric  TotalAccessDensity += newMIB.TotalAccessDensity;
170bdd1243dSDimitry Andric  MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity
171bdd1243dSDimitry Andric                         ? newMIB.MinAccessDensity
172bdd1243dSDimitry Andric                         : MinAccessDensity;
173bdd1243dSDimitry Andric  MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity
174bdd1243dSDimitry Andric                         ? newMIB.MaxAccessDensity
175bdd1243dSDimitry Andric                         : MaxAccessDensity;
176bdd1243dSDimitry Andric
177bdd1243dSDimitry Andric  TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity;
178bdd1243dSDimitry Andric  MinLifetimeAccessDensity =
179bdd1243dSDimitry Andric      newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity
180bdd1243dSDimitry Andric          ? newMIB.MinLifetimeAccessDensity
181bdd1243dSDimitry Andric          : MinLifetimeAccessDensity;
182bdd1243dSDimitry Andric  MaxLifetimeAccessDensity =
183bdd1243dSDimitry Andric      newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity
184bdd1243dSDimitry Andric          ? newMIB.MaxLifetimeAccessDensity
185bdd1243dSDimitry Andric          : MaxLifetimeAccessDensity;
186bdd1243dSDimitry Andric
1871fd87a68SDimitry Andric  // We know newMIB was deallocated later, so just need to check if it was
1881fd87a68SDimitry Andric  // allocated before last one deallocated.
18981ad6265SDimitry Andric  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
19081ad6265SDimitry Andric  AllocTimestamp = newMIB.AllocTimestamp;
19181ad6265SDimitry Andric  DeallocTimestamp = newMIB.DeallocTimestamp;
1921fd87a68SDimitry Andric
19381ad6265SDimitry Andric  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
19481ad6265SDimitry Andric  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
19581ad6265SDimitry Andric  AllocCpuId = newMIB.AllocCpuId;
19681ad6265SDimitry Andric  DeallocCpuId = newMIB.DeallocCpuId;
1971fd87a68SDimitry Andric}
19881ad6265SDimitry Andric
19981ad6265SDimitry Andric#ifdef _MSC_VER
20081ad6265SDimitry Andric} __pragma(pack(pop));
20181ad6265SDimitry Andric#else
20281ad6265SDimitry Andric} __attribute__((__packed__));
20381ad6265SDimitry Andric#endif
2041fd87a68SDimitry Andric
2054824e7fdSDimitry Andric} // namespace memprof
2064824e7fdSDimitry Andric} // namespace llvm
2074824e7fdSDimitry Andric
2084824e7fdSDimitry Andric#endif
209