diff options
Diffstat (limited to 'compiler-rt/lib/memprof/tests/rawprofile.cpp')
| -rw-r--r-- | compiler-rt/lib/memprof/tests/rawprofile.cpp | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/compiler-rt/lib/memprof/tests/rawprofile.cpp b/compiler-rt/lib/memprof/tests/rawprofile.cpp new file mode 100644 index 000000000000..4404ab86092e --- /dev/null +++ b/compiler-rt/lib/memprof/tests/rawprofile.cpp @@ -0,0 +1,188 @@ +#include "memprof/memprof_rawprofile.h" + +#include "memprof/memprof_meminfoblock.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" + +#include <memory> + +namespace { + +using ::__memprof::MemInfoBlock; +using ::__memprof::MIBMapTy; +using ::__memprof::SerializeToRawProfile; +using ::__sanitizer::MemoryMappedSegment; +using ::__sanitizer::MemoryMappingLayoutBase; +using ::__sanitizer::StackDepotPut; +using ::__sanitizer::StackTrace; +using ::testing::_; +using ::testing::Action; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SetArgPointee; + +class MockMemoryMappingLayout final : public MemoryMappingLayoutBase { +public: + MOCK_METHOD(bool, Next, (MemoryMappedSegment *), (override)); + MOCK_METHOD(void, Reset, (), (override)); +}; + +u64 PopulateFakeMap(const MemInfoBlock &FakeMIB, uptr StackPCBegin, + MIBMapTy &FakeMap) { + constexpr int kSize = 5; + uptr array[kSize]; + for (int i = 0; i < kSize; i++) { + array[i] = StackPCBegin + i; + } + StackTrace St(array, kSize); + u32 Id = StackDepotPut(St); + + InsertOrMerge(Id, FakeMIB, FakeMap); + return Id; +} + +template <class T = u64> T Read(char *&Buffer) { + static_assert(std::is_pod<T>::value, "Must be a POD type."); + T t = *reinterpret_cast<T *>(Buffer); + Buffer += sizeof(T); + return t; +} + +TEST(MemProf, Basic) { + MockMemoryMappingLayout Layout; + MemoryMappedSegment FakeSegment; + memset(&FakeSegment, 0, sizeof(FakeSegment)); + FakeSegment.start = 0x10; + FakeSegment.end = 0x20; + FakeSegment.offset = 0x10; + uint8_t uuid[__sanitizer::kModuleUUIDSize] = {0xC, 0x0, 0xF, 0xF, 0xE, 0xE}; + memcpy(FakeSegment.uuid, uuid, __sanitizer::kModuleUUIDSize); + FakeSegment.protection = + __sanitizer::kProtectionExecute | __sanitizer::kProtectionRead; + + const Action<bool(MemoryMappedSegment *)> SetSegment = + DoAll(SetArgPointee<0>(FakeSegment), Return(true)); + EXPECT_CALL(Layout, Next(_)) + .WillOnce(SetSegment) + .WillOnce(Return(false)) + .WillOnce(SetSegment) + .WillRepeatedly(Return(false)); + + EXPECT_CALL(Layout, Reset).Times(2); + + 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.alloc_count = 0x1; + FakeMIB.total_access_count = 0x2; + + u64 FakeIds[2]; + FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap); + FakeIds[1] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/3, FakeMap); + + char *Ptr = nullptr; + u64 NumBytes = SerializeToRawProfile(FakeMap, Layout, 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 u64 TotalSize = Read(Ptr); + const u64 SegmentOffset = Read(Ptr); + const u64 MIBOffset = Read(Ptr); + const u64 StackOffset = Read(Ptr); + + // ============= Check sizes. + EXPECT_EQ(TotalSize, NumBytes); + + // 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 56b for SegmentEntry + // in memprof_rawprofile.cpp. + EXPECT_EQ(MIBOffset - SegmentOffset, 64ULL); + + EXPECT_EQ(MIBOffset, 112ULL); + // We expect 2 mib entry, 8b for the count and sizeof(u64) + + // sizeof(MemInfoBlock) contains stack id + MeminfoBlock. + EXPECT_EQ(StackOffset - MIBOffset, 8 + 2 * (8 + sizeof(MemInfoBlock))); + + EXPECT_EQ(StackOffset, 336ULL); + // 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) + EXPECT_EQ(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8)); + + // ============= Check contents. + unsigned char ExpectedSegmentBytes[64] = { + 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 + 0x10, 0, 0, 0, 0, 0, 0, 0, // Offset + 0x0C, 0x0, 0xF, 0xF, 0xE, 0xE, // Uuid + }; + EXPECT_EQ(memcmp(Buffer + SegmentOffset, ExpectedSegmentBytes, 64), 0); + + // Check that the number of entries is 2. + EXPECT_EQ(*reinterpret_cast<const u64 *>(Buffer + MIBOffset), 2ULL); + // Check that stack id is set. + EXPECT_EQ(*reinterpret_cast<const u64 *>(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 u64 *>(Buffer + StackOffset), 2ULL); + // Check that the 1st stack id is set. + EXPECT_EQ(*reinterpret_cast<const u64 *>(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 u64 *>(Buffer + StackOffset + 8 + 6 * 8 + 8), + FakeIds[1]); + + EXPECT_EQ(memcmp(Buffer + StackOffset + 16 + 6 * 8 + 8, ExpectedStackBytes[1], + sizeof(ExpectedStackBytes[1])), + 0); +} + +} // namespace |
