1349cc55cSDimitry Andric #include "memprof/memprof_rawprofile.h"
2349cc55cSDimitry Andric 
34824e7fdSDimitry Andric #include <cstdint>
44824e7fdSDimitry Andric #include <memory>
54824e7fdSDimitry Andric 
64824e7fdSDimitry Andric #include "profile/MemProfData.inc"
7*06c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_array_ref.h"
8349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
9349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_procmaps.h"
10349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
11349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
12349cc55cSDimitry Andric #include "gmock/gmock.h"
13349cc55cSDimitry Andric #include "gtest/gtest.h"
14349cc55cSDimitry Andric 
15349cc55cSDimitry Andric namespace {
16349cc55cSDimitry Andric 
17349cc55cSDimitry Andric using ::__memprof::MIBMapTy;
18349cc55cSDimitry Andric using ::__memprof::SerializeToRawProfile;
19349cc55cSDimitry Andric using ::__sanitizer::StackDepotPut;
20349cc55cSDimitry Andric using ::__sanitizer::StackTrace;
211fd87a68SDimitry Andric using ::llvm::memprof::MemInfoBlock;
22349cc55cSDimitry Andric 
PopulateFakeMap(const MemInfoBlock & FakeMIB,uintptr_t StackPCBegin,MIBMapTy & FakeMap)23*06c3fb27SDimitry Andric uint64_t PopulateFakeMap(const MemInfoBlock &FakeMIB, uintptr_t StackPCBegin,
24349cc55cSDimitry Andric                          MIBMapTy &FakeMap) {
25349cc55cSDimitry Andric   constexpr int kSize = 5;
26*06c3fb27SDimitry Andric   uintptr_t array[kSize];
27349cc55cSDimitry Andric   for (int i = 0; i < kSize; i++) {
28349cc55cSDimitry Andric     array[i] = StackPCBegin + i;
29349cc55cSDimitry Andric   }
30349cc55cSDimitry Andric   StackTrace St(array, kSize);
311fd87a68SDimitry Andric   uint32_t Id = StackDepotPut(St);
32349cc55cSDimitry Andric 
33349cc55cSDimitry Andric   InsertOrMerge(Id, FakeMIB, FakeMap);
34349cc55cSDimitry Andric   return Id;
35349cc55cSDimitry Andric }
36349cc55cSDimitry Andric 
Read(char * & Buffer)371fd87a68SDimitry Andric template <class T = uint64_t> T Read(char *&Buffer) {
38349cc55cSDimitry Andric   static_assert(std::is_pod<T>::value, "Must be a POD type.");
394824e7fdSDimitry Andric   assert(reinterpret_cast<size_t>(Buffer) % sizeof(T) == 0 &&
404824e7fdSDimitry Andric          "Unaligned read!");
41349cc55cSDimitry Andric   T t = *reinterpret_cast<T *>(Buffer);
42349cc55cSDimitry Andric   Buffer += sizeof(T);
43349cc55cSDimitry Andric   return t;
44349cc55cSDimitry Andric }
45349cc55cSDimitry Andric 
TEST(MemProf,Basic)46349cc55cSDimitry Andric TEST(MemProf, Basic) {
47*06c3fb27SDimitry Andric   __sanitizer::LoadedModule FakeModule;
48*06c3fb27SDimitry Andric   FakeModule.addAddressRange(/*begin=*/0x10, /*end=*/0x20, /*executable=*/true,
49*06c3fb27SDimitry Andric                              /*writable=*/false, /*name=*/"");
50*06c3fb27SDimitry Andric   const char uuid[MEMPROF_BUILDID_MAX_SIZE] = {0xC, 0x0, 0xF, 0xF, 0xE, 0xE};
51*06c3fb27SDimitry Andric   FakeModule.setUuid(uuid, MEMPROF_BUILDID_MAX_SIZE);
52*06c3fb27SDimitry Andric   __sanitizer::ArrayRef<__sanitizer::LoadedModule> Modules(&FakeModule,
53*06c3fb27SDimitry Andric                                                            (&FakeModule) + 1);
54349cc55cSDimitry Andric 
55349cc55cSDimitry Andric   MIBMapTy FakeMap;
56349cc55cSDimitry Andric   MemInfoBlock FakeMIB;
57349cc55cSDimitry Andric   // Since we want to override the constructor set vals to make it easier to
58349cc55cSDimitry Andric   // test.
59349cc55cSDimitry Andric   memset(&FakeMIB, 0, sizeof(MemInfoBlock));
6081ad6265SDimitry Andric   FakeMIB.AllocCount = 0x1;
6181ad6265SDimitry Andric   FakeMIB.TotalAccessCount = 0x2;
62349cc55cSDimitry Andric 
631fd87a68SDimitry Andric   uint64_t FakeIds[2];
64349cc55cSDimitry Andric   FakeIds[0] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/2, FakeMap);
65349cc55cSDimitry Andric   FakeIds[1] = PopulateFakeMap(FakeMIB, /*StackPCBegin=*/3, FakeMap);
66349cc55cSDimitry Andric 
67349cc55cSDimitry Andric   char *Ptr = nullptr;
68*06c3fb27SDimitry Andric   uint64_t NumBytes = SerializeToRawProfile(FakeMap, Modules, Ptr);
69349cc55cSDimitry Andric   const char *Buffer = Ptr;
70349cc55cSDimitry Andric 
71349cc55cSDimitry Andric   ASSERT_GT(NumBytes, 0ULL);
72349cc55cSDimitry Andric   ASSERT_TRUE(Ptr);
73349cc55cSDimitry Andric 
74349cc55cSDimitry Andric   // Check the header.
75349cc55cSDimitry Andric   EXPECT_THAT(Read(Ptr), MEMPROF_RAW_MAGIC_64);
76349cc55cSDimitry Andric   EXPECT_THAT(Read(Ptr), MEMPROF_RAW_VERSION);
771fd87a68SDimitry Andric   const uint64_t TotalSize = Read(Ptr);
781fd87a68SDimitry Andric   const uint64_t SegmentOffset = Read(Ptr);
791fd87a68SDimitry Andric   const uint64_t MIBOffset = Read(Ptr);
801fd87a68SDimitry Andric   const uint64_t StackOffset = Read(Ptr);
81349cc55cSDimitry Andric 
824824e7fdSDimitry Andric   // ============= Check sizes and padding.
83349cc55cSDimitry Andric   EXPECT_EQ(TotalSize, NumBytes);
844824e7fdSDimitry Andric   EXPECT_EQ(TotalSize % 8, 0ULL);
85349cc55cSDimitry Andric 
86349cc55cSDimitry Andric   // Should be equal to the size of the raw profile header.
87349cc55cSDimitry Andric   EXPECT_EQ(SegmentOffset, 48ULL);
88349cc55cSDimitry Andric 
89*06c3fb27SDimitry Andric   // We expect only 1 segment entry, 8b for the count and 64b for SegmentEntry
90349cc55cSDimitry Andric   // in memprof_rawprofile.cpp.
91*06c3fb27SDimitry Andric   EXPECT_EQ(MIBOffset - SegmentOffset, 72ULL);
92349cc55cSDimitry Andric 
93*06c3fb27SDimitry Andric   EXPECT_EQ(MIBOffset, 120ULL);
941fd87a68SDimitry Andric   // We expect 2 mib entry, 8b for the count and sizeof(uint64_t) +
95349cc55cSDimitry Andric   // sizeof(MemInfoBlock) contains stack id + MeminfoBlock.
96349cc55cSDimitry Andric   EXPECT_EQ(StackOffset - MIBOffset, 8 + 2 * (8 + sizeof(MemInfoBlock)));
97349cc55cSDimitry Andric 
98*06c3fb27SDimitry Andric   EXPECT_EQ(StackOffset, 408ULL);
99349cc55cSDimitry Andric   // We expect 2 stack entries, with 5 frames - 8b for total count,
1004824e7fdSDimitry Andric   // 2 * (8b for id, 8b for frame count and 5*8b for fake frames).
1014824e7fdSDimitry Andric   // Since this is the last section, there may be additional padding at the end
1024824e7fdSDimitry Andric   // to make the total profile size 8b aligned.
1034824e7fdSDimitry Andric   EXPECT_GE(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8));
104349cc55cSDimitry Andric 
105349cc55cSDimitry Andric   // ============= Check contents.
106*06c3fb27SDimitry Andric   unsigned char ExpectedSegmentBytes[72] = {
107349cc55cSDimitry Andric       0x01, 0,   0,   0,   0,   0,  0, 0, // Number of entries
108349cc55cSDimitry Andric       0x10, 0,   0,   0,   0,   0,  0, 0, // Start
109349cc55cSDimitry Andric       0x20, 0,   0,   0,   0,   0,  0, 0, // End
110*06c3fb27SDimitry Andric       0x0,  0,   0,   0,   0,   0,  0, 0, // Offset
111*06c3fb27SDimitry Andric       0x20, 0,   0,   0,   0,   0,  0, 0, // UuidSize
112*06c3fb27SDimitry Andric       0xC,  0x0, 0xF, 0xF, 0xE, 0xE       // Uuid
113349cc55cSDimitry Andric   };
114*06c3fb27SDimitry Andric   EXPECT_EQ(memcmp(Buffer + SegmentOffset, ExpectedSegmentBytes, 72), 0);
115349cc55cSDimitry Andric 
116349cc55cSDimitry Andric   // Check that the number of entries is 2.
1171fd87a68SDimitry Andric   EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + MIBOffset), 2ULL);
118349cc55cSDimitry Andric   // Check that stack id is set.
1191fd87a68SDimitry Andric   EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + MIBOffset + 8),
1201fd87a68SDimitry Andric             FakeIds[0]);
121349cc55cSDimitry Andric 
122349cc55cSDimitry Andric   // Only check a few fields of the first MemInfoBlock.
123349cc55cSDimitry Andric   unsigned char ExpectedMIBBytes[sizeof(MemInfoBlock)] = {
124349cc55cSDimitry Andric       0x01, 0, 0, 0, // Alloc count
125349cc55cSDimitry Andric       0x02, 0, 0, 0, // Total access count
126349cc55cSDimitry Andric   };
127349cc55cSDimitry Andric   // Compare contents of 1st MIB after skipping count and stack id.
128349cc55cSDimitry Andric   EXPECT_EQ(
129349cc55cSDimitry Andric       memcmp(Buffer + MIBOffset + 16, ExpectedMIBBytes, sizeof(MemInfoBlock)),
130349cc55cSDimitry Andric       0);
131349cc55cSDimitry Andric   // Compare contents of 2nd MIB after skipping count and stack id for the first
132349cc55cSDimitry Andric   // and only the id for the second.
133349cc55cSDimitry Andric   EXPECT_EQ(memcmp(Buffer + MIBOffset + 16 + sizeof(MemInfoBlock) + 8,
134349cc55cSDimitry Andric                    ExpectedMIBBytes, sizeof(MemInfoBlock)),
135349cc55cSDimitry Andric             0);
136349cc55cSDimitry Andric 
137349cc55cSDimitry Andric   // Check that the number of entries is 2.
1381fd87a68SDimitry Andric   EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + StackOffset), 2ULL);
139349cc55cSDimitry Andric   // Check that the 1st stack id is set.
1401fd87a68SDimitry Andric   EXPECT_EQ(*reinterpret_cast<const uint64_t *>(Buffer + StackOffset + 8),
141349cc55cSDimitry Andric             FakeIds[0]);
142349cc55cSDimitry Andric   // Contents are num pcs, value of each pc - 1.
143349cc55cSDimitry Andric   unsigned char ExpectedStackBytes[2][6 * 8] = {
144349cc55cSDimitry Andric       {
145349cc55cSDimitry Andric           0x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs
146349cc55cSDimitry Andric           0x1, 0, 0, 0, 0, 0, 0, 0, // PC ...
147349cc55cSDimitry Andric           0x2, 0, 0, 0, 0, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0,
148349cc55cSDimitry Andric           0x4, 0, 0, 0, 0, 0, 0, 0, 0x5, 0, 0, 0, 0, 0, 0, 0,
149349cc55cSDimitry Andric       },
150349cc55cSDimitry Andric       {
151349cc55cSDimitry Andric           0x5, 0, 0, 0, 0, 0, 0, 0, // Number of PCs
152349cc55cSDimitry Andric           0x2, 0, 0, 0, 0, 0, 0, 0, // PC ...
153349cc55cSDimitry Andric           0x3, 0, 0, 0, 0, 0, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0,
154349cc55cSDimitry Andric           0x5, 0, 0, 0, 0, 0, 0, 0, 0x6, 0, 0, 0, 0, 0, 0, 0,
155349cc55cSDimitry Andric       },
156349cc55cSDimitry Andric   };
157349cc55cSDimitry Andric   EXPECT_EQ(memcmp(Buffer + StackOffset + 16, ExpectedStackBytes[0],
158349cc55cSDimitry Andric                    sizeof(ExpectedStackBytes[0])),
159349cc55cSDimitry Andric             0);
160349cc55cSDimitry Andric 
161349cc55cSDimitry Andric   // Check that the 2nd stack id is set.
162349cc55cSDimitry Andric   EXPECT_EQ(
1631fd87a68SDimitry Andric       *reinterpret_cast<const uint64_t *>(Buffer + StackOffset + 8 + 6 * 8 + 8),
164349cc55cSDimitry Andric       FakeIds[1]);
165349cc55cSDimitry Andric 
166349cc55cSDimitry Andric   EXPECT_EQ(memcmp(Buffer + StackOffset + 16 + 6 * 8 + 8, ExpectedStackBytes[1],
167349cc55cSDimitry Andric                    sizeof(ExpectedStackBytes[1])),
168349cc55cSDimitry Andric             0);
169349cc55cSDimitry Andric }
170349cc55cSDimitry Andric } // namespace
171