diff --git a/compiler-rt/include/profile/MemProfData.inc b/compiler-rt/include/profile/MemProfData.inc --- a/compiler-rt/include/profile/MemProfData.inc +++ b/compiler-rt/include/profile/MemProfData.inc @@ -80,71 +80,73 @@ } }); + + +// Packed struct definition for MSVC. We can't use the PACKED macro defined in +// MemProfData.inc since it would mean we are embedding a directive (the +// #include for MIBEntryDef) into the macros which is undefined behaviour. +#ifdef _MSC_VER +__pragma(pack(push,1)) +#endif + // 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; +struct MemInfoBlock{ + +#define MIBEntryDef(NameTag, Name, TypeTag, Type) Type Name; +#include "MemProfMIB.inc" +#undef MIBEntryDef + +MemInfoBlock() : AllocCount(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) + : AllocCount(1), TotalAccessCount(access_count), + MinAccessCount(access_count), MaxAccessCount(access_count), + TotalSize(size), MinSize(size), MaxSize(size), + AllocTimestamp(alloc_timestamp), DeallocTimestamp(dealloc_timestamp), + TotalLifetime(dealloc_timestamp - alloc_timestamp), + MinLifetime(TotalLifetime), MaxLifetime(TotalLifetime), + AllocCpuId(alloc_cpu), DeallocCpuId(dealloc_cpu), + NumLifetimeOverlaps(0), NumSameAllocCpu(0), + NumSameDeallocCpu(0) { + NumMigratedCpu = AllocCpuId != DeallocCpuId; +} + +void Merge(const MemInfoBlock &newMIB) { + AllocCount += newMIB.AllocCount; + + TotalAccessCount += newMIB.TotalAccessCount; + MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount; + MaxAccessCount = newMIB.MaxAccessCount < MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount; + + TotalSize += newMIB.TotalSize; + MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize; + MaxSize = newMIB.MaxSize < MaxSize ? newMIB.MaxSize : MaxSize; + + TotalLifetime += newMIB.TotalLifetime; + MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime; + MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime; + + // We know newMIB was deallocated later, so just need to check if it was + // allocated before last one deallocated. + NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp; + AllocTimestamp = newMIB.AllocTimestamp; + DeallocTimestamp = newMIB.DeallocTimestamp; + + NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId; + NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId; + AllocCpuId = newMIB.AllocCpuId; + DeallocCpuId = newMIB.DeallocCpuId; +} - 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; - } -}); +#ifdef _MSC_VER +} __pragma(pack(pop)); +#else +} __attribute__((__packed__)); +#endif } // namespace memprof } // namespace llvm diff --git a/compiler-rt/include/profile/MemProfMIB.inc b/compiler-rt/include/profile/MemProfMIB.inc new file mode 100644 --- /dev/null +++ b/compiler-rt/include/profile/MemProfMIB.inc @@ -0,0 +1,45 @@ +#ifndef MIBEntryDef +#define MIBEntryDef(NameTag, Name, TypeTag, Type) +#endif + +MIBEntryDef(AllocCount = 1, AllocCount, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(TotalAccessCount = 2, TotalAccessCount, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MinAccessCount = 3, MinAccessCount, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MaxAccessCount = 4, MaxAccessCount, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(TotalSize = 5, TotalSize, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MinSize = 6, MinSize, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(MaxSize = 7, MaxSize, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(AllocTimestamp = 8, AllocTimestamp, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(DeallocTimestamp = 9, DeallocTimestamp, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(TotalLifetime = 10, TotalLifetime, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MinLifetime = 11, MinLifetime, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(MaxLifetime = 12, MaxLifetime, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(AllocCpuId = 13, AllocCpuId, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(DeallocCpuId = 14, DeallocCpuId, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumMigratedCpu = 15, NumMigratedCpu, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumLifetimeOverlaps = 16, NumLifetimeOverlaps, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumSameAllocCpu = 17, NumSameAllocCpu, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumSameDeallocCpu = 18, NumSameDeallocCpu, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(DataTypeId = 19, DataTypeId, + MIBMeta::MIBFieldType::UINT64, uint64_t) + + + diff --git a/compiler-rt/lib/memprof/memprof_allocator.cpp b/compiler-rt/lib/memprof/memprof_allocator.cpp --- a/compiler-rt/lib/memprof/memprof_allocator.cpp +++ b/compiler-rt/lib/memprof/memprof_allocator.cpp @@ -43,32 +43,32 @@ u64 p; if (print_terse) { - p = M.total_size * 100 / M.alloc_count; - Printf("MIB:%llu/%u/%llu.%02llu/%u/%u/", id, M.alloc_count, p / 100, - p % 100, M.min_size, M.max_size); - p = M.total_access_count * 100 / M.alloc_count; - Printf("%llu.%02llu/%llu/%llu/", p / 100, p % 100, M.min_access_count, - M.max_access_count); - p = M.total_lifetime * 100 / M.alloc_count; - Printf("%llu.%02llu/%u/%u/", p / 100, p % 100, M.min_lifetime, - M.max_lifetime); - Printf("%u/%u/%u/%u\n", M.num_migrated_cpu, M.num_lifetime_overlaps, - M.num_same_alloc_cpu, M.num_same_dealloc_cpu); + p = M.TotalSize * 100 / M.AllocCount; + Printf("MIB:%llu/%u/%llu.%02llu/%u/%u/", id, M.AllocCount, p / 100, p % 100, + M.MinSize, M.MaxSize); + p = M.TotalAccessCount * 100 / M.AllocCount; + Printf("%llu.%02llu/%llu/%llu/", p / 100, p % 100, M.MinAccessCount, + M.MaxAccessCount); + p = M.TotalLifetime * 100 / M.AllocCount; + Printf("%llu.%02llu/%u/%u/", p / 100, p % 100, M.MinLifetime, + M.MaxLifetime); + Printf("%u/%u/%u/%u\n", M.NumMigratedCpu, M.NumLifetimeOverlaps, + M.NumSameAllocCpu, M.NumSameDeallocCpu); } else { - p = M.total_size * 100 / M.alloc_count; + p = M.TotalSize * 100 / M.AllocCount; Printf("Memory allocation stack id = %llu\n", id); Printf("\talloc_count %u, size (ave/min/max) %llu.%02llu / %u / %u\n", - M.alloc_count, p / 100, p % 100, M.min_size, M.max_size); - p = M.total_access_count * 100 / M.alloc_count; + M.AllocCount, p / 100, p % 100, M.MinSize, M.MaxSize); + p = M.TotalAccessCount * 100 / M.AllocCount; Printf("\taccess_count (ave/min/max): %llu.%02llu / %llu / %llu\n", p / 100, - p % 100, M.min_access_count, M.max_access_count); - p = M.total_lifetime * 100 / M.alloc_count; + p % 100, M.MinAccessCount, M.MaxAccessCount); + p = M.TotalLifetime * 100 / M.AllocCount; Printf("\tlifetime (ave/min/max): %llu.%02llu / %u / %u\n", p / 100, - p % 100, M.min_lifetime, M.max_lifetime); + p % 100, M.MinLifetime, M.MaxLifetime); Printf("\tnum migrated: %u, num lifetime overlaps: %u, num same alloc " "cpu: %u, num same dealloc_cpu: %u\n", - M.num_migrated_cpu, M.num_lifetime_overlaps, M.num_same_alloc_cpu, - M.num_same_dealloc_cpu); + M.NumMigratedCpu, M.NumLifetimeOverlaps, M.NumSameAllocCpu, + M.NumSameDeallocCpu); } } } // namespace diff --git a/compiler-rt/lib/memprof/tests/rawprofile.cpp b/compiler-rt/lib/memprof/tests/rawprofile.cpp --- a/compiler-rt/lib/memprof/tests/rawprofile.cpp +++ b/compiler-rt/lib/memprof/tests/rawprofile.cpp @@ -82,8 +82,8 @@ // Since we want to override the constructor set vals to make it easier to // test. memset(&FakeMIB, 0, sizeof(MemInfoBlock)); - FakeMIB.alloc_count = 0x1; - FakeMIB.total_access_count = 0x2; + FakeMIB.AllocCount = 0x1; + FakeMIB.TotalAccessCount = 0x2; uint64_t FakeIds[2]; FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap); diff --git a/llvm/include/llvm/ProfileData/MemProf.h b/llvm/include/llvm/ProfileData/MemProf.h --- a/llvm/include/llvm/ProfileData/MemProf.h +++ b/llvm/include/llvm/ProfileData/MemProf.h @@ -5,12 +5,77 @@ #include #include +#include "llvm/ADT/SmallVector.h" #include "llvm/ProfileData/MemProfData.inc" #include "llvm/Support/raw_ostream.h" namespace llvm { namespace memprof { +enum class Meta { + Start = 0, +#define MIBEntryDef(NameTag, Name, TypeTag, Type) NameTag, +#include "llvm/ProfileData/MemProfMIB.inc" +#undef MIBEntryDef + Size +}; + +struct PortableMemInfoBlock { + PortableMemInfoBlock() {} + PortableMemInfoBlock(const MemInfoBlock &Block) : Info(Block) {} + PortableMemInfoBlock(const llvm::SmallVectorImpl &Schema, char *Ptr) { + for (const Meta Id : Schema) { + switch (Id) { +#define MIBEntryDef(NameTag, Name, TypeTag, Type) \ + case Meta::Name: { \ + Info.Name = *reinterpret_cast(Ptr); \ + Ptr += sizeof(Type); \ + } break; +#include "llvm/ProfileData/MemProfMIB.inc" +#undef MIBEntryDef + default: + llvm_unreachable("Unknown meta type id, is the profile collected from " + "a newer version of the runtime?"); + } + } + } + + void serialize(const llvm::SmallVectorImpl &Schema, char *Ptr) { + for (const Meta Id : Schema) { + switch (Id) { +#define MIBEntryDef(NameTag, Name, TypeTag, Type) \ + case Meta::Name: { \ + *(Type *)Ptr = Info.Name; \ + Ptr += sizeof(Type); \ + } break; +#include "llvm/ProfileData/MemProfMIB.inc" +#undef MIBEntryDef + default: + llvm_unreachable("Unknown meta type id, invalid input?"); + } + } + } + + void printYAML(raw_ostream &OS) const { + OS << " MemInfoBlock:\n"; +#define MIBEntryDef(NameTag, Name, TypeTag, Type) \ + OS << " " << #Name << ": " << Info.Name << "\n"; +#include "llvm/ProfileData/MemProfMIB.inc" +#undef MIBEntryDef + } + + // Define getters for each type which can be called by analyses. +#define MIBEntryDef(NameTag, Name, TypeTag, Type) \ + Type get##Name() { return Info.Name; } +#include "llvm/ProfileData/MemProfMIB.inc" +#undef MIBEntryDef + + void clear() { Info = MemInfoBlock(); } + +private: + MemInfoBlock Info; +}; + struct MemProfRecord { struct Frame { std::string Function; @@ -24,14 +89,11 @@ }; std::vector CallStack; - // TODO: Replace this with the entry format described in the RFC so - // that the InstrProfRecord reader and writer do not have to be concerned - // about backwards compat. - MemInfoBlock Info; + PortableMemInfoBlock Info; void clear() { CallStack.clear(); - Info = MemInfoBlock(); + Info.clear(); } // Prints out the contents of the memprof record in YAML. @@ -45,29 +107,7 @@ << " Inline: " << Frame.IsInlineFrame << "\n"; } - OS << " MemInfoBlock:\n"; - - // TODO: Replace this once the format is updated to be version agnostic. -#define PRINT(Field) OS << " " #Field ": " << Info.Field << "\n" - PRINT(alloc_count); - PRINT(total_access_count); - PRINT(min_access_count); - PRINT(max_access_count); - PRINT(total_size); - PRINT(min_size); - PRINT(max_size); - PRINT(alloc_timestamp); - PRINT(dealloc_timestamp); - PRINT(total_lifetime); - PRINT(min_lifetime); - PRINT(max_lifetime); - PRINT(alloc_cpu_id); - PRINT(dealloc_cpu_id); - PRINT(num_migrated_cpu); - PRINT(num_lifetime_overlaps); - PRINT(num_same_alloc_cpu); - PRINT(num_same_dealloc_cpu); -#undef PRINT + Info.printYAML(OS); } }; diff --git a/llvm/include/llvm/ProfileData/MemProfData.inc b/llvm/include/llvm/ProfileData/MemProfData.inc --- a/llvm/include/llvm/ProfileData/MemProfData.inc +++ b/llvm/include/llvm/ProfileData/MemProfData.inc @@ -80,71 +80,82 @@ } }); + + +// Packed struct definition for MSVC. We can't use the PACKED macro defined in +// MemProfData.inc since it would mean we are embedding a directive (the +// #include for MIBEntryDef) into the macros which is undefined behaviour. +#ifdef _MSC_VER +__pragma(pack(push,1)) +#endif + // 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; +struct MemInfoBlock{ + +#define MIBEntryDef(NameTag, Name, TypeTag, Type) Type Name; +#include "MemProfMIB.inc" +#undef MIBEntryDef + +bool operator==(const MemInfoBlock& Other) const { + bool IsEqual = true; +#define MIBEntryDef(NameTag, Name, TypeTag, Type) \ + IsEqual = (IsEqual && Name == Other.Name); +#include "MemProfMIB.inc" +#undef MIBEntryDef + return IsEqual; +} + +MemInfoBlock() : AllocCount(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) + : AllocCount(1), TotalAccessCount(access_count), + MinAccessCount(access_count), MaxAccessCount(access_count), + TotalSize(size), MinSize(size), MaxSize(size), + AllocTimestamp(alloc_timestamp), DeallocTimestamp(dealloc_timestamp), + TotalLifetime(dealloc_timestamp - alloc_timestamp), + MinLifetime(TotalLifetime), MaxLifetime(TotalLifetime), + AllocCpuId(alloc_cpu), DeallocCpuId(dealloc_cpu), + NumLifetimeOverlaps(0), NumSameAllocCpu(0), + NumSameDeallocCpu(0) { + NumMigratedCpu = AllocCpuId != DeallocCpuId; +} + +void Merge(const MemInfoBlock &newMIB) { + AllocCount += newMIB.AllocCount; + + TotalAccessCount += newMIB.TotalAccessCount; + MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount; + MaxAccessCount = newMIB.MaxAccessCount < MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount; + + TotalSize += newMIB.TotalSize; + MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize; + MaxSize = newMIB.MaxSize < MaxSize ? newMIB.MaxSize : MaxSize; + + TotalLifetime += newMIB.TotalLifetime; + MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime; + MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime; + + // We know newMIB was deallocated later, so just need to check if it was + // allocated before last one deallocated. + NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp; + AllocTimestamp = newMIB.AllocTimestamp; + DeallocTimestamp = newMIB.DeallocTimestamp; + + NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId; + NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId; + AllocCpuId = newMIB.AllocCpuId; + DeallocCpuId = newMIB.DeallocCpuId; +} - 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; - } -}); +#ifdef _MSC_VER +} __pragma(pack(pop)); +#else +} __attribute__((__packed__)); +#endif } // namespace memprof } // namespace llvm diff --git a/llvm/include/llvm/ProfileData/MemProfMIB.inc b/llvm/include/llvm/ProfileData/MemProfMIB.inc new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/ProfileData/MemProfMIB.inc @@ -0,0 +1,71 @@ +/*===-- MemProfMIB.inc - MemProf profiling primitives -*- 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 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. + * + * This file defines the primitives for data structures used in the profiling + * runtime and the serialized profile file. + * E.g. To declare the fields in a struct + * + * struct MemInfoBlock { + * #define MIBEntryDef(NameTag, Name, TypeTag, Type) Type Tag; + * #include "MemProfMIB.inc" + * #undef MIBEntryDef + * }; +\*===----------------------------------------------------------------------===*/ + +// If the MIBEntryDef macro has not been defined then define it to silently +// consume the arguments. +#ifndef MIBEntryDef +#define MIBEntryDef(NameTag, Name, TypeTag, Type) +#endif + +// Ensure that the constructor and methods of MemInfoBlock in MemProfData.inc +// are updated if new members are added. +MIBEntryDef(AllocCount = 1, AllocCount, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(TotalAccessCount = 2, TotalAccessCount, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MinAccessCount = 3, MinAccessCount, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MaxAccessCount = 4, MaxAccessCount, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(TotalSize = 5, TotalSize, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MinSize = 6, MinSize, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(MaxSize = 7, MaxSize, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(AllocTimestamp = 8, AllocTimestamp, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(DeallocTimestamp = 9, DeallocTimestamp, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(TotalLifetime = 10, TotalLifetime, + MIBMeta::MIBFieldType::UINT64, uint64_t) +MIBEntryDef(MinLifetime = 11, MinLifetime, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(MaxLifetime = 12, MaxLifetime, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(AllocCpuId = 13, AllocCpuId, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(DeallocCpuId = 14, DeallocCpuId, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumMigratedCpu = 15, NumMigratedCpu, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumLifetimeOverlaps = 16, NumLifetimeOverlaps, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumSameAllocCpu = 17, NumSameAllocCpu, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(NumSameDeallocCpu = 18, NumSameDeallocCpu, + MIBMeta::MIBFieldType::UINT32, uint32_t) +MIBEntryDef(DataTypeId = 19, DataTypeId, + MIBMeta::MIBFieldType::UINT64, uint64_t) diff --git a/llvm/test/tools/llvm-profdata/memprof-basic.test b/llvm/test/tools/llvm-profdata/memprof-basic.test --- a/llvm/test/tools/llvm-profdata/memprof-basic.test +++ b/llvm/test/tools/llvm-profdata/memprof-basic.test @@ -58,24 +58,25 @@ CHECK-NEXT: Column: 0 CHECK-NEXT: Inline: 0 CHECK-NEXT: MemInfoBlock: -CHECK-NEXT: alloc_count: 1 -CHECK-NEXT: total_access_count: 0 -CHECK-NEXT: min_access_count: 0 -CHECK-NEXT: max_access_count: 0 -CHECK-NEXT: total_size: 53 -CHECK-NEXT: min_size: 53 -CHECK-NEXT: max_size: 53 -CHECK-NEXT: alloc_timestamp: 0 -CHECK-NEXT: dealloc_timestamp: 987 -CHECK-NEXT: total_lifetime: 987 -CHECK-NEXT: min_lifetime: 987 -CHECK-NEXT: max_lifetime: 987 -CHECK-NEXT: alloc_cpu_id: 4294967295 -CHECK-NEXT: dealloc_cpu_id: 56 -CHECK-NEXT: num_migrated_cpu: 1 -CHECK-NEXT: num_lifetime_overlaps: 0 -CHECK-NEXT: num_same_alloc_cpu: 0 -CHECK-NEXT: num_same_dealloc_cpu: 0 +CHECK-NEXT: AllocCount: 1 +CHECK-NEXT: TotalAccessCount: 0 +CHECK-NEXT: MinAccessCount: 0 +CHECK-NEXT: MaxAccessCount: 0 +CHECK-NEXT: TotalSize: 53 +CHECK-NEXT: MinSize: 53 +CHECK-NEXT: MaxSize: 53 +CHECK-NEXT: AllocTimestamp: 0 +CHECK-NEXT: DeallocTimestamp: 987 +CHECK-NEXT: TotalLifetime: 987 +CHECK-NEXT: MinLifetime: 987 +CHECK-NEXT: MaxLifetime: 987 +CHECK-NEXT: AllocCpuId: 4294967295 +CHECK-NEXT: DeallocCpuId: 56 +CHECK-NEXT: NumMigratedCpu: 1 +CHECK-NEXT: NumLifetimeOverlaps: 0 +CHECK-NEXT: NumSameAllocCpu: 0 +CHECK-NEXT: NumSameDeallocCpu: 0 +CHECK-NEXT: DataTypeId: {{[0-9]+}} CHECK-NEXT: - CHECK-NEXT: Callstack: CHECK-NEXT: - @@ -94,24 +95,25 @@ CHECK-NEXT: Column: 0 CHECK-NEXT: Inline: 0 CHECK-NEXT: MemInfoBlock: -CHECK-NEXT: alloc_count: 1 -CHECK-NEXT: total_access_count: 2 -CHECK-NEXT: min_access_count: 2 -CHECK-NEXT: max_access_count: 2 -CHECK-NEXT: total_size: 10 -CHECK-NEXT: min_size: 10 -CHECK-NEXT: max_size: 10 -CHECK-NEXT: alloc_timestamp: 986 -CHECK-NEXT: dealloc_timestamp: 986 -CHECK-NEXT: total_lifetime: 0 -CHECK-NEXT: min_lifetime: 0 -CHECK-NEXT: max_lifetime: 0 -CHECK-NEXT: alloc_cpu_id: 56 -CHECK-NEXT: dealloc_cpu_id: 56 -CHECK-NEXT: num_migrated_cpu: 0 -CHECK-NEXT: num_lifetime_overlaps: 0 -CHECK-NEXT: num_same_alloc_cpu: 0 -CHECK-NEXT: num_same_dealloc_cpu: 0 +CHECK-NEXT: AllocCount: 1 +CHECK-NEXT: TotalAccessCount: 2 +CHECK-NEXT: MinAccessCount: 2 +CHECK-NEXT: MaxAccessCount: 2 +CHECK-NEXT: TotalSize: 10 +CHECK-NEXT: MinSize: 10 +CHECK-NEXT: MaxSize: 10 +CHECK-NEXT: AllocTimestamp: 986 +CHECK-NEXT: DeallocTimestamp: 986 +CHECK-NEXT: TotalLifetime: 0 +CHECK-NEXT: MinLifetime: 0 +CHECK-NEXT: MaxLifetime: 0 +CHECK-NEXT: AllocCpuId: 56 +CHECK-NEXT: DeallocCpuId: 56 +CHECK-NEXT: NumMigratedCpu: 0 +CHECK-NEXT: NumLifetimeOverlaps: 0 +CHECK-NEXT: NumSameAllocCpu: 0 +CHECK-NEXT: NumSameDeallocCpu: 0 +CHECK-NEXT: DataTypeId: {{[0-9]+}} CHECK-NEXT: - CHECK-NEXT: Callstack: CHECK-NEXT: - @@ -130,21 +132,22 @@ CHECK-NEXT: Column: 0 CHECK-NEXT: Inline: 0 CHECK-NEXT: MemInfoBlock: -CHECK-NEXT: alloc_count: 1 -CHECK-NEXT: total_access_count: 2 -CHECK-NEXT: min_access_count: 2 -CHECK-NEXT: max_access_count: 2 -CHECK-NEXT: total_size: 10 -CHECK-NEXT: min_size: 10 -CHECK-NEXT: max_size: 10 -CHECK-NEXT: alloc_timestamp: 987 -CHECK-NEXT: dealloc_timestamp: 987 -CHECK-NEXT: total_lifetime: 0 -CHECK-NEXT: min_lifetime: 0 -CHECK-NEXT: max_lifetime: 0 -CHECK-NEXT: alloc_cpu_id: 56 -CHECK-NEXT: dealloc_cpu_id: 56 -CHECK-NEXT: num_migrated_cpu: 0 -CHECK-NEXT: num_lifetime_overlaps: 0 -CHECK-NEXT: num_same_alloc_cpu: 0 -CHECK-NEXT: num_same_dealloc_cpu: 0 +CHECK-NEXT: AllocCount: 1 +CHECK-NEXT: TotalAccessCount: 2 +CHECK-NEXT: MinAccessCount: 2 +CHECK-NEXT: MaxAccessCount: 2 +CHECK-NEXT: TotalSize: 10 +CHECK-NEXT: MinSize: 10 +CHECK-NEXT: MaxSize: 10 +CHECK-NEXT: AllocTimestamp: 987 +CHECK-NEXT: DeallocTimestamp: 987 +CHECK-NEXT: TotalLifetime: 0 +CHECK-NEXT: MinLifetime: 0 +CHECK-NEXT: MaxLifetime: 0 +CHECK-NEXT: AllocCpuId: 56 +CHECK-NEXT: DeallocCpuId: 56 +CHECK-NEXT: NumMigratedCpu: 0 +CHECK-NEXT: NumLifetimeOverlaps: 0 +CHECK-NEXT: NumSameAllocCpu: 0 +CHECK-NEXT: NumSameDeallocCpu: 0 +CHECK-NEXT: DataTypeId: {{[0-9]+}} diff --git a/llvm/unittests/ProfileData/MemProfTest.cpp b/llvm/unittests/ProfileData/MemProfTest.cpp --- a/llvm/unittests/ProfileData/MemProfTest.cpp +++ b/llvm/unittests/ProfileData/MemProfTest.cpp @@ -24,6 +24,8 @@ using ::llvm::memprof::CallStackMap; using ::llvm::memprof::MemInfoBlock; using ::llvm::memprof::MemProfRecord; +using ::llvm::memprof::Meta; +using ::llvm::memprof::PortableMemInfoBlock; using ::llvm::memprof::RawMemProfReader; using ::llvm::memprof::SegmentEntry; using ::llvm::object::SectionedAddress; @@ -122,8 +124,8 @@ CSM[0x2] = {0x6000, 0x2000}; llvm::MapVector Prof; - Prof[0x1].alloc_count = 1; - Prof[0x2].alloc_count = 2; + Prof[0x1].AllocCount = 1; + Prof[0x2].AllocCount = 2; auto Seg = makeSegments(); @@ -135,8 +137,8 @@ } EXPECT_EQ(Records.size(), 2U); - EXPECT_EQ(Records[0].Info.alloc_count, 1U); - EXPECT_EQ(Records[1].Info.alloc_count, 2U); + EXPECT_EQ(Records[0].Info.getAllocCount(), 1U); + EXPECT_EQ(Records[1].Info.getAllocCount(), 2U); EXPECT_THAT(Records[0].CallStack[0], FrameContains("foo", 5U, 30U, false)); EXPECT_THAT(Records[0].CallStack[1], FrameContains("bar", 51U, 20U, true)); @@ -146,4 +148,26 @@ EXPECT_THAT(Records[1].CallStack[3], FrameContains("bar", 51U, 20U, true)); } +TEST(MemProf, PortableWrapper) { + MemInfoBlock Info(/*size=*/16, /*access_count=*/7, /*alloc_timestamp=*/1000, + /*dealloc_timestamp=*/2000, /*alloc_cpu=*/3, + /*dealloc_cpu=*/4); + + llvm::SmallVector(Meta::Size)> Schema; +#define MIBEntryDef(NameTag, Name, TypeTag, Type) Schema.push_back(Meta::Name); +#include "llvm/ProfileData/MemProfMIB.inc" +#undef MIBEntryDef + + PortableMemInfoBlock Block(Schema, reinterpret_cast(&Info)); + + EXPECT_EQ(Block.getAllocCount(), Info.AllocCount); + EXPECT_EQ(Block.getTotalAccessCount(), Info.MaxAccessCount); + EXPECT_EQ(Block.getAllocCpuId(), Info.AllocCpuId); + + char Output[sizeof(MemInfoBlock)] = {0}; + Block.serialize(Schema, Output); + + EXPECT_EQ(*reinterpret_cast(Output), Info); +} + } // namespace