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
23#ifdef _MSC_VER
24#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
25#else
26#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
27#endif
28
29// A 64-bit magic number to uniquely identify the raw binary memprof profile file.
30#define MEMPROF_RAW_MAGIC_64                                                                        \
31  ((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 |          \
32   (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)
33
34// The version number of the raw binary format.
35#define MEMPROF_RAW_VERSION 2ULL
36
37namespace llvm {
38namespace memprof {
39// A struct describing the header used for the raw binary memprof profile format.
40PACKED(struct Header {
41  uint64_t Magic;
42  uint64_t Version;
43  uint64_t TotalSize;
44  uint64_t SegmentOffset;
45  uint64_t MIBOffset;
46  uint64_t StackOffset;
47});
48
49
50// A struct describing the information necessary to describe a /proc/maps
51// segment entry for a particular binary/library identified by its build id.
52PACKED(struct SegmentEntry {
53  uint64_t Start;
54  uint64_t End;
55  uint64_t Offset;
56  // This field is unused until sanitizer procmaps support for build ids for
57  // Linux-Elf is implemented.
58  uint8_t BuildId[32] = {0};
59
60  SegmentEntry(uint64_t S, uint64_t E, uint64_t O) :
61    Start(S), End(E), Offset(O) {}
62
63  SegmentEntry(const SegmentEntry& S) {
64    Start = S.Start;
65    End = S.End;
66    Offset = S.Offset;
67  }
68
69  SegmentEntry& operator=(const SegmentEntry& S) {
70    Start = S.Start;
71    End = S.End;
72    Offset = S.Offset;
73    return *this;
74  }
75
76  bool operator==(const SegmentEntry& S) const {
77    return Start == S.Start &&
78           End == S.End &&
79           Offset == S.Offset;
80  }
81});
82
83// Packed struct definition for MSVC. We can't use the PACKED macro defined in
84// MemProfData.inc since it would mean we are embedding a directive (the
85// #include for MIBEntryDef) into the macros which is undefined behaviour.
86#ifdef _MSC_VER
87__pragma(pack(push,1))
88#endif
89
90// A struct representing the heap allocation characteristics of a particular
91// runtime context. This struct is shared between the compiler-rt runtime and
92// the raw profile reader. The indexed format uses a separate, self-describing
93// backwards compatible format.
94struct MemInfoBlock{
95
96#define MIBEntryDef(NameTag, Name, Type) Type Name;
97#include "MIBEntryDef.inc"
98#undef MIBEntryDef
99
100bool operator==(const MemInfoBlock& Other) const {
101  bool IsEqual = true;
102#define MIBEntryDef(NameTag, Name, Type) \
103  IsEqual = (IsEqual && Name == Other.Name);
104#include "MIBEntryDef.inc"
105#undef MIBEntryDef
106  return IsEqual;
107}
108
109MemInfoBlock() {
110#define MIBEntryDef(NameTag, Name, Type) Name = Type();
111#include "MIBEntryDef.inc"
112#undef MIBEntryDef
113}
114
115MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs,
116             uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu)
117    : MemInfoBlock() {
118  AllocCount = 1U;
119  TotalAccessCount = AccessCount;
120  MinAccessCount = AccessCount;
121  MaxAccessCount = AccessCount;
122  TotalSize = Size;
123  MinSize = Size;
124  MaxSize = Size;
125  AllocTimestamp = AllocTs;
126  DeallocTimestamp = DeallocTs;
127  TotalLifetime = DeallocTimestamp - AllocTimestamp;
128  MinLifetime = TotalLifetime;
129  MaxLifetime = TotalLifetime;
130  // Access density is accesses per byte. Multiply by 100 to include the
131  // fractional part.
132  TotalAccessDensity = AccessCount * 100 / Size;
133  MinAccessDensity = TotalAccessDensity;
134  MaxAccessDensity = TotalAccessDensity;
135  // Lifetime access density is the access density per second of lifetime.
136  // Multiply by 1000 to convert denominator lifetime to seconds (using a
137  // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first
138  // to reduce truncations to 0.
139  TotalLifetimeAccessDensity =
140      TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1);
141  MinLifetimeAccessDensity = TotalLifetimeAccessDensity;
142  MaxLifetimeAccessDensity = TotalLifetimeAccessDensity;
143  AllocCpuId = AllocCpu;
144  DeallocCpuId = DeallocCpu;
145  NumMigratedCpu = AllocCpuId != DeallocCpuId;
146}
147
148void Merge(const MemInfoBlock &newMIB) {
149  AllocCount += newMIB.AllocCount;
150
151  TotalAccessCount += newMIB.TotalAccessCount;
152  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
153  MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;
154
155  TotalSize += newMIB.TotalSize;
156  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
157  MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize;
158
159  TotalLifetime += newMIB.TotalLifetime;
160  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
161  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;
162
163  TotalAccessDensity += newMIB.TotalAccessDensity;
164  MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity
165                         ? newMIB.MinAccessDensity
166                         : MinAccessDensity;
167  MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity
168                         ? newMIB.MaxAccessDensity
169                         : MaxAccessDensity;
170
171  TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity;
172  MinLifetimeAccessDensity =
173      newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity
174          ? newMIB.MinLifetimeAccessDensity
175          : MinLifetimeAccessDensity;
176  MaxLifetimeAccessDensity =
177      newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity
178          ? newMIB.MaxLifetimeAccessDensity
179          : MaxLifetimeAccessDensity;
180
181  // We know newMIB was deallocated later, so just need to check if it was
182  // allocated before last one deallocated.
183  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
184  AllocTimestamp = newMIB.AllocTimestamp;
185  DeallocTimestamp = newMIB.DeallocTimestamp;
186
187  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
188  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
189  AllocCpuId = newMIB.AllocCpuId;
190  DeallocCpuId = newMIB.DeallocCpuId;
191}
192
193#ifdef _MSC_VER
194} __pragma(pack(pop));
195#else
196} __attribute__((__packed__));
197#endif
198
199} // namespace memprof
200} // namespace llvm
201
202#endif
203