diff options
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/memprof/tests/rawprofile.cpp')
-rw-r--r-- | contrib/llvm-project/compiler-rt/lib/memprof/tests/rawprofile.cpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/memprof/tests/rawprofile.cpp b/contrib/llvm-project/compiler-rt/lib/memprof/tests/rawprofile.cpp new file mode 100644 index 000000000000..5764af9ce8af --- /dev/null +++ b/contrib/llvm-project/compiler-rt/lib/memprof/tests/rawprofile.cpp @@ -0,0 +1,170 @@ +#include "memprof/memprof_rawprofile.h" + +#include <cstdint> +#include <memory> + +#include "profile/MemProfData.inc" +#include "sanitizer_common/sanitizer_array_ref.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_procmaps.h" +#include "sanitizer_common/sanitizer_stackdepot.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { + +using ::__memprof::MIBMapTy; +using ::__memprof::SerializeToRawProfile; +using ::__sanitizer::StackDepotPut; +using ::__sanitizer::StackTrace; +using ::llvm::memprof::MemInfoBlock; + +uint64_t PopulateFakeMap(const MemInfoBlock &FakeMIB, uintptr_t StackPCBegin, + MIBMapTy &FakeMap) { + constexpr int kSize = 5; + uintptr_t array[kSize]; + for (int i = 0; i < kSize; i++) { + array[i] = StackPCBegin + i; + } + StackTrace St(array, kSize); + uint32_t Id = StackDepotPut(St); + + InsertOrMerge(Id, FakeMIB, FakeMap); + return Id; +} + +template <class T = uint64_t> T Read(char *&Buffer) { + static_assert(std::is_pod<T>::value, "Must be a POD type."); + assert(reinterpret_cast<size_t>(Buffer) % sizeof(T) == 0 && + "Unaligned read!"); + T t = *reinterpret_cast<T *>(Buffer); + Buffer += sizeof(T); + return t; +} + +TEST(MemProf, Basic) { + __sanitizer::LoadedModule FakeModule; + FakeModule.addAddressRange(/*begin=*/0x10, /*end=*/0x20, /*executable=*/true, + /*writable=*/false, /*name=*/""); + const char uuid[MEMPROF_BUILDID_MAX_SIZE] = {0xC, 0x0, 0xF, 0xF, 0xE, 0xE}; + FakeModule.setUuid(uuid, MEMPROF_BUILDID_MAX_SIZE); + __sanitizer::ArrayRef<__sanitizer::LoadedModule> Modules(&FakeModule, + (&FakeModule) + 1); + + MIBMapTy FakeMap; + MemInfoBlock FakeMIB; + // Since we want to override the constructor set vals to make it easier to + // test. + memset(&FakeMIB, 0, sizeof(MemInfoBlock)); + FakeMIB.AllocCount = 0x1; + FakeMIB.TotalAccessCount = 0x2; + + uint64_t FakeIds[2]; + FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap); + FakeIds[1] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/3, FakeMap); + + char *Ptr = nullptr; + uint64_t NumBytes = SerializeToRawProfile(FakeMap, Modules, Ptr); + const char *Buffer = Ptr; + + ASSERT_GT(NumBytes, 0ULL); + ASSERT_TRUE(Ptr); + + // Check the header. + EXPECT_THAT(Read(Ptr), MEMPROF_RAW_MAGIC_64); + EXPECT_THAT(Read(Ptr), MEMPROF_RAW_VERSION); + const uint64_t TotalSize = Read(Ptr); + const uint64_t SegmentOffset = Read(Ptr); + const uint64_t MIBOffset = Read(Ptr); + const uint64_t StackOffset = Read(Ptr); + + // ============= Check sizes and padding. + EXPECT_EQ(TotalSize, NumBytes); + EXPECT_EQ(TotalSize % 8, 0ULL); + + // Should be equal to the size of the raw profile header. + EXPECT_EQ(SegmentOffset, 48ULL); + + // We expect only 1 segment entry, 8b for the count and 64b for SegmentEntry + // in memprof_rawprofile.cpp. + EXPECT_EQ(MIBOffset - SegmentOffset, 72ULL); + + EXPECT_EQ(MIBOffset, 120ULL); + // We expect 2 mib entry, 8b for the count and sizeof(uint64_t) + + // sizeof(MemInfoBlock) contains stack id + MeminfoBlock. + EXPECT_EQ(StackOffset - MIBOffset, 8 + 2 * (8 + sizeof(MemInfoBlock))); + + EXPECT_EQ(StackOffset, 432ULL); + // We expect 2 stack entries, with 5 frames - 8b for total count, + // 2 * (8b for id, 8b for frame count and 5*8b for fake frames). + // Since this is the last section, there may be additional padding at the end + // to make the total profile size 8b aligned. + EXPECT_GE(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8)); + + // ============= Check contents. + unsigned char ExpectedSegmentBytes[72] = { + 0x01, 0, 0, 0, 0, 0, 0, 0, // Number of entries + 0x10, 0, 0, 0, 0, 0, 0, 0, // Start + 0x20, 0, 0, 0, 0, 0, 0, 0, // End + 0x0, 0, 0, 0, 0, 0, 0, 0, // Offset + 0x20, 0, 0, 0, 0, 0, 0, 0, // UuidSize + 0xC, 0x0, 0xF, 0xF, 0xE, 0xE // Uuid + }; + EXPECT_EQ(memcmp(Buffer + SegmentOffset, ExpectedSegmentBytes, 72), 0); + + // Check that the number of entries is 2. + EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + MIBOffset), 2ULL); + // Check that stack id is set. + EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + MIBOffset + 8), + FakeIds[0]); + + // Only check a few fields of the first MemInfoBlock. + unsigned char ExpectedMIBBytes[sizeof(MemInfoBlock)] = { + 0x01, 0, 0, 0, // Alloc count + 0x02, 0, 0, 0, // Total access count + }; + // Compare contents of 1st MIB after skipping count and stack id. + EXPECT_EQ( + memcmp(Buffer + MIBOffset + 16, ExpectedMIBBytes, sizeof(MemInfoBlock)), + 0); + // Compare contents of 2nd MIB after skipping count and stack id for the first + // and only the id for the second. + EXPECT_EQ(memcmp(Buffer + MIBOffset + 16 + sizeof(MemInfoBlock) + 8, + ExpectedMIBBytes, sizeof(MemInfoBlock)), + 0); + + // Check that the number of entries is 2. + EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + StackOffset), 2ULL); + // Check that the 1st stack id is set. + EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + StackOffset + 8), + FakeIds[0]); + // Contents are num pcs, value of each pc - 1. + unsigned char ExpectedStackBytes[2][6 * 8] = { + { + 0x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs + 0x1, 0, 0, 0, 0, 0, 0, 0, // PC ... + 0x2, 0, 0, 0, 0, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0, + 0x4, 0, 0, 0, 0, 0, 0, 0, 0x5, 0, 0, 0, 0, 0, 0, 0, + }, + { + 0x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs + 0x2, 0, 0, 0, 0, 0, 0, 0, // PC ... + 0x3, 0, 0, 0, 0, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, + 0x5, 0, 0, 0, 0, 0, 0, 0, 0x6, 0, 0, 0, 0, 0, 0, 0, + }, + }; + EXPECT_EQ(memcmp(Buffer + StackOffset + 16, ExpectedStackBytes[0], + sizeof(ExpectedStackBytes[0])), + 0); + + // Check that the 2nd stack id is set. + EXPECT_EQ( + *reinterpret_cast<const uint64_t *>(Buffer + StackOffset + 8 + 6 * 8 + 8), + FakeIds[1]); + + EXPECT_EQ(memcmp(Buffer + StackOffset + 16 + 6 * 8 + 8, ExpectedStackBytes[1], + sizeof(ExpectedStackBytes[1])), + 0); +} +} // namespace |