#ifndef LLVM_PROFILEDATA_MEMPROFDATA_INC #define LLVM_PROFILEDATA_MEMPROFDATA_INC /*===-- MemProfData.inc - MemProf profiling runtime structures -*- C++ -*-=== *\ |* |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |* See https://llvm.org/LICENSE.txt for license information. |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |* \*===----------------------------------------------------------------------===*/ /* * This is the main file that defines all the data structure, signature, * constant literals that are shared across profiling runtime library, * and host tools (reader/writer). * * This file has two identical copies. The primary copy lives in LLVM and * the other one sits in compiler-rt/include/profile directory. To make changes * in this file, first modify the primary copy and copy it over to compiler-rt. * Testing of any change in this file can start only after the two copies are * synced up. * \*===----------------------------------------------------------------------===*/ #ifdef _MSC_VER #define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop)) #else #define PACKED(...) __VA_ARGS__ __attribute__((__packed__)) #endif // A 64-bit magic number to uniquely identify the raw binary memprof profile file. #define MEMPROF_RAW_MAGIC_64 \ ((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | \ (uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129) // The version number of the raw binary format. #define MEMPROF_RAW_VERSION 1ULL namespace llvm { namespace memprof { // A struct describing the header used for the raw binary memprof profile format. PACKED(struct Header { uint64_t Magic; uint64_t Version; uint64_t TotalSize; uint64_t SegmentOffset; uint64_t MIBOffset; uint64_t StackOffset; }); // A struct describing the information necessary to describe a /proc/maps // segment entry for a particular binary/library identified by its build id. PACKED(struct SegmentEntry { uint64_t Start; uint64_t End; uint64_t Offset; // This field is unused until sanitizer procmaps support for build ids for // Linux-Elf is implemented. uint8_t BuildId[32] = {0}; SegmentEntry(uint64_t S, uint64_t E, uint64_t O) : Start(S), End(E), Offset(O) {} SegmentEntry(const SegmentEntry& S) { Start = S.Start; End = S.End; Offset = S.Offset; } SegmentEntry& operator=(const SegmentEntry& S) { Start = S.Start; End = S.End; Offset = S.Offset; return *this; } bool operator==(const SegmentEntry& S) const { return Start == S.Start && End == S.End && Offset == S.Offset; } }); // A struct representing the heap allocation characteristics of a particular // runtime context. This struct is shared between the compiler-rt runtime and // the raw profile reader. The indexed format uses a separate, self-describing // backwards compatible format. PACKED(struct MemInfoBlock { uint32_t alloc_count; uint64_t total_access_count, min_access_count, max_access_count; uint64_t total_size; uint32_t min_size, max_size; uint32_t alloc_timestamp, dealloc_timestamp; uint64_t total_lifetime; uint32_t min_lifetime, max_lifetime; uint32_t alloc_cpu_id, dealloc_cpu_id; uint32_t num_migrated_cpu; // Only compared to prior deallocated object currently. uint32_t num_lifetime_overlaps; uint32_t num_same_alloc_cpu; uint32_t num_same_dealloc_cpu; uint64_t data_type_id; // TODO: hash of type name MemInfoBlock() : alloc_count(0) {} MemInfoBlock(uint32_t size, uint64_t access_count, uint32_t alloc_timestamp, uint32_t dealloc_timestamp, uint32_t alloc_cpu, uint32_t dealloc_cpu) : alloc_count(1), total_access_count(access_count), min_access_count(access_count), max_access_count(access_count), total_size(size), min_size(size), max_size(size), alloc_timestamp(alloc_timestamp), dealloc_timestamp(dealloc_timestamp), total_lifetime(dealloc_timestamp - alloc_timestamp), min_lifetime(total_lifetime), max_lifetime(total_lifetime), alloc_cpu_id(alloc_cpu), dealloc_cpu_id(dealloc_cpu), num_lifetime_overlaps(0), num_same_alloc_cpu(0), num_same_dealloc_cpu(0) { num_migrated_cpu = alloc_cpu_id != dealloc_cpu_id; } void Merge(const MemInfoBlock &newMIB) { alloc_count += newMIB.alloc_count; total_access_count += newMIB.total_access_count; min_access_count = newMIB.min_access_count < min_access_count ? newMIB.min_access_count : min_access_count; max_access_count = newMIB.max_access_count < max_access_count ? newMIB.max_access_count : max_access_count; total_size += newMIB.total_size; min_size = newMIB.min_size < min_size ? newMIB.min_size : min_size; max_size = newMIB.max_size < max_size ? newMIB.max_size : max_size; total_lifetime += newMIB.total_lifetime; min_lifetime = newMIB.min_lifetime < min_lifetime ? newMIB.min_lifetime : min_lifetime; max_lifetime = newMIB.max_lifetime > max_lifetime ? newMIB.max_lifetime : max_lifetime; // We know newMIB was deallocated later, so just need to check if it was // allocated before last one deallocated. num_lifetime_overlaps += newMIB.alloc_timestamp < dealloc_timestamp; alloc_timestamp = newMIB.alloc_timestamp; dealloc_timestamp = newMIB.dealloc_timestamp; num_same_alloc_cpu += alloc_cpu_id == newMIB.alloc_cpu_id; num_same_dealloc_cpu += dealloc_cpu_id == newMIB.dealloc_cpu_id; alloc_cpu_id = newMIB.alloc_cpu_id; dealloc_cpu_id = newMIB.dealloc_cpu_id; } }); } // namespace memprof } // namespace llvm #endif