brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.1 KiB · 80a9a96 Raw
314 lines · cpp
1#include "../CtxInstrProfiling.h"2#include "gtest/gtest.h"3#include <thread>4 5using namespace __ctx_profile;6 7class ContextTest : public ::testing::Test {8  void SetUp() override { Root.getOrAllocateContextRoot(); }9  void TearDown() override { __llvm_ctx_profile_free(); }10 11public:12  FunctionData Root;13};14 15TEST(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 24TEST(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 42TEST_F(ContextTest, Basic) {43  __llvm_ctx_profile_start_collection();44  auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4);45  ASSERT_NE(Ctx, nullptr);46  auto &CtxRoot = *Root.CtxRoot;47  EXPECT_NE(CtxRoot.CurrentMem, nullptr);48  EXPECT_EQ(CtxRoot.FirstMemBlock, CtxRoot.CurrentMem);49  EXPECT_EQ(Ctx->size(), sizeof(ContextNode) + 10 * sizeof(uint64_t) +50                             4 * sizeof(ContextNode *));51  EXPECT_EQ(Ctx->counters_size(), 10U);52  EXPECT_EQ(Ctx->callsites_size(), 4U);53  EXPECT_EQ(__llvm_ctx_profile_current_context_root, &CtxRoot);54  CtxRoot.Taken.CheckLocked();55  EXPECT_FALSE(CtxRoot.Taken.TryLock());56  __llvm_ctx_profile_release_context(&Root);57  EXPECT_EQ(__llvm_ctx_profile_current_context_root, nullptr);58  EXPECT_TRUE(CtxRoot.Taken.TryLock());59  CtxRoot.Taken.Unlock();60}61 62TEST_F(ContextTest, Callsite) {63  __llvm_ctx_profile_start_collection();64  auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4);65  int FakeCalleeAddress = 0;66  const bool IsScratch = isScratch(Ctx);67  EXPECT_FALSE(IsScratch);68  // This is the sequence the caller performs - it's the lowering of the69  // instrumentation of the callsite "2". "2" is arbitrary here.70  __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress;71  __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2];72  // This is what the callee does73  FunctionData FData;74  auto *Subctx =75      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 2, 3, 1);76  // This should not have required creating a flat context.77  EXPECT_EQ(FData.FlatCtx, nullptr);78  // We expect the subcontext to be appropriately placed and dimensioned79  EXPECT_EQ(Ctx->subContexts()[2], Subctx);80  EXPECT_EQ(Subctx->counters_size(), 3U);81  EXPECT_EQ(Subctx->callsites_size(), 1U);82  // We reset these in _get_context.83  EXPECT_EQ(__llvm_ctx_profile_expected_callee[0], nullptr);84  EXPECT_EQ(__llvm_ctx_profile_callsite[0], nullptr);85 86  EXPECT_EQ(Subctx->size(), sizeof(ContextNode) + 3 * sizeof(uint64_t) +87                                1 * sizeof(ContextNode *));88  __llvm_ctx_profile_release_context(&Root);89}90 91TEST_F(ContextTest, ScratchNoCollectionProfilingNotStarted) {92  // This test intentionally does not call __llvm_ctx_profile_start_collection.93  EXPECT_EQ(__llvm_ctx_profile_current_context_root, nullptr);94  int FakeCalleeAddress = 0;95  // this would be the very first function executing this. the TLS is empty,96  // too.97  FunctionData FData;98  auto *Ctx =99      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 2, 3, 1);100  // We never entered a context (_start_context was never called) - so the101  // returned context must be a tagged pointer.102  EXPECT_TRUE(isScratch(Ctx));103  // Because we didn't start collection, no flat profile should have been104  // allocated.105  EXPECT_EQ(FData.FlatCtx, nullptr);106}107 108TEST_F(ContextTest, ScratchNoCollectionProfilingStarted) {109  ASSERT_EQ(__llvm_ctx_profile_current_context_root, nullptr);110  int FakeCalleeAddress = 0;111  // Start collection, so the function gets a flat profile instead of scratch.112  __llvm_ctx_profile_start_collection();113  // this would be the very first function executing this. the TLS is empty,114  // too.115  FunctionData FData;116  auto *Ctx =117      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 2, 3, 1);118  // We never entered a context (_start_context was never called) - so the119  // returned context must be a tagged pointer.120  EXPECT_TRUE(isScratch(Ctx));121  // Because we never entered a context, we should have allocated a flat context122  EXPECT_NE(FData.FlatCtx, nullptr);123  EXPECT_EQ(reinterpret_cast<uintptr_t>(FData.FlatCtx) + 1,124            reinterpret_cast<uintptr_t>(Ctx));125}126 127TEST_F(ContextTest, ScratchDuringCollection) {128  __llvm_ctx_profile_start_collection();129  auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4);130  int FakeCalleeAddress = 0;131  int OtherFakeCalleeAddress = 0;132  __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress;133  __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2];134  FunctionData FData[3];135  auto *Subctx = __llvm_ctx_profile_get_context(136      &FData[0], &OtherFakeCalleeAddress, 2, 3, 1);137  // We expected a different callee - so return scratch. It mimics what happens138  // in the case of a signal handler - in this case, OtherFakeCalleeAddress is139  // the signal handler.140  EXPECT_TRUE(isScratch(Subctx));141  // We shouldn't have tried to return a flat context because we're under a142  // root.143  EXPECT_EQ(FData[0].FlatCtx, nullptr);144  EXPECT_EQ(__llvm_ctx_profile_expected_callee[0], nullptr);145  EXPECT_EQ(__llvm_ctx_profile_callsite[0], nullptr);146 147  int ThirdFakeCalleeAddress = 0;148  __llvm_ctx_profile_expected_callee[1] = &ThirdFakeCalleeAddress;149  __llvm_ctx_profile_callsite[1] = &Subctx->subContexts()[0];150 151  auto *Subctx2 = __llvm_ctx_profile_get_context(152      &FData[1], &ThirdFakeCalleeAddress, 3, 0, 0);153  // We again expect scratch because the '0' position is where the runtime154  // looks, so it doesn't matter the '1' position is populated correctly.155  EXPECT_TRUE(isScratch(Subctx2));156  EXPECT_EQ(FData[1].FlatCtx, nullptr);157 158  __llvm_ctx_profile_expected_callee[0] = &ThirdFakeCalleeAddress;159  __llvm_ctx_profile_callsite[0] = &Subctx->subContexts()[0];160  auto *Subctx3 = __llvm_ctx_profile_get_context(161      &FData[2], &ThirdFakeCalleeAddress, 3, 0, 0);162  // We expect scratch here, too, because the value placed in163  // __llvm_ctx_profile_callsite is scratch164  EXPECT_TRUE(isScratch(Subctx3));165  EXPECT_EQ(FData[2].FlatCtx, nullptr);166 167  __llvm_ctx_profile_release_context(&Root);168}169 170TEST_F(ContextTest, NeedMoreMemory) {171  __llvm_ctx_profile_start_collection();172  auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4);173  int FakeCalleeAddress = 0;174  const bool IsScratch = isScratch(Ctx);175  EXPECT_FALSE(IsScratch);176  auto &CtxRoot = *Root.CtxRoot;177  const auto *CurrentMem = CtxRoot.CurrentMem;178  __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress;179  __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2];180  FunctionData FData;181  // Allocate a massive subcontext to force new arena allocation182  auto *Subctx =183      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 3, 1 << 20, 1);184  EXPECT_EQ(FData.FlatCtx, nullptr);185  EXPECT_EQ(Ctx->subContexts()[2], Subctx);186  EXPECT_NE(CurrentMem, CtxRoot.CurrentMem);187  EXPECT_NE(CtxRoot.CurrentMem, nullptr);188}189 190TEST_F(ContextTest, ConcurrentRootCollection) {191  std::atomic<int> NonScratch = 0;192  std::atomic<int> Executions = 0;193 194  __sanitizer::Semaphore GotCtx;195 196  auto Entrypoint = [&]() {197    ++Executions;198    auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4);199    GotCtx.Post();200    const bool IS = isScratch(Ctx);201    NonScratch += (!IS);202    if (!IS) {203      GotCtx.Wait();204      GotCtx.Wait();205    }206    __llvm_ctx_profile_release_context(&Root);207  };208  std::thread T1(Entrypoint);209  std::thread T2(Entrypoint);210  T1.join();211  T2.join();212  EXPECT_EQ(NonScratch, 1);213  EXPECT_EQ(Executions, 2);214}215 216TEST_F(ContextTest, Dump) {217  auto *Ctx = __llvm_ctx_profile_start_context(&Root, 1, 10, 4);218  int FakeCalleeAddress = 0;219  __llvm_ctx_profile_expected_callee[0] = &FakeCalleeAddress;220  __llvm_ctx_profile_callsite[0] = &Ctx->subContexts()[2];221  FunctionData FData;222  auto *Subctx =223      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 2, 3, 1);224  (void)Subctx;225  __llvm_ctx_profile_release_context(&Root);226 227  class TestProfileWriter : public ProfileWriter {228  public:229    ContextRoot *const Root;230    const size_t Entries;231 232    int EnteredSectionCount = 0;233    int ExitedSectionCount = 0;234    int EnteredFlatCount = 0;235    int ExitedFlatCount = 0;236    int FlatsWritten = 0;237 238    bool State = false;239 240    TestProfileWriter(ContextRoot *Root, size_t Entries)241        : Root(Root), Entries(Entries) {}242 243    void writeContextual(const ContextNode &Node, const ContextNode *Unhandled,244                         uint64_t TotalRootEntryCount) override {245      EXPECT_EQ(TotalRootEntryCount, Entries);246      EXPECT_EQ(EnteredSectionCount, 1);247      EXPECT_EQ(ExitedSectionCount, 0);248      EXPECT_FALSE(Root->Taken.TryLock());249      EXPECT_EQ(Node.guid(), 1U);250      EXPECT_EQ(Node.counters()[0], Entries);251      EXPECT_EQ(Node.counters_size(), 10U);252      EXPECT_EQ(Node.callsites_size(), 4U);253      EXPECT_EQ(Node.subContexts()[0], nullptr);254      EXPECT_EQ(Node.subContexts()[1], nullptr);255      EXPECT_NE(Node.subContexts()[2], nullptr);256      EXPECT_EQ(Node.subContexts()[3], nullptr);257      const auto &SN = *Node.subContexts()[2];258      EXPECT_EQ(SN.guid(), 2U);259      EXPECT_EQ(SN.counters()[0], Entries);260      EXPECT_EQ(SN.counters_size(), 3U);261      EXPECT_EQ(SN.callsites_size(), 1U);262      EXPECT_EQ(SN.subContexts()[0], nullptr);263      State = true;264    }265    void startContextSection() override { ++EnteredSectionCount; }266    void endContextSection() override {267      EXPECT_EQ(EnteredSectionCount, 1);268      ++ExitedSectionCount;269    }270    void startFlatSection() override { ++EnteredFlatCount; }271    void writeFlat(GUID Guid, const uint64_t *Buffer,272                   size_t BufferSize) override {273      ++FlatsWritten;274      EXPECT_EQ(BufferSize, 3U);275      EXPECT_EQ(Buffer[0], 15U);276      EXPECT_EQ(Buffer[1], 0U);277      EXPECT_EQ(Buffer[2], 0U);278    }279    void endFlatSection() override { ++ExitedFlatCount; }280  };281 282  TestProfileWriter W(Root.CtxRoot, 1);283  EXPECT_FALSE(W.State);284  __llvm_ctx_profile_fetch(W);285  EXPECT_TRUE(W.State);286 287  // this resets all counters but not the internal structure.288  __llvm_ctx_profile_start_collection();289  auto *Flat =290      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 2, 3, 1);291  (void)Flat;292  EXPECT_NE(FData.FlatCtx, nullptr);293  FData.FlatCtx->counters()[0] = 15U;294  TestProfileWriter W2(Root.CtxRoot, 0);295  EXPECT_FALSE(W2.State);296  __llvm_ctx_profile_fetch(W2);297  EXPECT_TRUE(W2.State);298  EXPECT_EQ(W2.EnteredSectionCount, 1);299  EXPECT_EQ(W2.ExitedSectionCount, 1);300  EXPECT_EQ(W2.EnteredFlatCount, 1);301  EXPECT_EQ(W2.FlatsWritten, 1);302  EXPECT_EQ(W2.ExitedFlatCount, 1);303}304 305TEST_F(ContextTest, MustNotBeRoot) {306  FunctionData FData;307  FData.CtxRoot = reinterpret_cast<ContextRoot *>(1U);308  int FakeCalleeAddress = 0;309  __llvm_ctx_profile_start_collection();310  auto *Subctx =311      __llvm_ctx_profile_get_context(&FData, &FakeCalleeAddress, 2, 3, 1);312  EXPECT_TRUE(isScratch(Subctx));313}314