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\*===----------------------------------------------------------------------===*/ 2206c3fb27SDimitry 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*0fca6ea1SDimitry Andric#define MEMPROF_RAW_VERSION 4ULL 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric// Currently supported versions. 39*0fca6ea1SDimitry Andric#define MEMPROF_RAW_SUPPORTED_VERSIONS \ 40*0fca6ea1SDimitry Andric { 3ULL, 4ULL } 41*0fca6ea1SDimitry Andric 42*0fca6ea1SDimitry Andric#define MEMPROF_V3_MIB_SIZE 132ULL; 4306c3fb27SDimitry Andric 4406c3fb27SDimitry Andric#define MEMPROF_BUILDID_MAX_SIZE 32ULL 454824e7fdSDimitry Andric 464824e7fdSDimitry Andricnamespace llvm { 474824e7fdSDimitry Andricnamespace memprof { 484824e7fdSDimitry Andric// A struct describing the header used for the raw binary memprof profile format. 494824e7fdSDimitry AndricPACKED(struct Header { 504824e7fdSDimitry Andric uint64_t Magic; 514824e7fdSDimitry Andric uint64_t Version; 524824e7fdSDimitry Andric uint64_t TotalSize; 534824e7fdSDimitry Andric uint64_t SegmentOffset; 544824e7fdSDimitry Andric uint64_t MIBOffset; 554824e7fdSDimitry Andric uint64_t StackOffset; 564824e7fdSDimitry Andric}); 574824e7fdSDimitry Andric 584824e7fdSDimitry Andric// A struct describing the information necessary to describe a /proc/maps 594824e7fdSDimitry Andric// segment entry for a particular binary/library identified by its build id. 604824e7fdSDimitry AndricPACKED(struct SegmentEntry { 614824e7fdSDimitry Andric uint64_t Start; 624824e7fdSDimitry Andric uint64_t End; 634824e7fdSDimitry Andric uint64_t Offset; 6406c3fb27SDimitry Andric uint64_t BuildIdSize; 6506c3fb27SDimitry Andric uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0}; 661fd87a68SDimitry Andric 6706c3fb27SDimitry Andric // This constructor is only used in tests so don't set the BuildId. 6806c3fb27SDimitry Andric SegmentEntry(uint64_t S, uint64_t E, uint64_t O) 6906c3fb27SDimitry Andric : Start(S), End(E), Offset(O), BuildIdSize(0) {} 701fd87a68SDimitry Andric 711fd87a68SDimitry Andric SegmentEntry(const SegmentEntry& S) { 721fd87a68SDimitry Andric Start = S.Start; 731fd87a68SDimitry Andric End = S.End; 741fd87a68SDimitry Andric Offset = S.Offset; 7506c3fb27SDimitry Andric BuildIdSize = S.BuildIdSize; 7606c3fb27SDimitry Andric memcpy(BuildId, S.BuildId, S.BuildIdSize); 771fd87a68SDimitry Andric } 781fd87a68SDimitry Andric 791fd87a68SDimitry Andric SegmentEntry& operator=(const SegmentEntry& S) { 801fd87a68SDimitry Andric Start = S.Start; 811fd87a68SDimitry Andric End = S.End; 821fd87a68SDimitry Andric Offset = S.Offset; 8306c3fb27SDimitry Andric BuildIdSize = S.BuildIdSize; 8406c3fb27SDimitry Andric memcpy(BuildId, S.BuildId, S.BuildIdSize); 851fd87a68SDimitry Andric return *this; 861fd87a68SDimitry Andric } 871fd87a68SDimitry Andric 881fd87a68SDimitry Andric bool operator==(const SegmentEntry& S) const { 8906c3fb27SDimitry Andric return Start == S.Start && End == S.End && Offset == S.Offset && 9006c3fb27SDimitry Andric BuildIdSize == S.BuildIdSize && 9106c3fb27SDimitry Andric memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0; 921fd87a68SDimitry Andric } 934824e7fdSDimitry Andric}); 941fd87a68SDimitry Andric 9581ad6265SDimitry Andric// Packed struct definition for MSVC. We can't use the PACKED macro defined in 9681ad6265SDimitry Andric// MemProfData.inc since it would mean we are embedding a directive (the 9781ad6265SDimitry Andric// #include for MIBEntryDef) into the macros which is undefined behaviour. 9881ad6265SDimitry Andric#ifdef _MSC_VER 9981ad6265SDimitry Andric__pragma(pack(push,1)) 10081ad6265SDimitry Andric#endif 10181ad6265SDimitry Andric 1021fd87a68SDimitry Andric// A struct representing the heap allocation characteristics of a particular 1031fd87a68SDimitry Andric// runtime context. This struct is shared between the compiler-rt runtime and 1041fd87a68SDimitry Andric// the raw profile reader. The indexed format uses a separate, self-describing 1051fd87a68SDimitry Andric// backwards compatible format. 10681ad6265SDimitry Andricstruct MemInfoBlock{ 1071fd87a68SDimitry Andric 10881ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) Type Name; 10981ad6265SDimitry Andric#include "MIBEntryDef.inc" 11081ad6265SDimitry Andric#undef MIBEntryDef 1111fd87a68SDimitry Andric 11281ad6265SDimitry Andricbool operator==(const MemInfoBlock& Other) const { 11381ad6265SDimitry Andric bool IsEqual = true; 11481ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) \ 11581ad6265SDimitry Andric IsEqual = (IsEqual && Name == Other.Name); 11681ad6265SDimitry Andric#include "MIBEntryDef.inc" 11781ad6265SDimitry Andric#undef MIBEntryDef 11881ad6265SDimitry Andric return IsEqual; 11981ad6265SDimitry Andric} 1201fd87a68SDimitry Andric 12181ad6265SDimitry AndricMemInfoBlock() { 12281ad6265SDimitry Andric#define MIBEntryDef(NameTag, Name, Type) Name = Type(); 12381ad6265SDimitry Andric#include "MIBEntryDef.inc" 12481ad6265SDimitry Andric#undef MIBEntryDef 12581ad6265SDimitry Andric} 1261fd87a68SDimitry Andric 12781ad6265SDimitry AndricMemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs, 128*0fca6ea1SDimitry Andric uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu, 129*0fca6ea1SDimitry Andric uintptr_t Histogram, uint32_t HistogramSize) 13081ad6265SDimitry Andric : MemInfoBlock() { 13181ad6265SDimitry Andric AllocCount = 1U; 13281ad6265SDimitry Andric TotalAccessCount = AccessCount; 13381ad6265SDimitry Andric MinAccessCount = AccessCount; 13481ad6265SDimitry Andric MaxAccessCount = AccessCount; 13581ad6265SDimitry Andric TotalSize = Size; 13681ad6265SDimitry Andric MinSize = Size; 13781ad6265SDimitry Andric MaxSize = Size; 13881ad6265SDimitry Andric AllocTimestamp = AllocTs; 13981ad6265SDimitry Andric DeallocTimestamp = DeallocTs; 14081ad6265SDimitry Andric TotalLifetime = DeallocTimestamp - AllocTimestamp; 14181ad6265SDimitry Andric MinLifetime = TotalLifetime; 14281ad6265SDimitry Andric MaxLifetime = TotalLifetime; 143bdd1243dSDimitry Andric // Access density is accesses per byte. Multiply by 100 to include the 144bdd1243dSDimitry Andric // fractional part. 145bdd1243dSDimitry Andric TotalAccessDensity = AccessCount * 100 / Size; 146bdd1243dSDimitry Andric MinAccessDensity = TotalAccessDensity; 147bdd1243dSDimitry Andric MaxAccessDensity = TotalAccessDensity; 148bdd1243dSDimitry Andric // Lifetime access density is the access density per second of lifetime. 149bdd1243dSDimitry Andric // Multiply by 1000 to convert denominator lifetime to seconds (using a 150bdd1243dSDimitry Andric // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first 151bdd1243dSDimitry Andric // to reduce truncations to 0. 152bdd1243dSDimitry Andric TotalLifetimeAccessDensity = 153bdd1243dSDimitry Andric TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1); 154bdd1243dSDimitry Andric MinLifetimeAccessDensity = TotalLifetimeAccessDensity; 155bdd1243dSDimitry Andric MaxLifetimeAccessDensity = TotalLifetimeAccessDensity; 15681ad6265SDimitry Andric AllocCpuId = AllocCpu; 15781ad6265SDimitry Andric DeallocCpuId = DeallocCpu; 15881ad6265SDimitry Andric NumMigratedCpu = AllocCpuId != DeallocCpuId; 159*0fca6ea1SDimitry Andric AccessHistogramSize = HistogramSize; 160*0fca6ea1SDimitry Andric AccessHistogram = Histogram; 1611fd87a68SDimitry Andric} 1621fd87a68SDimitry Andric 1631fd87a68SDimitry Andricvoid Merge(const MemInfoBlock &newMIB) { 16481ad6265SDimitry Andric AllocCount += newMIB.AllocCount; 1651fd87a68SDimitry Andric 16681ad6265SDimitry Andric TotalAccessCount += newMIB.TotalAccessCount; 16781ad6265SDimitry Andric MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount; 168bdd1243dSDimitry Andric MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount; 1691fd87a68SDimitry Andric 17081ad6265SDimitry Andric TotalSize += newMIB.TotalSize; 17181ad6265SDimitry Andric MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize; 172bdd1243dSDimitry Andric MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize; 1731fd87a68SDimitry Andric 17481ad6265SDimitry Andric TotalLifetime += newMIB.TotalLifetime; 17581ad6265SDimitry Andric MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime; 17681ad6265SDimitry Andric MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime; 1771fd87a68SDimitry Andric 178bdd1243dSDimitry Andric TotalAccessDensity += newMIB.TotalAccessDensity; 179bdd1243dSDimitry Andric MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity 180bdd1243dSDimitry Andric ? newMIB.MinAccessDensity 181bdd1243dSDimitry Andric : MinAccessDensity; 182bdd1243dSDimitry Andric MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity 183bdd1243dSDimitry Andric ? newMIB.MaxAccessDensity 184bdd1243dSDimitry Andric : MaxAccessDensity; 185bdd1243dSDimitry Andric 186bdd1243dSDimitry Andric TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity; 187bdd1243dSDimitry Andric MinLifetimeAccessDensity = 188bdd1243dSDimitry Andric newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity 189bdd1243dSDimitry Andric ? newMIB.MinLifetimeAccessDensity 190bdd1243dSDimitry Andric : MinLifetimeAccessDensity; 191bdd1243dSDimitry Andric MaxLifetimeAccessDensity = 192bdd1243dSDimitry Andric newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity 193bdd1243dSDimitry Andric ? newMIB.MaxLifetimeAccessDensity 194bdd1243dSDimitry Andric : MaxLifetimeAccessDensity; 195bdd1243dSDimitry Andric 1961fd87a68SDimitry Andric // We know newMIB was deallocated later, so just need to check if it was 1971fd87a68SDimitry Andric // allocated before last one deallocated. 19881ad6265SDimitry Andric NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp; 19981ad6265SDimitry Andric AllocTimestamp = newMIB.AllocTimestamp; 20081ad6265SDimitry Andric DeallocTimestamp = newMIB.DeallocTimestamp; 2011fd87a68SDimitry Andric 20281ad6265SDimitry Andric NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId; 20381ad6265SDimitry Andric NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId; 20481ad6265SDimitry Andric AllocCpuId = newMIB.AllocCpuId; 20581ad6265SDimitry Andric DeallocCpuId = newMIB.DeallocCpuId; 206*0fca6ea1SDimitry Andric 207*0fca6ea1SDimitry Andric // For merging histograms, we always keep the longer histogram, and add 208*0fca6ea1SDimitry Andric // values of shorter histogram to larger one. 209*0fca6ea1SDimitry Andric uintptr_t ShorterHistogram; 210*0fca6ea1SDimitry Andric uint32_t ShorterHistogramSize; 211*0fca6ea1SDimitry Andric if (newMIB.AccessHistogramSize > AccessHistogramSize) { 212*0fca6ea1SDimitry Andric ShorterHistogram = AccessHistogram; 213*0fca6ea1SDimitry Andric ShorterHistogramSize = AccessHistogramSize; 214*0fca6ea1SDimitry Andric // Swap histogram of current to larger histogram 215*0fca6ea1SDimitry Andric AccessHistogram = newMIB.AccessHistogram; 216*0fca6ea1SDimitry Andric AccessHistogramSize = newMIB.AccessHistogramSize; 217*0fca6ea1SDimitry Andric } else { 218*0fca6ea1SDimitry Andric ShorterHistogram = newMIB.AccessHistogram; 219*0fca6ea1SDimitry Andric ShorterHistogramSize = newMIB.AccessHistogramSize; 220*0fca6ea1SDimitry Andric } 221*0fca6ea1SDimitry Andric for (size_t i = 0; i < ShorterHistogramSize; ++i) { 222*0fca6ea1SDimitry Andric ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i]; 223*0fca6ea1SDimitry Andric } 2241fd87a68SDimitry Andric} 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric#ifdef _MSC_VER 22781ad6265SDimitry Andric} __pragma(pack(pop)); 22881ad6265SDimitry Andric#else 22981ad6265SDimitry Andric} __attribute__((__packed__)); 23081ad6265SDimitry Andric#endif 2311fd87a68SDimitry Andric 2324824e7fdSDimitry Andric} // namespace memprof 2334824e7fdSDimitry Andric} // namespace llvm 2344824e7fdSDimitry Andric 2354824e7fdSDimitry Andric#endif 236