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 
TEST(XRayFDRTest,BuilderAndBlockIndexer)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 
TEST(XRayFDRTest,BuilderAndBlockVerifier)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 
TEST(XRayFDRTest,IndexAndVerifyBlocks)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   OS.flush();
162   EXPECT_THAT(Output, Not(Eq("")));
163 }
164 
165 } // namespace
166 } // namespace xray
167 } // namespace llvm
168