brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.3 KiB · 26baddd Raw
270 lines · plain
1#ifndef MEMPROF_DATA_INC2#define MEMPROF_DATA_INC3/*===-- 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-exception8|*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 and16 * the other one sits in compiler-rt/include/profile directory. To make changes17 * 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 are19 * synced up.20 *21\*===----------------------------------------------------------------------===*/22#include <string.h>23 24#ifdef _MSC_VER25#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))26#else27#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))28#endif29 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 5ULL37 38// Currently supported versions.39#define MEMPROF_RAW_SUPPORTED_VERSIONS {3ULL, 4ULL, 5ULL}40 41#define MEMPROF_V3_MIB_SIZE 132ULL;42 43#define MEMPROF_BUILDID_MAX_SIZE 32ULL44 45namespace llvm {46namespace memprof {47// A struct describing the header used for the raw binary memprof profile format.48PACKED(struct Header {49  uint64_t Magic;50  uint64_t Version;51  uint64_t TotalSize;52  uint64_t SegmentOffset;53  uint64_t MIBOffset;54  uint64_t StackOffset;55});56 57// A struct describing the information necessary to describe a /proc/maps58// segment entry for a particular binary/library identified by its build id.59PACKED(struct SegmentEntry {60  uint64_t Start;61  uint64_t End;62  uint64_t Offset;63  uint64_t BuildIdSize;64  uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};65 66  // This constructor is only used in tests so don't set the BuildId.67  SegmentEntry(uint64_t S, uint64_t E, uint64_t O)68      : Start(S), End(E), Offset(O), BuildIdSize(0) {}69 70  SegmentEntry(const SegmentEntry& S) {71    Start = S.Start;72    End = S.End;73    Offset = S.Offset;74    BuildIdSize = S.BuildIdSize;75    memcpy(BuildId, S.BuildId, S.BuildIdSize);76  }77 78  SegmentEntry& operator=(const SegmentEntry& S) {79    Start = S.Start;80    End = S.End;81    Offset = S.Offset;82    BuildIdSize = S.BuildIdSize;83    memcpy(BuildId, S.BuildId, S.BuildIdSize);84    return *this;85  }86 87  bool operator==(const SegmentEntry& S) const {88    return Start == S.Start && End == S.End && Offset == S.Offset &&89           BuildIdSize == S.BuildIdSize &&90           memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;91  }92});93 94// Packed struct definition for MSVC. We can't use the PACKED macro defined in95// MemProfData.inc since it would mean we are embedding a directive (the96// #include for MIBEntryDef) into the macros which is undefined behaviour.97#ifdef _MSC_VER98__pragma(pack(push,1))99#endif100 101// A struct representing the heap allocation characteristics of a particular102// runtime context. This struct is shared between the compiler-rt runtime and103// the raw profile reader. The indexed format uses a separate, self-describing104// backwards compatible format.105struct MemInfoBlock{106 107#define MIBEntryDef(NameTag, Name, Type) Type Name;108#include "MIBEntryDef.inc"109#undef MIBEntryDef110 111bool operator==(const MemInfoBlock& Other) const {112  bool IsEqual = true;113#define MIBEntryDef(NameTag, Name, Type) \114  IsEqual = (IsEqual && Name == Other.Name);115#include "MIBEntryDef.inc"116#undef MIBEntryDef117  return IsEqual;118}119 120MemInfoBlock() {121#define MIBEntryDef(NameTag, Name, Type) Name = Type();122#include "MIBEntryDef.inc"123#undef MIBEntryDef124}125 126MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs,127             uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu,128             uintptr_t Histogram, uint32_t HistogramSize)129    : MemInfoBlock() {130  AllocCount = 1U;131  TotalAccessCount = AccessCount;132  MinAccessCount = AccessCount;133  MaxAccessCount = AccessCount;134  TotalSize = Size;135  MinSize = Size;136  MaxSize = Size;137  AllocTimestamp = AllocTs;138  DeallocTimestamp = DeallocTs;139  TotalLifetime = DeallocTimestamp - AllocTimestamp;140  MinLifetime = TotalLifetime;141  MaxLifetime = TotalLifetime;142  // Access density is accesses per byte. Multiply by 100 to include the143  // fractional part.144  TotalAccessDensity = AccessCount * 100 / Size;145  MinAccessDensity = TotalAccessDensity;146  MaxAccessDensity = TotalAccessDensity;147  // Lifetime access density is the access density per second of lifetime.148  // Multiply by 1000 to convert denominator lifetime to seconds (using a149  // minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first150  // to reduce truncations to 0.151  TotalLifetimeAccessDensity =152      TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1);153  MinLifetimeAccessDensity = TotalLifetimeAccessDensity;154  MaxLifetimeAccessDensity = TotalLifetimeAccessDensity;155  AllocCpuId = AllocCpu;156  DeallocCpuId = DeallocCpu;157  NumMigratedCpu = AllocCpuId != DeallocCpuId;158  AccessHistogramSize = HistogramSize;159  AccessHistogram = Histogram;160}161 162void Merge(const MemInfoBlock &newMIB) {163  AllocCount += newMIB.AllocCount;164 165  TotalAccessCount += newMIB.TotalAccessCount;166  MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;167  MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;168 169  TotalSize += newMIB.TotalSize;170  MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;171  MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize;172 173  TotalLifetime += newMIB.TotalLifetime;174  MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;175  MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;176 177  TotalAccessDensity += newMIB.TotalAccessDensity;178  MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity179                         ? newMIB.MinAccessDensity180                         : MinAccessDensity;181  MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity182                         ? newMIB.MaxAccessDensity183                         : MaxAccessDensity;184 185  TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity;186  MinLifetimeAccessDensity =187      newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity188          ? newMIB.MinLifetimeAccessDensity189          : MinLifetimeAccessDensity;190  MaxLifetimeAccessDensity =191      newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity192          ? newMIB.MaxLifetimeAccessDensity193          : MaxLifetimeAccessDensity;194 195  // We know newMIB was deallocated later, so just need to check if it was196  // allocated before last one deallocated.197  NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;198  AllocTimestamp = newMIB.AllocTimestamp;199  DeallocTimestamp = newMIB.DeallocTimestamp;200 201  NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;202  NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;203  AllocCpuId = newMIB.AllocCpuId;204  DeallocCpuId = newMIB.DeallocCpuId;205 206  // For merging histograms, we always keep the longer histogram, and add207  // values of shorter histogram to larger one.208  uintptr_t ShorterHistogram;209  uint32_t ShorterHistogramSize;210  if (newMIB.AccessHistogramSize > AccessHistogramSize) {211    ShorterHistogram = AccessHistogram;212    ShorterHistogramSize = AccessHistogramSize;213    // Swap histogram of current to larger histogram214    AccessHistogram = newMIB.AccessHistogram;215    AccessHistogramSize = newMIB.AccessHistogramSize;216  } else {217    ShorterHistogram = newMIB.AccessHistogram;218    ShorterHistogramSize = newMIB.AccessHistogramSize;219  }220  for (size_t i = 0; i < ShorterHistogramSize; ++i) {221    ((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i];222  }223}224 225#ifdef _MSC_VER226} __pragma(pack(pop));227#else228} __attribute__((__packed__));229#endif230 231constexpr int MantissaBits = 12;232constexpr int ExponentBits = 4;233constexpr uint16_t MaxMantissa = (1U << MantissaBits) - 1;234constexpr uint16_t MaxExponent = (1U << ExponentBits) - 1;235constexpr uint64_t MaxRepresentableValue = static_cast<uint64_t>(MaxMantissa)236                                           << MaxExponent;237 238// Encodes a 64-bit unsigned integer into a 16-bit scaled integer format.239inline uint16_t encodeHistogramCount(uint64_t Count) {240  if (Count == 0)241    return 0;242 243  if (Count > MaxRepresentableValue)244    Count = MaxRepresentableValue;245 246  if (Count <= MaxMantissa)247    return Count;248 249  uint64_t M = Count;250  uint16_t E = 0;251  while (M > MaxMantissa) {252    M = (M + 1) >> 1;253    E++;254  }255  return (E << MantissaBits) | static_cast<uint16_t>(M);256}257 258// Decodes a 16-bit scaled integer and returns the259// decoded 64-bit unsigned integer.260inline uint64_t decodeHistogramCount(uint16_t EncodedValue) {261  const uint16_t E = EncodedValue >> MantissaBits;262  const uint16_t M = EncodedValue & MaxMantissa;263  return static_cast<uint64_t>(M) << E;264}265 266} // namespace memprof267} // namespace llvm268 269#endif270