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