Path: blob/main/contrib/llvm-project/compiler-rt/lib/memprof/tests/rawprofile.cpp
35271 views
#include "memprof/memprof_rawprofile.h"12#include <cstdint>3#include <memory>45#include "profile/MemProfData.inc"6#include "sanitizer_common/sanitizer_array_ref.h"7#include "sanitizer_common/sanitizer_common.h"8#include "sanitizer_common/sanitizer_procmaps.h"9#include "sanitizer_common/sanitizer_stackdepot.h"10#include "sanitizer_common/sanitizer_stacktrace.h"11#include "gmock/gmock.h"12#include "gtest/gtest.h"1314namespace {1516using ::__memprof::MIBMapTy;17using ::__memprof::SerializeToRawProfile;18using ::__sanitizer::StackDepotPut;19using ::__sanitizer::StackTrace;20using ::llvm::memprof::MemInfoBlock;2122uint64_t PopulateFakeMap(const MemInfoBlock &FakeMIB, uintptr_t StackPCBegin,23MIBMapTy &FakeMap) {24constexpr int kSize = 5;25uintptr_t array[kSize];26for (int i = 0; i < kSize; i++) {27array[i] = StackPCBegin + i;28}29StackTrace St(array, kSize);30uint32_t Id = StackDepotPut(St);3132InsertOrMerge(Id, FakeMIB, FakeMap);33return Id;34}3536template <class T = uint64_t> T Read(char *&Buffer) {37static_assert(std::is_pod<T>::value, "Must be a POD type.");38assert(reinterpret_cast<size_t>(Buffer) % sizeof(T) == 0 &&39"Unaligned read!");40T t = *reinterpret_cast<T *>(Buffer);41Buffer += sizeof(T);42return t;43}4445TEST(MemProf, Basic) {46__sanitizer::LoadedModule FakeModule;47FakeModule.addAddressRange(/*begin=*/0x10, /*end=*/0x20, /*executable=*/true,48/*writable=*/false, /*name=*/"");49const char uuid[MEMPROF_BUILDID_MAX_SIZE] = {0xC, 0x0, 0xF, 0xF, 0xE, 0xE};50FakeModule.setUuid(uuid, MEMPROF_BUILDID_MAX_SIZE);51__sanitizer::ArrayRef<__sanitizer::LoadedModule> Modules(&FakeModule,52(&FakeModule) + 1);5354MIBMapTy FakeMap;55MemInfoBlock FakeMIB;56// Since we want to override the constructor set vals to make it easier to57// test.58memset(&FakeMIB, 0, sizeof(MemInfoBlock));59FakeMIB.AllocCount = 0x1;60FakeMIB.TotalAccessCount = 0x2;6162uint64_t FakeIds[2];63FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap);64FakeIds[1] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/3, FakeMap);6566char *Ptr = nullptr;67uint64_t NumBytes = SerializeToRawProfile(FakeMap, Modules, Ptr);68const char *Buffer = Ptr;6970ASSERT_GT(NumBytes, 0ULL);71ASSERT_TRUE(Ptr);7273// Check the header.74EXPECT_THAT(Read(Ptr), MEMPROF_RAW_MAGIC_64);75EXPECT_THAT(Read(Ptr), MEMPROF_RAW_VERSION);76const uint64_t TotalSize = Read(Ptr);77const uint64_t SegmentOffset = Read(Ptr);78const uint64_t MIBOffset = Read(Ptr);79const uint64_t StackOffset = Read(Ptr);8081// ============= Check sizes and padding.82EXPECT_EQ(TotalSize, NumBytes);83EXPECT_EQ(TotalSize % 8, 0ULL);8485// Should be equal to the size of the raw profile header.86EXPECT_EQ(SegmentOffset, 48ULL);8788// We expect only 1 segment entry, 8b for the count and 64b for SegmentEntry89// in memprof_rawprofile.cpp.90EXPECT_EQ(MIBOffset - SegmentOffset, 72ULL);9192EXPECT_EQ(MIBOffset, 120ULL);93// We expect 2 mib entry, 8b for the count and sizeof(uint64_t) +94// sizeof(MemInfoBlock) contains stack id + MeminfoBlock.95EXPECT_EQ(StackOffset - MIBOffset, 8 + 2 * (8 + sizeof(MemInfoBlock)));9697EXPECT_EQ(StackOffset, 432ULL);98// We expect 2 stack entries, with 5 frames - 8b for total count,99// 2 * (8b for id, 8b for frame count and 5*8b for fake frames).100// Since this is the last section, there may be additional padding at the end101// to make the total profile size 8b aligned.102EXPECT_GE(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8));103104// ============= Check contents.105unsigned char ExpectedSegmentBytes[72] = {1060x01, 0, 0, 0, 0, 0, 0, 0, // Number of entries1070x10, 0, 0, 0, 0, 0, 0, 0, // Start1080x20, 0, 0, 0, 0, 0, 0, 0, // End1090x0, 0, 0, 0, 0, 0, 0, 0, // Offset1100x20, 0, 0, 0, 0, 0, 0, 0, // UuidSize1110xC, 0x0, 0xF, 0xF, 0xE, 0xE // Uuid112};113EXPECT_EQ(memcmp(Buffer + SegmentOffset, ExpectedSegmentBytes, 72), 0);114115// Check that the number of entries is 2.116EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + MIBOffset), 2ULL);117// Check that stack id is set.118EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + MIBOffset + 8),119FakeIds[0]);120121// Only check a few fields of the first MemInfoBlock.122unsigned char ExpectedMIBBytes[sizeof(MemInfoBlock)] = {1230x01, 0, 0, 0, // Alloc count1240x02, 0, 0, 0, // Total access count125};126// Compare contents of 1st MIB after skipping count and stack id.127EXPECT_EQ(128memcmp(Buffer + MIBOffset + 16, ExpectedMIBBytes, sizeof(MemInfoBlock)),1290);130// Compare contents of 2nd MIB after skipping count and stack id for the first131// and only the id for the second.132EXPECT_EQ(memcmp(Buffer + MIBOffset + 16 + sizeof(MemInfoBlock) + 8,133ExpectedMIBBytes, sizeof(MemInfoBlock)),1340);135136// Check that the number of entries is 2.137EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + StackOffset), 2ULL);138// Check that the 1st stack id is set.139EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + StackOffset + 8),140FakeIds[0]);141// Contents are num pcs, value of each pc - 1.142unsigned char ExpectedStackBytes[2][6 * 8] = {143{1440x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs1450x1, 0, 0, 0, 0, 0, 0, 0, // PC ...1460x2, 0, 0, 0, 0, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0,1470x4, 0, 0, 0, 0, 0, 0, 0, 0x5, 0, 0, 0, 0, 0, 0, 0,148},149{1500x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs1510x2, 0, 0, 0, 0, 0, 0, 0, // PC ...1520x3, 0, 0, 0, 0, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0,1530x5, 0, 0, 0, 0, 0, 0, 0, 0x6, 0, 0, 0, 0, 0, 0, 0,154},155};156EXPECT_EQ(memcmp(Buffer + StackOffset + 16, ExpectedStackBytes[0],157sizeof(ExpectedStackBytes[0])),1580);159160// Check that the 2nd stack id is set.161EXPECT_EQ(162*reinterpret_cast<const uint64_t *>(Buffer + StackOffset + 8 + 6 * 8 + 8),163FakeIds[1]);164165EXPECT_EQ(memcmp(Buffer + StackOffset + 16 + 6 * 8 + 8, ExpectedStackBytes[1],166sizeof(ExpectedStackBytes[1])),1670);168}169} // namespace170171172