1 #include "../CtxInstrProfiling.h" 2 #include "gtest/gtest.h" 3 #include <thread> 4 5 using namespace __ctx_profile; 6 7 class ContextTest : public ::testing::Test { 8 void SetUp() override { memset(&Root, 0, sizeof(ContextRoot)); } 9 void TearDown() override { __llvm_ctx_profile_free(); } 10 11 public: 12 ContextRoot Root; 13 }; 14 15 TEST(ArenaTest, ZeroInit) { 16 char Buffer[1024]; 17 memset(Buffer, 1, 1024); 18 Arena *A = new (Buffer) Arena(10); 19 for (auto I = 0U; I < A->size(); ++I) 20 EXPECT_EQ(A->pos()[I], static_cast<char>(0)); 21 EXPECT_EQ(A->size(), 10U); 22 } 23 24 TEST(ArenaTest, Basic) { 25 Arena *A = Arena::allocateNewArena(1024); 26 EXPECT_EQ(A->size(), 1024U); 27 EXPECT_EQ(A->next(), nullptr); 28 29 auto *M1 = A->tryBumpAllocate(1020); 30 EXPECT_NE(M1, nullptr); 31 auto *M2 = A->tryBumpAllocate(4); 32 EXPECT_NE(M2, nullptr); 33 EXPECT_EQ(M1 + 1020, M2); 34 EXPECT_EQ(A->tryBumpAllocate(1), nullptr); 35 Arena *A2 = Arena::allocateNewArena(2024, A); 36 EXPECT_EQ(A->next(), A2); 37 EXPECT_EQ(A2->next(), nullptr); 38 Arena::freeArenaList(A); 39 EXPECT_EQ(A, nullptr); 40 } 41 42 TEST_F(ContextTest, Basic) { 43 auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4); 44 ASSERT_NE(Ctx, nullptr); 45 EXPECT_NE(Root.CurrentMem, nullptr); 46 EXPECT_EQ(Root.FirstMemBlock, Root.CurrentMem); 47 EXPECT_EQ(Ctx->size(), sizeof(ContextNode) + 10 * sizeof(uint64_t) + 48 4 * sizeof(ContextNode *)); 49 EXPECT_EQ(Ctx->counters_size(), 10U); 50 EXPECT_EQ(Ctx->callsites_size(), 4U); 51 EXPECT_EQ(__llvm_ctx_profile_current_context_root, &Root); 52 Root.Taken.CheckLocked(); 53 EXPECT_FALSE(Root.Taken.TryLock()); 54 __llvm_ctx_profile_release_context(&Root); 55 EXPECT_EQ(__llvm_ctx_profile_current_context_root, nullptr); 56 EXPECT_TRUE(Root.Taken.TryLock()); 57 Root.Taken.Unlock(); 58 } 59 60 TEST_F(ContextTest, Callsite) { 61 auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4); 62 int FakeCalleeAddress = 0; 63 const bool IsScratch = isScratch(Ctx); 64 EXPECT_FALSE(IsScratch); 65 // This is the sequence the caller performs - it's the lowering of the 66 // instrumentation of the callsite "2". "2" is arbitrary here. 67 __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress; 68 __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2]; 69 // This is what the callee does 70 auto *Subctx = __llvm_ctx_profile_get_context(&FakeCalleeAddress, 2, 3, 1); 71 // We expect the subcontext to be appropriately placed and dimensioned 72 EXPECT_EQ(Ctx->subContexts()[2], Subctx); 73 EXPECT_EQ(Subctx->counters_size(), 3U); 74 EXPECT_EQ(Subctx->callsites_size(), 1U); 75 // We reset these in _get_context. 76 EXPECT_EQ(__llvm_ctx_profile_expected_callee[0], nullptr); 77 EXPECT_EQ(__llvm_ctx_profile_callsite[0], nullptr); 78 79 EXPECT_EQ(Subctx->size(), sizeof(ContextNode) + 3 * sizeof(uint64_t) + 80 1 * sizeof(ContextNode *)); 81 __llvm_ctx_profile_release_context(&Root); 82 } 83 84 TEST_F(ContextTest, ScratchNoCollection) { 85 EXPECT_EQ(__llvm_ctx_profile_current_context_root, nullptr); 86 int FakeCalleeAddress = 0; 87 // this would be the very first function executing this. the TLS is empty, 88 // too. 89 auto *Ctx = __llvm_ctx_profile_get_context(&FakeCalleeAddress, 2, 3, 1); 90 // We never entered a context (_start_context was never called) - so the 91 // returned context must be scratch. 92 EXPECT_TRUE(isScratch(Ctx)); 93 } 94 95 TEST_F(ContextTest, ScratchDuringCollection) { 96 auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4); 97 int FakeCalleeAddress = 0; 98 int OtherFakeCalleeAddress = 0; 99 __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress; 100 __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2]; 101 auto *Subctx = 102 __llvm_ctx_profile_get_context(&OtherFakeCalleeAddress, 2, 3, 1); 103 // We expected a different callee - so return scratch. It mimics what happens 104 // in the case of a signal handler - in this case, OtherFakeCalleeAddress is 105 // the signal handler. 106 EXPECT_TRUE(isScratch(Subctx)); 107 EXPECT_EQ(__llvm_ctx_profile_expected_callee[0], nullptr); 108 EXPECT_EQ(__llvm_ctx_profile_callsite[0], nullptr); 109 110 int ThirdFakeCalleeAddress = 0; 111 __llvm_ctx_profile_expected_callee[1] = &ThirdFakeCalleeAddress; 112 __llvm_ctx_profile_callsite[1] = &Subctx->subContexts()[0]; 113 114 auto *Subctx2 = 115 __llvm_ctx_profile_get_context(&ThirdFakeCalleeAddress, 3, 0, 0); 116 // We again expect scratch because the '0' position is where the runtime 117 // looks, so it doesn't matter the '1' position is populated correctly. 118 EXPECT_TRUE(isScratch(Subctx2)); 119 120 __llvm_ctx_profile_expected_callee[0] = &ThirdFakeCalleeAddress; 121 __llvm_ctx_profile_callsite[0] = &Subctx->subContexts()[0]; 122 auto *Subctx3 = 123 __llvm_ctx_profile_get_context(&ThirdFakeCalleeAddress, 3, 0, 0); 124 // We expect scratch here, too, because the value placed in 125 // __llvm_ctx_profile_callsite is scratch 126 EXPECT_TRUE(isScratch(Subctx3)); 127 128 __llvm_ctx_profile_release_context(&Root); 129 } 130 131 TEST_F(ContextTest, NeedMoreMemory) { 132 auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4); 133 int FakeCalleeAddress = 0; 134 const bool IsScratch = isScratch(Ctx); 135 EXPECT_FALSE(IsScratch); 136 const auto *CurrentMem = Root.CurrentMem; 137 __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress; 138 __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2]; 139 // Allocate a massive subcontext to force new arena allocation 140 auto *Subctx = 141 __llvm_ctx_profile_get_context(&FakeCalleeAddress, 3, 1 << 20, 1); 142 EXPECT_EQ(Ctx->subContexts()[2], Subctx); 143 EXPECT_NE(CurrentMem, Root.CurrentMem); 144 EXPECT_NE(Root.CurrentMem, nullptr); 145 } 146 147 TEST_F(ContextTest, ConcurrentRootCollection) { 148 std::atomic<int> NonScratch = 0; 149 std::atomic<int> Executions = 0; 150 151 __sanitizer::Semaphore GotCtx; 152 153 auto Entrypoint = [&]() { 154 ++Executions; 155 auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4); 156 GotCtx.Post(); 157 const bool IS = isScratch(Ctx); 158 NonScratch += (!IS); 159 if (!IS) { 160 GotCtx.Wait(); 161 GotCtx.Wait(); 162 } 163 __llvm_ctx_profile_release_context(&Root); 164 }; 165 std::thread T1(Entrypoint); 166 std::thread T2(Entrypoint); 167 T1.join(); 168 T2.join(); 169 EXPECT_EQ(NonScratch, 1); 170 EXPECT_EQ(Executions, 2); 171 } 172 173 TEST_F(ContextTest, Dump) { 174 auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4); 175 int FakeCalleeAddress = 0; 176 __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress; 177 __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2]; 178 auto *Subctx = __llvm_ctx_profile_get_context(&FakeCalleeAddress, 2, 3, 1); 179 (void)Subctx; 180 __llvm_ctx_profile_release_context(&Root); 181 182 struct Writer { 183 ContextRoot *const Root; 184 const size_t Entries; 185 bool State = false; 186 Writer(ContextRoot *Root, size_t Entries) : Root(Root), Entries(Entries) {} 187 188 bool write(const ContextNode &Node) { 189 EXPECT_FALSE(Root->Taken.TryLock()); 190 EXPECT_EQ(Node.guid(), 1U); 191 EXPECT_EQ(Node.counters()[0], Entries); 192 EXPECT_EQ(Node.counters_size(), 10U); 193 EXPECT_EQ(Node.callsites_size(), 4U); 194 EXPECT_EQ(Node.subContexts()[0], nullptr); 195 EXPECT_EQ(Node.subContexts()[1], nullptr); 196 EXPECT_NE(Node.subContexts()[2], nullptr); 197 EXPECT_EQ(Node.subContexts()[3], nullptr); 198 const auto &SN = *Node.subContexts()[2]; 199 EXPECT_EQ(SN.guid(), 2U); 200 EXPECT_EQ(SN.counters()[0], Entries); 201 EXPECT_EQ(SN.counters_size(), 3U); 202 EXPECT_EQ(SN.callsites_size(), 1U); 203 EXPECT_EQ(SN.subContexts()[0], nullptr); 204 State = true; 205 return true; 206 } 207 }; 208 Writer W(&Root, 1); 209 EXPECT_FALSE(W.State); 210 __llvm_ctx_profile_fetch(&W, [](void *W, const ContextNode &Node) -> bool { 211 return reinterpret_cast<Writer *>(W)->write(Node); 212 }); 213 EXPECT_TRUE(W.State); 214 215 // this resets all counters but not the internal structure. 216 __llvm_ctx_profile_start_collection(); 217 Writer W2(&Root, 0); 218 EXPECT_FALSE(W2.State); 219 __llvm_ctx_profile_fetch(&W2, [](void *W, const ContextNode &Node) -> bool { 220 return reinterpret_cast<Writer *>(W)->write(Node); 221 }); 222 EXPECT_TRUE(W2.State); 223 } 224