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