1 //===- FDRRecords.cpp - Unit Tests for XRay FDR Record Loading ------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "gmock/gmock.h" 9 #include "gtest/gtest.h" 10 11 #include "llvm/XRay/BlockIndexer.h" 12 #include "llvm/XRay/BlockPrinter.h" 13 #include "llvm/XRay/BlockVerifier.h" 14 #include "llvm/XRay/FDRLogBuilder.h" 15 #include "llvm/XRay/FDRRecords.h" 16 #include "llvm/XRay/RecordPrinter.h" 17 18 namespace llvm { 19 namespace xray { 20 namespace { 21 22 using ::testing::Eq; 23 using ::testing::Not; 24 25 TEST(XRayFDRTest, BuilderAndBlockIndexer) { 26 // We recreate a single block of valid records, then ensure that we find all 27 // of them belonging in the same index. We do this for three blocks, and 28 // ensure we find the same records in the blocks we deduce. 29 auto Block0 = LogBuilder() 30 .add<BufferExtents>(100) 31 .add<NewBufferRecord>(1) 32 .add<WallclockRecord>(1, 1) 33 .add<PIDRecord>(1) 34 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1) 35 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100) 36 .add<CustomEventRecordV5>(1, 4, "XRAY") 37 .add<TypedEventRecord>(1, 4, 2, "XRAY") 38 .consume(); 39 auto Block1 = LogBuilder() 40 .add<BufferExtents>(100) 41 .add<NewBufferRecord>(1) 42 .add<WallclockRecord>(1, 2) 43 .add<PIDRecord>(1) 44 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1) 45 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100) 46 .add<CustomEventRecordV5>(1, 4, "XRAY") 47 .add<TypedEventRecord>(1, 4, 2, "XRAY") 48 .consume(); 49 auto Block2 = LogBuilder() 50 .add<BufferExtents>(100) 51 .add<NewBufferRecord>(2) 52 .add<WallclockRecord>(1, 3) 53 .add<PIDRecord>(1) 54 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1) 55 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100) 56 .add<CustomEventRecordV5>(1, 4, "XRAY") 57 .add<TypedEventRecord>(1, 4, 2, "XRAY") 58 .consume(); 59 BlockIndexer::Index Index; 60 BlockIndexer Indexer(Index); 61 for (auto B : {std::ref(Block0), std::ref(Block1), std::ref(Block2)}) { 62 for (auto &R : B.get()) 63 ASSERT_FALSE(errorToBool(R->apply(Indexer))); 64 ASSERT_FALSE(errorToBool(Indexer.flush())); 65 } 66 67 // We have two threads worth of blocks. 68 ASSERT_THAT(Index.size(), Eq(2u)); 69 auto T1Blocks = Index.find({1, 1}); 70 ASSERT_THAT(T1Blocks, Not(Eq(Index.end()))); 71 ASSERT_THAT(T1Blocks->second.size(), Eq(2u)); 72 auto T2Blocks = Index.find({1, 2}); 73 ASSERT_THAT(T2Blocks, Not(Eq(Index.end()))); 74 ASSERT_THAT(T2Blocks->second.size(), Eq(1u)); 75 } 76 77 TEST(XRayFDRTest, BuilderAndBlockVerifier) { 78 auto Block = LogBuilder() 79 .add<BufferExtents>(48) 80 .add<NewBufferRecord>(1) 81 .add<WallclockRecord>(1, 1) 82 .add<PIDRecord>(1) 83 .add<NewCPUIDRecord>(1, 2) 84 .consume(); 85 BlockVerifier Verifier; 86 for (auto &R : Block) 87 ASSERT_FALSE(errorToBool(R->apply(Verifier))); 88 ASSERT_FALSE(errorToBool(Verifier.verify())); 89 } 90 91 TEST(XRayFDRTest, IndexAndVerifyBlocks) { 92 auto Block0 = LogBuilder() 93 .add<BufferExtents>(64) 94 .add<NewBufferRecord>(1) 95 .add<WallclockRecord>(1, 1) 96 .add<PIDRecord>(1) 97 .add<NewCPUIDRecord>(1, 2) 98 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1) 99 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100) 100 .add<CustomEventRecordV5>(1, 4, "XRAY") 101 .add<TypedEventRecord>(1, 4, 2, "XRAY") 102 .consume(); 103 auto Block1 = LogBuilder() 104 .add<BufferExtents>(64) 105 .add<NewBufferRecord>(1) 106 .add<WallclockRecord>(1, 1) 107 .add<PIDRecord>(1) 108 .add<NewCPUIDRecord>(1, 2) 109 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1) 110 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100) 111 .add<CustomEventRecordV5>(1, 4, "XRAY") 112 .add<TypedEventRecord>(1, 4, 2, "XRAY") 113 .consume(); 114 auto Block2 = LogBuilder() 115 .add<BufferExtents>(64) 116 .add<NewBufferRecord>(1) 117 .add<WallclockRecord>(1, 1) 118 .add<PIDRecord>(1) 119 .add<NewCPUIDRecord>(1, 2) 120 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1) 121 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100) 122 .add<CustomEventRecordV5>(1, 4, "XRAY") 123 .add<TypedEventRecord>(1, 4, 2, "XRAY") 124 .consume(); 125 126 // First, index the records in different blocks. 127 BlockIndexer::Index Index; 128 BlockIndexer Indexer(Index); 129 for (auto B : {std::ref(Block0), std::ref(Block1), std::ref(Block2)}) { 130 for (auto &R : B.get()) 131 ASSERT_FALSE(errorToBool(R->apply(Indexer))); 132 ASSERT_FALSE(errorToBool(Indexer.flush())); 133 } 134 135 // Next, verify that each block is consistently defined. 136 BlockVerifier Verifier; 137 for (auto &ProcessThreadBlocks : Index) { 138 auto &Blocks = ProcessThreadBlocks.second; 139 for (auto &B : Blocks) { 140 for (auto *R : B.Records) 141 ASSERT_FALSE(errorToBool(R->apply(Verifier))); 142 ASSERT_FALSE(errorToBool(Verifier.verify())); 143 Verifier.reset(); 144 } 145 } 146 147 // Then set up the printing mechanisms. 148 std::string Output; 149 raw_string_ostream OS(Output); 150 RecordPrinter RP(OS); 151 BlockPrinter BP(OS, RP); 152 for (auto &ProcessThreadBlocks : Index) { 153 auto &Blocks = ProcessThreadBlocks.second; 154 for (auto &B : Blocks) { 155 for (auto *R : B.Records) 156 ASSERT_FALSE(errorToBool(R->apply(BP))); 157 BP.reset(); 158 } 159 } 160 161 EXPECT_THAT(Output, Not(Eq(""))); 162 } 163 164 } // namespace 165 } // namespace xray 166 } // namespace llvm 167