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