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