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 4ULL 37 38// Currently supported versions. 39#define MEMPROF_RAW_SUPPORTED_VERSIONS \ 40 { 3ULL, 4ULL } 41 42#define MEMPROF_V3_MIB_SIZE 132ULL; 43 44#define MEMPROF_BUILDID_MAX_SIZE 32ULL 45 46namespace llvm { 47namespace memprof { 48// A struct describing the header used for the raw binary memprof profile format. 49PACKED(struct Header { 50 uint64_t Magic; 51 uint64_t Version; 52 uint64_t TotalSize; 53 uint64_t SegmentOffset; 54 uint64_t MIBOffset; 55 uint64_t StackOffset; 56}); 57 58// A struct describing the information necessary to describe a /proc/maps 59// segment entry for a particular binary/library identified by its build id. 60PACKED(struct SegmentEntry { 61 uint64_t Start; 62 uint64_t End; 63 uint64_t Offset; 64 uint64_t BuildIdSize; 65 uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0}; 66 67 // This constructor is only used in tests so don't set the BuildId. 68 SegmentEntry(uint64_t S, uint64_t E, uint64_t O) 69 : Start(S), End(E), Offset(O), BuildIdSize(0) {} 70 71 SegmentEntry(const SegmentEntry& S) { 72 Start = S.Start; 73 End = S.End; 74 Offset = S.Offset; 75 BuildIdSize = S.BuildIdSize; 76 memcpy(BuildId, S.BuildId, S.BuildIdSize); 77 } 78 79 SegmentEntry& operator=(const SegmentEntry& S) { 80 Start = S.Start; 81 End = S.End; 82 Offset = S.Offset; 83 BuildIdSize = S.BuildIdSize; 84 memcpy(BuildId, S.BuildId, S.BuildIdSize); 85 return *this; 86 } 87 88 bool operator==(const SegmentEntry& S) const { 89 return Start == S.Start && End == S.End && Offset == S.Offset && 90 BuildIdSize == S.BuildIdSize && 91 memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0; 92 } 93}); 94 95// Packed struct definition for MSVC. We can't use the PACKED macro defined in 96// MemProfData.inc since it would mean we are embedding a directive (the 97// #include for MIBEntryDef) into the macros which is undefined behaviour. 98#ifdef _MSC_VER 99__pragma(pack(push,1)) 100#endif 101 102// A struct representing the heap allocation characteristics of a particular 103// runtime context. This struct is shared between the compiler-rt runtime and 104// the raw profile reader. The indexed format uses a separate, self-describing 105// backwards compatible format. 106struct MemInfoBlock{ 107 108#define MIBEntryDef(NameTag, Name, Type) Type Name; 109#include "MIBEntryDef.inc" 110#undef MIBEntryDef 111 112bool operator==(const MemInfoBlock& Other) const { 113 bool IsEqual = true; 114#define MIBEntryDef(NameTag, Name, Type) \ 115 IsEqual = (IsEqual && Name == Other.Name); 116#include "MIBEntryDef.inc" 117#undef MIBEntryDef 118 return IsEqual; 119} 120 121MemInfoBlock() { 122#define MIBEntryDef(NameTag, Name, Type) Name = Type(); 123#include "MIBEntryDef.inc" 124#undef MIBEntryDef 125} 126 127MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs, 128 uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu, 129 uintptr_t Histogram, uint32_t HistogramSize) 130 : MemInfoBlock() { 131 AllocCount = 1U; 132 TotalAccessCount = AccessCount; 133 MinAccessCount = AccessCount; 134 MaxAccessCount = AccessCount; 135 TotalSize = Size; 136 MinSize = Size; 137 MaxSize = Size; 138 AllocTimestamp = AllocTs; 139 DeallocTimestamp = DeallocTs; 140 TotalLifetime = DeallocTimestamp - AllocTimestamp; 141 MinLifetime = TotalLifetime; 142 MaxLifetime = TotalLifetime; 143 // Access density is accesses per byte. Multiply by 100 to include the 144 // fractional part. 145 TotalAccessDensity = AccessCount * 100 / Size; 146 MinAccessDensity = TotalAccessDensity; 147 MaxAccessDensity = TotalAccessDensity; 148 // Lifetime access density is the access density per second of lifetime. 149 // Multiply by 1000 to convert denominator lifetime to seconds (using a 150 // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first 151 // to reduce truncations to 0. 152 TotalLifetimeAccessDensity = 153 TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1); 154 MinLifetimeAccessDensity = TotalLifetimeAccessDensity; 155 MaxLifetimeAccessDensity = TotalLifetimeAccessDensity; 156 AllocCpuId = AllocCpu; 157 DeallocCpuId = DeallocCpu; 158 NumMigratedCpu = AllocCpuId != DeallocCpuId; 159 AccessHistogramSize = HistogramSize; 160 AccessHistogram = Histogram; 161} 162 163void Merge(const MemInfoBlock &newMIB) { 164 AllocCount += newMIB.AllocCount; 165 166 TotalAccessCount += newMIB.TotalAccessCount; 167 MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount; 168 MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount; 169 170 TotalSize += newMIB.TotalSize; 171 MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize; 172 MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize; 173 174 TotalLifetime += newMIB.TotalLifetime; 175 MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime; 176 MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime; 177 178 TotalAccessDensity += newMIB.TotalAccessDensity; 179 MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity 180 ? newMIB.MinAccessDensity 181 : MinAccessDensity; 182 MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity 183 ? newMIB.MaxAccessDensity 184 : MaxAccessDensity; 185 186 TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity; 187 MinLifetimeAccessDensity = 188 newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity 189 ? newMIB.MinLifetimeAccessDensity 190 : MinLifetimeAccessDensity; 191 MaxLifetimeAccessDensity = 192 newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity 193 ? newMIB.MaxLifetimeAccessDensity 194 : MaxLifetimeAccessDensity; 195 196 // We know newMIB was deallocated later, so just need to check if it was 197 // allocated before last one deallocated. 198 NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp; 199 AllocTimestamp = newMIB.AllocTimestamp; 200 DeallocTimestamp = newMIB.DeallocTimestamp; 201 202 NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId; 203 NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId; 204 AllocCpuId = newMIB.AllocCpuId; 205 DeallocCpuId = newMIB.DeallocCpuId; 206 207 // For merging histograms, we always keep the longer histogram, and add 208 // values of shorter histogram to larger one. 209 uintptr_t ShorterHistogram; 210 uint32_t ShorterHistogramSize; 211 if (newMIB.AccessHistogramSize > AccessHistogramSize) { 212 ShorterHistogram = AccessHistogram; 213 ShorterHistogramSize = AccessHistogramSize; 214 // Swap histogram of current to larger histogram 215 AccessHistogram = newMIB.AccessHistogram; 216 AccessHistogramSize = newMIB.AccessHistogramSize; 217 } else { 218 ShorterHistogram = newMIB.AccessHistogram; 219 ShorterHistogramSize = newMIB.AccessHistogramSize; 220 } 221 for (size_t i = 0; i < ShorterHistogramSize; ++i) { 222 ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i]; 223 } 224} 225 226#ifdef _MSC_VER 227} __pragma(pack(pop)); 228#else 229} __attribute__((__packed__)); 230#endif 231 232} // namespace memprof 233} // namespace llvm 234 235#endif 236