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>(A: 100) |
31 | .add<NewBufferRecord>(A: 1) |
32 | .add<WallclockRecord>(A: 1, A: 1) |
33 | .add<PIDRecord>(A: 1) |
34 | .add<FunctionRecord>(A: RecordTypes::ENTER, A: 1, A: 1) |
35 | .add<FunctionRecord>(A: RecordTypes::EXIT, A: 1, A: 100) |
36 | .add<CustomEventRecordV5>(A: 1, A: 4, A: "XRAY" ) |
37 | .add<TypedEventRecord>(A: 1, A: 4, A: 2, A: "XRAY" ) |
38 | .consume(); |
39 | auto Block1 = LogBuilder() |
40 | .add<BufferExtents>(A: 100) |
41 | .add<NewBufferRecord>(A: 1) |
42 | .add<WallclockRecord>(A: 1, A: 2) |
43 | .add<PIDRecord>(A: 1) |
44 | .add<FunctionRecord>(A: RecordTypes::ENTER, A: 1, A: 1) |
45 | .add<FunctionRecord>(A: RecordTypes::EXIT, A: 1, A: 100) |
46 | .add<CustomEventRecordV5>(A: 1, A: 4, A: "XRAY" ) |
47 | .add<TypedEventRecord>(A: 1, A: 4, A: 2, A: "XRAY" ) |
48 | .consume(); |
49 | auto Block2 = LogBuilder() |
50 | .add<BufferExtents>(A: 100) |
51 | .add<NewBufferRecord>(A: 2) |
52 | .add<WallclockRecord>(A: 1, A: 3) |
53 | .add<PIDRecord>(A: 1) |
54 | .add<FunctionRecord>(A: RecordTypes::ENTER, A: 1, A: 1) |
55 | .add<FunctionRecord>(A: RecordTypes::EXIT, A: 1, A: 100) |
56 | .add<CustomEventRecordV5>(A: 1, A: 4, A: "XRAY" ) |
57 | .add<TypedEventRecord>(A: 1, A: 4, A: 2, A: "XRAY" ) |
58 | .consume(); |
59 | BlockIndexer::Index Index; |
60 | BlockIndexer Indexer(Index); |
61 | for (auto B : {std::ref(t&: Block0), std::ref(t&: Block1), std::ref(t&: 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(Val: {1, 1}); |
70 | ASSERT_THAT(T1Blocks, Not(Eq(Index.end()))); |
71 | ASSERT_THAT(T1Blocks->second.size(), Eq(2u)); |
72 | auto T2Blocks = Index.find(Val: {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>(A: 48) |
80 | .add<NewBufferRecord>(A: 1) |
81 | .add<WallclockRecord>(A: 1, A: 1) |
82 | .add<PIDRecord>(A: 1) |
83 | .add<NewCPUIDRecord>(A: 1, A: 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>(A: 64) |
94 | .add<NewBufferRecord>(A: 1) |
95 | .add<WallclockRecord>(A: 1, A: 1) |
96 | .add<PIDRecord>(A: 1) |
97 | .add<NewCPUIDRecord>(A: 1, A: 2) |
98 | .add<FunctionRecord>(A: RecordTypes::ENTER, A: 1, A: 1) |
99 | .add<FunctionRecord>(A: RecordTypes::EXIT, A: 1, A: 100) |
100 | .add<CustomEventRecordV5>(A: 1, A: 4, A: "XRAY" ) |
101 | .add<TypedEventRecord>(A: 1, A: 4, A: 2, A: "XRAY" ) |
102 | .consume(); |
103 | auto Block1 = LogBuilder() |
104 | .add<BufferExtents>(A: 64) |
105 | .add<NewBufferRecord>(A: 1) |
106 | .add<WallclockRecord>(A: 1, A: 1) |
107 | .add<PIDRecord>(A: 1) |
108 | .add<NewCPUIDRecord>(A: 1, A: 2) |
109 | .add<FunctionRecord>(A: RecordTypes::ENTER, A: 1, A: 1) |
110 | .add<FunctionRecord>(A: RecordTypes::EXIT, A: 1, A: 100) |
111 | .add<CustomEventRecordV5>(A: 1, A: 4, A: "XRAY" ) |
112 | .add<TypedEventRecord>(A: 1, A: 4, A: 2, A: "XRAY" ) |
113 | .consume(); |
114 | auto Block2 = LogBuilder() |
115 | .add<BufferExtents>(A: 64) |
116 | .add<NewBufferRecord>(A: 1) |
117 | .add<WallclockRecord>(A: 1, A: 1) |
118 | .add<PIDRecord>(A: 1) |
119 | .add<NewCPUIDRecord>(A: 1, A: 2) |
120 | .add<FunctionRecord>(A: RecordTypes::ENTER, A: 1, A: 1) |
121 | .add<FunctionRecord>(A: RecordTypes::EXIT, A: 1, A: 100) |
122 | .add<CustomEventRecordV5>(A: 1, A: 4, A: "XRAY" ) |
123 | .add<TypedEventRecord>(A: 1, A: 4, A: 2, A: "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(t&: Block0), std::ref(t&: Block1), std::ref(t&: 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 | |