blob: bbc15be03027816baeb83d3cea8204ce1a493474 [file] [log] [blame]
Dean Michael Berris146d57912018-08-31 08:04:56 +00001//===- llvm/unittest/XRay/FDRProducerConsumerTest.cpp -----------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dean Michael Berris146d57912018-08-31 08:04:56 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Test for round-trip record writing and reading.
10//
11//===----------------------------------------------------------------------===//
12#include "llvm/Support/DataExtractor.h"
13#include "llvm/Support/raw_ostream.h"
14#include "llvm/XRay/FDRLogBuilder.h"
15#include "llvm/XRay/FDRRecordConsumer.h"
16#include "llvm/XRay/FDRRecordProducer.h"
17#include "llvm/XRay/FDRRecords.h"
18#include "llvm/XRay/FDRTraceWriter.h"
19#include "llvm/XRay/FileHeaderReader.h"
20#include "gmock/gmock.h"
21#include "gtest/gtest.h"
22#include <string>
23#include <tuple>
24
25namespace llvm {
26namespace xray {
27namespace {
28
29using ::testing::Eq;
30using ::testing::IsEmpty;
31using ::testing::Not;
Dean Michael Berrisda375a62018-11-09 06:26:48 +000032using ::testing::SizeIs;
Dean Michael Berris146d57912018-08-31 08:04:56 +000033
34template <class RecordType> std::unique_ptr<Record> MakeRecord();
35
Dean Michael Berris146d57912018-08-31 08:04:56 +000036template <> std::unique_ptr<Record> MakeRecord<NewBufferRecord>() {
37 return make_unique<NewBufferRecord>(1);
38}
39
40template <> std::unique_ptr<Record> MakeRecord<NewCPUIDRecord>() {
Dean Michael Berrisd2c50402018-09-11 06:36:51 +000041 return make_unique<NewCPUIDRecord>(1, 2);
Dean Michael Berris146d57912018-08-31 08:04:56 +000042}
43
44template <> std::unique_ptr<Record> MakeRecord<TSCWrapRecord>() {
45 return make_unique<TSCWrapRecord>(1);
46}
47
48template <> std::unique_ptr<Record> MakeRecord<WallclockRecord>() {
49 return make_unique<WallclockRecord>(1, 2);
50}
51
52template <> std::unique_ptr<Record> MakeRecord<CustomEventRecord>() {
Dean Michael Berris6b67ff02018-11-01 00:18:52 +000053 return make_unique<CustomEventRecord>(4, 1, 2, "data");
Dean Michael Berris146d57912018-08-31 08:04:56 +000054}
55
56template <> std::unique_ptr<Record> MakeRecord<CallArgRecord>() {
57 return make_unique<CallArgRecord>(1);
58}
59
60template <> std::unique_ptr<Record> MakeRecord<PIDRecord>() {
61 return make_unique<PIDRecord>(1);
62}
63
64template <> std::unique_ptr<Record> MakeRecord<FunctionRecord>() {
65 return make_unique<FunctionRecord>(RecordTypes::ENTER, 1, 2);
66}
67
Dean Michael Berrisda375a62018-11-09 06:26:48 +000068template <> std::unique_ptr<Record> MakeRecord<CustomEventRecordV5>() {
69 return make_unique<CustomEventRecordV5>(4, 1, "data");
70}
71
72template <> std::unique_ptr<Record> MakeRecord<TypedEventRecord>() {
73 return make_unique<TypedEventRecord>(4, 1, 2, "data");
74}
75
Dean Michael Berris146d57912018-08-31 08:04:56 +000076template <class T> class RoundTripTest : public ::testing::Test {
77public:
78 RoundTripTest() : Data(), OS(Data) {
Dean Michael Berrisda375a62018-11-09 06:26:48 +000079 H.Version = 4;
Dean Michael Berris146d57912018-08-31 08:04:56 +000080 H.Type = 1;
81 H.ConstantTSC = true;
82 H.NonstopTSC = true;
83 H.CycleFrequency = 3e9;
84
85 Writer = make_unique<FDRTraceWriter>(OS, H);
Roman Lebedeva8c22c02018-08-31 08:59:15 +000086 Rec = MakeRecord<T>();
Dean Michael Berris146d57912018-08-31 08:04:56 +000087 }
88
89protected:
90 std::string Data;
91 raw_string_ostream OS;
92 XRayFileHeader H;
93 std::unique_ptr<FDRTraceWriter> Writer;
Roman Lebedeva8c22c02018-08-31 08:59:15 +000094 std::unique_ptr<Record> Rec;
Dean Michael Berris146d57912018-08-31 08:04:56 +000095};
96
97TYPED_TEST_CASE_P(RoundTripTest);
98
Dean Michael Berrisda375a62018-11-09 06:26:48 +000099template <class T> class RoundTripTestV5 : public ::testing::Test {
100public:
101 RoundTripTestV5() : Data(), OS(Data) {
102 H.Version = 5;
103 H.Type = 1;
104 H.ConstantTSC = true;
105 H.NonstopTSC = true;
106 H.CycleFrequency = 3e9;
107
108 Writer = make_unique<FDRTraceWriter>(OS, H);
109 Rec = MakeRecord<T>();
110 }
111
112protected:
113 std::string Data;
114 raw_string_ostream OS;
115 XRayFileHeader H;
116 std::unique_ptr<FDRTraceWriter> Writer;
117 std::unique_ptr<Record> Rec;
118};
119
120TYPED_TEST_CASE_P(RoundTripTestV5);
121
Dean Michael Berris146d57912018-08-31 08:04:56 +0000122// This test ensures that the writing and reading implementations are in sync --
123// that given write(read(write(R))) == R.
124TYPED_TEST_P(RoundTripTest, RoundTripsSingleValue) {
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000125 // Always write a buffer extents record which will cover the correct size of
126 // the record, for version 3 and up.
127 BufferExtents BE(200);
128 ASSERT_FALSE(errorToBool(BE.apply(*this->Writer)));
Roman Lebedeva8c22c02018-08-31 08:59:15 +0000129 auto &R = this->Rec;
Dean Michael Berris146d57912018-08-31 08:04:56 +0000130 ASSERT_FALSE(errorToBool(R->apply(*this->Writer)));
131 this->OS.flush();
132
Dean Michael Berris98717972018-08-31 16:08:38 +0000133 DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8);
Dean Michael Berris146d57912018-08-31 08:04:56 +0000134 uint32_t OffsetPtr = 0;
135 auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr);
136 if (!HeaderOrErr)
137 FAIL() << HeaderOrErr.takeError();
138
139 FileBasedRecordProducer P(HeaderOrErr.get(), DE, OffsetPtr);
140 std::vector<std::unique_ptr<Record>> Records;
141 LogBuilderConsumer C(Records);
142 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {
143 auto R = P.produce();
144 if (!R)
145 FAIL() << R.takeError();
146 if (auto E = C.consume(std::move(R.get())))
147 FAIL() << E;
148 }
149 ASSERT_THAT(Records, Not(IsEmpty()));
150 std::string Data2;
151 raw_string_ostream OS2(Data2);
152 FDRTraceWriter Writer2(OS2, this->H);
153 for (auto &P : Records)
154 ASSERT_FALSE(errorToBool(P->apply(Writer2)));
155 OS2.flush();
156
157 EXPECT_EQ(Data2.substr(sizeof(XRayFileHeader)),
158 this->Data.substr(sizeof(XRayFileHeader)));
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000159 ASSERT_THAT(Records, SizeIs(2));
160 EXPECT_THAT(Records[1]->getRecordType(), Eq(R->getRecordType()));
Dean Michael Berris146d57912018-08-31 08:04:56 +0000161}
162
163REGISTER_TYPED_TEST_CASE_P(RoundTripTest, RoundTripsSingleValue);
164
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000165// We duplicate the above case for the V5 version using different types and
166// encodings.
167TYPED_TEST_P(RoundTripTestV5, RoundTripsSingleValue) {
168 BufferExtents BE(200);
169 ASSERT_FALSE(errorToBool(BE.apply(*this->Writer)));
170 auto &R = this->Rec;
171 ASSERT_FALSE(errorToBool(R->apply(*this->Writer)));
172 this->OS.flush();
173
174 DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8);
175 uint32_t OffsetPtr = 0;
176 auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr);
177 if (!HeaderOrErr)
178 FAIL() << HeaderOrErr.takeError();
179
180 FileBasedRecordProducer P(HeaderOrErr.get(), DE, OffsetPtr);
181 std::vector<std::unique_ptr<Record>> Records;
182 LogBuilderConsumer C(Records);
183 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {
184 auto R = P.produce();
185 if (!R)
186 FAIL() << R.takeError();
187 if (auto E = C.consume(std::move(R.get())))
188 FAIL() << E;
189 }
190 ASSERT_THAT(Records, Not(IsEmpty()));
191 std::string Data2;
192 raw_string_ostream OS2(Data2);
193 FDRTraceWriter Writer2(OS2, this->H);
194 for (auto &P : Records)
195 ASSERT_FALSE(errorToBool(P->apply(Writer2)));
196 OS2.flush();
197
198 EXPECT_EQ(Data2.substr(sizeof(XRayFileHeader)),
199 this->Data.substr(sizeof(XRayFileHeader)));
200 ASSERT_THAT(Records, SizeIs(2));
201 EXPECT_THAT(Records[1]->getRecordType(), Eq(R->getRecordType()));
202}
203
204REGISTER_TYPED_TEST_CASE_P(RoundTripTestV5, RoundTripsSingleValue);
205
206// These are the record types we support for v4 and below.
Dean Michael Berris146d57912018-08-31 08:04:56 +0000207using RecordTypes =
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000208 ::testing::Types<NewBufferRecord, NewCPUIDRecord, TSCWrapRecord,
209 WallclockRecord, CustomEventRecord, CallArgRecord,
210 PIDRecord, FunctionRecord>;
Dean Michael Berris146d57912018-08-31 08:04:56 +0000211INSTANTIATE_TYPED_TEST_CASE_P(Records, RoundTripTest, RecordTypes);
212
Dean Michael Berrisda375a62018-11-09 06:26:48 +0000213// For V5, we have two new types we're supporting.
214using RecordTypesV5 =
215 ::testing::Types<NewBufferRecord, NewCPUIDRecord, TSCWrapRecord,
216 WallclockRecord, CustomEventRecordV5, TypedEventRecord,
217 CallArgRecord, PIDRecord, FunctionRecord>;
218INSTANTIATE_TYPED_TEST_CASE_P(Records, RoundTripTestV5, RecordTypesV5);
219
Dean Michael Berris146d57912018-08-31 08:04:56 +0000220} // namespace
221} // namespace xray
222} // namespace llvm