Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/ctx_profile/tests/CtxInstrProfilingTest.cpp
35269 views
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
225