1bc0d697dSNico Weber //===-- fdr_controller_test.cpp -------------------------------------------===//
2bc0d697dSNico Weber //
3bc0d697dSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bc0d697dSNico Weber // See https://llvm.org/LICENSE.txt for license information.
5bc0d697dSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bc0d697dSNico Weber //
7bc0d697dSNico Weber //===----------------------------------------------------------------------===//
8bc0d697dSNico Weber //
9bc0d697dSNico Weber // This file is a part of XRay, a function call tracing system.
10bc0d697dSNico Weber //
11bc0d697dSNico Weber //===----------------------------------------------------------------------===//
12bc0d697dSNico Weber #include <algorithm>
13bc0d697dSNico Weber #include <memory>
14bc0d697dSNico Weber #include <time.h>
15bc0d697dSNico Weber
16bc0d697dSNico Weber #include "test_helpers.h"
17bc0d697dSNico Weber #include "xray/xray_records.h"
18bc0d697dSNico Weber #include "xray_buffer_queue.h"
19bc0d697dSNico Weber #include "xray_fdr_controller.h"
20bc0d697dSNico Weber #include "xray_fdr_log_writer.h"
21bc0d697dSNico Weber #include "llvm/Support/DataExtractor.h"
22bc0d697dSNico Weber #include "llvm/Testing/Support/Error.h"
23bc0d697dSNico Weber #include "llvm/XRay/Trace.h"
24bc0d697dSNico Weber #include "llvm/XRay/XRayRecord.h"
25bc0d697dSNico Weber #include "gmock/gmock.h"
26bc0d697dSNico Weber #include "gtest/gtest.h"
27bc0d697dSNico Weber
28bc0d697dSNico Weber namespace __xray {
29bc0d697dSNico Weber namespace {
30bc0d697dSNico Weber
31bc0d697dSNico Weber using ::llvm::HasValue;
32bc0d697dSNico Weber using ::llvm::xray::testing::FuncId;
33bc0d697dSNico Weber using ::llvm::xray::testing::HasArg;
34bc0d697dSNico Weber using ::llvm::xray::testing::RecordType;
35bc0d697dSNico Weber using ::llvm::xray::testing::TSCIs;
36bc0d697dSNico Weber using ::testing::AllOf;
37bc0d697dSNico Weber using ::testing::ElementsAre;
38bc0d697dSNico Weber using ::testing::Eq;
39bc0d697dSNico Weber using ::testing::Field;
40bc0d697dSNico Weber using ::testing::Gt;
41bc0d697dSNico Weber using ::testing::IsEmpty;
42bc0d697dSNico Weber using ::testing::SizeIs;
43bc0d697dSNico Weber
44bc0d697dSNico Weber class FunctionSequenceTest : public ::testing::Test {
45bc0d697dSNico Weber protected:
46bc0d697dSNico Weber BufferQueue::Buffer B{};
47bc0d697dSNico Weber std::unique_ptr<BufferQueue> BQ;
48bc0d697dSNico Weber std::unique_ptr<FDRLogWriter> W;
49bc0d697dSNico Weber std::unique_ptr<FDRController<>> C;
50bc0d697dSNico Weber
51bc0d697dSNico Weber public:
SetUp()52bc0d697dSNico Weber void SetUp() override {
53bc0d697dSNico Weber bool Success;
54*8903433bSJonas Devlieghere BQ = std::make_unique<BufferQueue>(4096, 1, Success);
55bc0d697dSNico Weber ASSERT_TRUE(Success);
56bc0d697dSNico Weber ASSERT_EQ(BQ->getBuffer(B), BufferQueue::ErrorCode::Ok);
57*8903433bSJonas Devlieghere W = std::make_unique<FDRLogWriter>(B);
58*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 0);
59bc0d697dSNico Weber }
60bc0d697dSNico Weber };
61bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,DefaultInitFinalizeFlush)62bc0d697dSNico Weber TEST_F(FunctionSequenceTest, DefaultInitFinalizeFlush) {
63bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, 2, 3));
64bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, 2, 3));
65bc0d697dSNico Weber ASSERT_TRUE(C->flush());
66bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
67bc0d697dSNico Weber
68bc0d697dSNico Weber // Serialize the buffers then test to see we find the expected records.
69bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
70bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
71bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
72bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
73bc0d697dSNico Weber TraceOrErr,
74bc0d697dSNico Weber HasValue(ElementsAre(
75bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)),
76bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
77bc0d697dSNico Weber }
78bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,BoundaryFuncIdEncoding)79bc0d697dSNico Weber TEST_F(FunctionSequenceTest, BoundaryFuncIdEncoding) {
80bc0d697dSNico Weber // We ensure that we can write function id's that are at the boundary of the
81bc0d697dSNico Weber // acceptable function ids.
82bc0d697dSNico Weber int32_t FId = (1 << 28) - 1;
83bc0d697dSNico Weber uint64_t TSC = 2;
84bc0d697dSNico Weber uint16_t CPU = 1;
85bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(FId, TSC++, CPU));
86bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(FId, TSC++, CPU));
87bc0d697dSNico Weber ASSERT_TRUE(C->functionEnterArg(FId, TSC++, CPU, 1));
88bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(FId, TSC++, CPU));
89bc0d697dSNico Weber ASSERT_TRUE(C->flush());
90bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
91bc0d697dSNico Weber
92bc0d697dSNico Weber // Serialize the buffers then test to see we find the expected records.
93bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
94bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
95bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
96bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
97bc0d697dSNico Weber TraceOrErr,
98bc0d697dSNico Weber HasValue(ElementsAre(
99bc0d697dSNico Weber AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::ENTER)),
100bc0d697dSNico Weber AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::EXIT)),
101bc0d697dSNico Weber AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::ENTER_ARG)),
102bc0d697dSNico Weber AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::TAIL_EXIT)))));
103bc0d697dSNico Weber }
104bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,ThresholdsAreEnforced)105bc0d697dSNico Weber TEST_F(FunctionSequenceTest, ThresholdsAreEnforced) {
106*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
107bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, 2, 3));
108bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, 2, 3));
109bc0d697dSNico Weber ASSERT_TRUE(C->flush());
110bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
111bc0d697dSNico Weber
112bc0d697dSNico Weber // Serialize the buffers then test to see we find the *no* records, because
113bc0d697dSNico Weber // the function entry-exit comes under the cycle threshold.
114bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
115bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
116bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
117bc0d697dSNico Weber EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(IsEmpty()));
118bc0d697dSNico Weber }
119bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,ArgsAreHandledAndKept)120bc0d697dSNico Weber TEST_F(FunctionSequenceTest, ArgsAreHandledAndKept) {
121*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
122bc0d697dSNico Weber ASSERT_TRUE(C->functionEnterArg(1, 2, 3, 4));
123bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, 2, 3));
124bc0d697dSNico Weber ASSERT_TRUE(C->flush());
125bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
126bc0d697dSNico Weber
127bc0d697dSNico Weber // Serialize the buffers then test to see we find the function enter arg
128bc0d697dSNico Weber // record with the specified argument.
129bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
130bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
131bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
132bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
133bc0d697dSNico Weber TraceOrErr,
134bc0d697dSNico Weber HasValue(ElementsAre(
135bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER_ARG),
136bc0d697dSNico Weber HasArg(4)),
137bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
138bc0d697dSNico Weber }
139bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,PreservedCallsHaveCorrectTSC)140bc0d697dSNico Weber TEST_F(FunctionSequenceTest, PreservedCallsHaveCorrectTSC) {
141*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
142bc0d697dSNico Weber uint64_t TSC = 1;
143bc0d697dSNico Weber uint16_t CPU = 0;
144bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
145bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(2, TSC++, CPU));
146bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(2, TSC++, CPU));
147bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC += 1000, CPU));
148bc0d697dSNico Weber ASSERT_TRUE(C->flush());
149bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
150bc0d697dSNico Weber
151bc0d697dSNico Weber // Serialize the buffers then test to see if we find the remaining records,
152bc0d697dSNico Weber // because the function entry-exit comes under the cycle threshold.
153bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
154bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
155bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
156bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
157bc0d697dSNico Weber TraceOrErr,
158bc0d697dSNico Weber HasValue(ElementsAre(
159bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER),
160bc0d697dSNico Weber TSCIs(Eq(1uL))),
161bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT),
162bc0d697dSNico Weber TSCIs(Gt(1000uL))))));
163bc0d697dSNico Weber }
164bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,PreservedCallsSupportLargeDeltas)165bc0d697dSNico Weber TEST_F(FunctionSequenceTest, PreservedCallsSupportLargeDeltas) {
166*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
167bc0d697dSNico Weber uint64_t TSC = 1;
168bc0d697dSNico Weber uint16_t CPU = 0;
169bc0d697dSNico Weber const auto LargeDelta = uint64_t{std::numeric_limits<int32_t>::max()};
170bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
171bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC += LargeDelta, CPU));
172bc0d697dSNico Weber ASSERT_TRUE(C->flush());
173bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
174bc0d697dSNico Weber
175bc0d697dSNico Weber // Serialize the buffer then test to see if we find the right TSC with a large
176bc0d697dSNico Weber // delta.
177bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
178bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
179bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
180bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
181bc0d697dSNico Weber TraceOrErr,
182bc0d697dSNico Weber HasValue(ElementsAre(
183bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER),
184bc0d697dSNico Weber TSCIs(Eq(1uL))),
185bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT),
186bc0d697dSNico Weber TSCIs(Gt(LargeDelta))))));
187bc0d697dSNico Weber }
188bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,RewindingMultipleCalls)189bc0d697dSNico Weber TEST_F(FunctionSequenceTest, RewindingMultipleCalls) {
190*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
191bc0d697dSNico Weber
192bc0d697dSNico Weber // First we construct an arbitrarily deep function enter/call stack.
193bc0d697dSNico Weber // We also ensure that we are in the same CPU.
194bc0d697dSNico Weber uint64_t TSC = 1;
195bc0d697dSNico Weber uint16_t CPU = 1;
196bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
197bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(2, TSC++, CPU));
198bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(3, TSC++, CPU));
199bc0d697dSNico Weber
200bc0d697dSNico Weber // Then we exit them one at a time, in reverse order of entry.
201bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(3, TSC++, CPU));
202bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(2, TSC++, CPU));
203bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
204bc0d697dSNico Weber
205bc0d697dSNico Weber ASSERT_TRUE(C->flush());
206bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
207bc0d697dSNico Weber
208bc0d697dSNico Weber // Serialize the buffers then test to see we find that all the calls have been
209bc0d697dSNico Weber // unwound because all of them are under the cycle counter threshold.
210bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
211bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
212bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
213bc0d697dSNico Weber EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(IsEmpty()));
214bc0d697dSNico Weber }
215bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,RewindingIntermediaryTailExits)216bc0d697dSNico Weber TEST_F(FunctionSequenceTest, RewindingIntermediaryTailExits) {
217*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
218bc0d697dSNico Weber
219bc0d697dSNico Weber // First we construct an arbitrarily deep function enter/call stack.
220bc0d697dSNico Weber // We also ensure that we are in the same CPU.
221bc0d697dSNico Weber uint64_t TSC = 1;
222bc0d697dSNico Weber uint16_t CPU = 1;
223bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
224bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(2, TSC++, CPU));
225bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(3, TSC++, CPU));
226bc0d697dSNico Weber
227bc0d697dSNico Weber // Next we tail-exit into a new function multiple times.
228bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(3, TSC++, CPU));
229bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(4, TSC++, CPU));
230bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(4, TSC++, CPU));
231bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(5, TSC++, CPU));
232bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(5, TSC++, CPU));
233bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(6, TSC++, CPU));
234bc0d697dSNico Weber
235bc0d697dSNico Weber // Then we exit them one at a time, in reverse order of entry.
236bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(6, TSC++, CPU));
237bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(2, TSC++, CPU));
238bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
239bc0d697dSNico Weber ASSERT_TRUE(C->flush());
240bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
241bc0d697dSNico Weber
242bc0d697dSNico Weber // Serialize the buffers then test to see we find that all the calls have been
243bc0d697dSNico Weber // unwound because all of them are under the cycle counter threshold.
244bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
245bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
246bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
247bc0d697dSNico Weber EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(IsEmpty()));
248bc0d697dSNico Weber }
249bc0d697dSNico Weber
TEST_F(FunctionSequenceTest,RewindingAfterMigration)250bc0d697dSNico Weber TEST_F(FunctionSequenceTest, RewindingAfterMigration) {
251*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
252bc0d697dSNico Weber
253bc0d697dSNico Weber // First we construct an arbitrarily deep function enter/call stack.
254bc0d697dSNico Weber // We also ensure that we are in the same CPU.
255bc0d697dSNico Weber uint64_t TSC = 1;
256bc0d697dSNico Weber uint16_t CPU = 1;
257bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
258bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(2, TSC++, CPU));
259bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(3, TSC++, CPU));
260bc0d697dSNico Weber
261bc0d697dSNico Weber // Next we tail-exit into a new function multiple times.
262bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(3, TSC++, CPU));
263bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(4, TSC++, CPU));
264bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(4, TSC++, CPU));
265bc0d697dSNico Weber
266bc0d697dSNico Weber // But before we enter the next function, we migrate to a different CPU.
267bc0d697dSNico Weber CPU = 2;
268bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(5, TSC++, CPU));
269bc0d697dSNico Weber ASSERT_TRUE(C->functionTailExit(5, TSC++, CPU));
270bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(6, TSC++, CPU));
271bc0d697dSNico Weber
272bc0d697dSNico Weber // Then we exit them one at a time, in reverse order of entry.
273bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(6, TSC++, CPU));
274bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(2, TSC++, CPU));
275bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
276bc0d697dSNico Weber
277bc0d697dSNico Weber ASSERT_TRUE(C->flush());
278bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
279bc0d697dSNico Weber
280bc0d697dSNico Weber // Serialize buffers then test that we can find all the events that span the
281bc0d697dSNico Weber // CPU migration.
282bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
283bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
284bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
285bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
286bc0d697dSNico Weber TraceOrErr,
287bc0d697dSNico Weber HasValue(ElementsAre(
288bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)),
289bc0d697dSNico Weber AllOf(FuncId(2), RecordType(llvm::xray::RecordTypes::ENTER)),
290bc0d697dSNico Weber AllOf(FuncId(2), RecordType(llvm::xray::RecordTypes::EXIT)),
291bc0d697dSNico Weber AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
292bc0d697dSNico Weber }
293bc0d697dSNico Weber
294bc0d697dSNico Weber class BufferManagementTest : public ::testing::Test {
295bc0d697dSNico Weber protected:
296bc0d697dSNico Weber BufferQueue::Buffer B{};
297bc0d697dSNico Weber std::unique_ptr<BufferQueue> BQ;
298bc0d697dSNico Weber std::unique_ptr<FDRLogWriter> W;
299bc0d697dSNico Weber std::unique_ptr<FDRController<>> C;
300bc0d697dSNico Weber
301bc0d697dSNico Weber static constexpr size_t kBuffers = 10;
302bc0d697dSNico Weber
303bc0d697dSNico Weber public:
SetUp()304bc0d697dSNico Weber void SetUp() override {
305bc0d697dSNico Weber bool Success;
306*8903433bSJonas Devlieghere BQ = std::make_unique<BufferQueue>(sizeof(MetadataRecord) * 5 +
307bc0d697dSNico Weber sizeof(FunctionRecord) * 2,
308bc0d697dSNico Weber kBuffers, Success);
309bc0d697dSNico Weber ASSERT_TRUE(Success);
310bc0d697dSNico Weber ASSERT_EQ(BQ->getBuffer(B), BufferQueue::ErrorCode::Ok);
311*8903433bSJonas Devlieghere W = std::make_unique<FDRLogWriter>(B);
312*8903433bSJonas Devlieghere C = std::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 0);
313bc0d697dSNico Weber }
314bc0d697dSNico Weber };
315bc0d697dSNico Weber
316bc0d697dSNico Weber constexpr size_t BufferManagementTest::kBuffers;
317bc0d697dSNico Weber
TEST_F(BufferManagementTest,HandlesOverflow)318bc0d697dSNico Weber TEST_F(BufferManagementTest, HandlesOverflow) {
319bc0d697dSNico Weber uint64_t TSC = 1;
320bc0d697dSNico Weber uint16_t CPU = 1;
321bc0d697dSNico Weber for (size_t I = 0; I < kBuffers + 1; ++I) {
322bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
323bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
324bc0d697dSNico Weber }
325bc0d697dSNico Weber ASSERT_TRUE(C->flush());
326bc0d697dSNico Weber ASSERT_THAT(BQ->finalize(), Eq(BufferQueue::ErrorCode::Ok));
327bc0d697dSNico Weber
328bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
329bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
330bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
331bc0d697dSNico Weber EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(SizeIs(kBuffers * 2)));
332bc0d697dSNico Weber }
333bc0d697dSNico Weber
TEST_F(BufferManagementTest,HandlesOverflowWithArgs)334bc0d697dSNico Weber TEST_F(BufferManagementTest, HandlesOverflowWithArgs) {
335bc0d697dSNico Weber uint64_t TSC = 1;
336bc0d697dSNico Weber uint16_t CPU = 1;
337bc0d697dSNico Weber uint64_t ARG = 1;
338bc0d697dSNico Weber for (size_t I = 0; I < kBuffers + 1; ++I) {
339bc0d697dSNico Weber ASSERT_TRUE(C->functionEnterArg(1, TSC++, CPU, ARG++));
340bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
341bc0d697dSNico Weber }
342bc0d697dSNico Weber ASSERT_TRUE(C->flush());
343bc0d697dSNico Weber ASSERT_THAT(BQ->finalize(), Eq(BufferQueue::ErrorCode::Ok));
344bc0d697dSNico Weber
345bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
346bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
347bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
348bc0d697dSNico Weber EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(SizeIs(kBuffers)));
349bc0d697dSNico Weber }
350bc0d697dSNico Weber
TEST_F(BufferManagementTest,HandlesOverflowWithCustomEvents)351bc0d697dSNico Weber TEST_F(BufferManagementTest, HandlesOverflowWithCustomEvents) {
352bc0d697dSNico Weber uint64_t TSC = 1;
353bc0d697dSNico Weber uint16_t CPU = 1;
354bc0d697dSNico Weber int32_t D = 0x9009;
355bc0d697dSNico Weber for (size_t I = 0; I < kBuffers; ++I) {
356bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
357bc0d697dSNico Weber ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
358bc0d697dSNico Weber ASSERT_TRUE(C->customEvent(TSC++, CPU, &D, sizeof(D)));
359bc0d697dSNico Weber }
360bc0d697dSNico Weber ASSERT_TRUE(C->flush());
361bc0d697dSNico Weber ASSERT_THAT(BQ->finalize(), Eq(BufferQueue::ErrorCode::Ok));
362bc0d697dSNico Weber
363bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
364bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
365bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
366bc0d697dSNico Weber
367bc0d697dSNico Weber // We expect to also now count the kBuffers/2 custom event records showing up
368bc0d697dSNico Weber // in the Trace.
369bc0d697dSNico Weber EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(SizeIs(kBuffers + (kBuffers / 2))));
370bc0d697dSNico Weber }
371bc0d697dSNico Weber
TEST_F(BufferManagementTest,HandlesFinalizedBufferQueue)372bc0d697dSNico Weber TEST_F(BufferManagementTest, HandlesFinalizedBufferQueue) {
373bc0d697dSNico Weber uint64_t TSC = 1;
374bc0d697dSNico Weber uint16_t CPU = 1;
375bc0d697dSNico Weber
376bc0d697dSNico Weber // First write one function entry.
377bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
378bc0d697dSNico Weber
379bc0d697dSNico Weber // Then we finalize the buffer queue, simulating the case where the logging
380bc0d697dSNico Weber // has been finalized.
381bc0d697dSNico Weber ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
382bc0d697dSNico Weber
383bc0d697dSNico Weber // At this point further calls to the controller must fail.
384bc0d697dSNico Weber ASSERT_FALSE(C->functionExit(1, TSC++, CPU));
385bc0d697dSNico Weber
386bc0d697dSNico Weber // But flushing should succeed.
387bc0d697dSNico Weber ASSERT_TRUE(C->flush());
388bc0d697dSNico Weber
389bc0d697dSNico Weber // We expect that we'll only be able to find the function enter event, but not
390bc0d697dSNico Weber // the function exit event.
391bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
392bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
393bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
394bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
395bc0d697dSNico Weber TraceOrErr, HasValue(ElementsAre(AllOf(
396bc0d697dSNico Weber FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)))));
397bc0d697dSNico Weber }
398bc0d697dSNico Weber
TEST_F(BufferManagementTest,HandlesGenerationalBufferQueue)399bc0d697dSNico Weber TEST_F(BufferManagementTest, HandlesGenerationalBufferQueue) {
400bc0d697dSNico Weber uint64_t TSC = 1;
401bc0d697dSNico Weber uint16_t CPU = 1;
402bc0d697dSNico Weber
403bc0d697dSNico Weber ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
404bc0d697dSNico Weber ASSERT_THAT(BQ->finalize(), Eq(BufferQueue::ErrorCode::Ok));
405bc0d697dSNico Weber ASSERT_THAT(BQ->init(sizeof(MetadataRecord) * 4 + sizeof(FunctionRecord) * 2,
406bc0d697dSNico Weber kBuffers),
407bc0d697dSNico Weber Eq(BufferQueue::ErrorCode::Ok));
408bc0d697dSNico Weber EXPECT_TRUE(C->functionExit(1, TSC++, CPU));
409bc0d697dSNico Weber ASSERT_TRUE(C->flush());
410bc0d697dSNico Weber
411bc0d697dSNico Weber // We expect that we will only be able to find the function exit event, but
412bc0d697dSNico Weber // not the function enter event, since we only have information about the new
413bc0d697dSNico Weber // generation of the buffers.
414bc0d697dSNico Weber std::string Serialized = serialize(*BQ, 3);
415bc0d697dSNico Weber llvm::DataExtractor DE(Serialized, true, 8);
416bc0d697dSNico Weber auto TraceOrErr = llvm::xray::loadTrace(DE);
417bc0d697dSNico Weber EXPECT_THAT_EXPECTED(
418bc0d697dSNico Weber TraceOrErr, HasValue(ElementsAre(AllOf(
419bc0d697dSNico Weber FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
420bc0d697dSNico Weber }
421bc0d697dSNico Weber
422bc0d697dSNico Weber } // namespace
423bc0d697dSNico Weber } // namespace __xray
424