blob: 03fabdf2372da9ed05807faa6a5a75b6c8f4699a [file] [log] [blame]
Dean Michael Berris65574472018-08-31 08:04:56 +00001//===- llvm/unittest/XRay/FDRProducerConsumerTest.cpp -----------*- C++ -*-===//
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//
10// Test for round-trip record writing and reading.
11//
12//===----------------------------------------------------------------------===//
13#include "llvm/Support/DataExtractor.h"
14#include "llvm/Support/raw_ostream.h"
15#include "llvm/XRay/FDRLogBuilder.h"
16#include "llvm/XRay/FDRRecordConsumer.h"
17#include "llvm/XRay/FDRRecordProducer.h"
18#include "llvm/XRay/FDRRecords.h"
19#include "llvm/XRay/FDRTraceWriter.h"
20#include "llvm/XRay/FileHeaderReader.h"
21#include "gmock/gmock.h"
22#include "gtest/gtest.h"
23#include <string>
24#include <tuple>
25
26namespace llvm {
27namespace xray {
28namespace {
29
30using ::testing::Eq;
31using ::testing::IsEmpty;
32using ::testing::Not;
Dean Michael Berris5de005f2018-11-09 06:26:48 +000033using ::testing::SizeIs;
Dean Michael Berris65574472018-08-31 08:04:56 +000034
35template <class RecordType> std::unique_ptr<Record> MakeRecord();
36
Dean Michael Berris65574472018-08-31 08:04:56 +000037template <> std::unique_ptr<Record> MakeRecord<NewBufferRecord>() {
38 return make_unique<NewBufferRecord>(1);
39}
40
41template <> std::unique_ptr<Record> MakeRecord<NewCPUIDRecord>() {
Dean Michael Berris2b5cea52018-09-11 06:36:51 +000042 return make_unique<NewCPUIDRecord>(1, 2);
Dean Michael Berris65574472018-08-31 08:04:56 +000043}
44
45template <> std::unique_ptr<Record> MakeRecord<TSCWrapRecord>() {
46 return make_unique<TSCWrapRecord>(1);
47}
48
49template <> std::unique_ptr<Record> MakeRecord<WallclockRecord>() {
50 return make_unique<WallclockRecord>(1, 2);
51}
52
53template <> std::unique_ptr<Record> MakeRecord<CustomEventRecord>() {
Dean Michael Berris3fe1b122018-11-01 00:18:52 +000054 return make_unique<CustomEventRecord>(4, 1, 2, "data");
Dean Michael Berris65574472018-08-31 08:04:56 +000055}
56
57template <> std::unique_ptr<Record> MakeRecord<CallArgRecord>() {
58 return make_unique<CallArgRecord>(1);
59}
60
61template <> std::unique_ptr<Record> MakeRecord<PIDRecord>() {
62 return make_unique<PIDRecord>(1);
63}
64
65template <> std::unique_ptr<Record> MakeRecord<FunctionRecord>() {
66 return make_unique<FunctionRecord>(RecordTypes::ENTER, 1, 2);
67}
68
Dean Michael Berris5de005f2018-11-09 06:26:48 +000069template <> std::unique_ptr<Record> MakeRecord<CustomEventRecordV5>() {
70 return make_unique<CustomEventRecordV5>(4, 1, "data");
71}
72
73template <> std::unique_ptr<Record> MakeRecord<TypedEventRecord>() {
74 return make_unique<TypedEventRecord>(4, 1, 2, "data");
75}
76
Dean Michael Berris65574472018-08-31 08:04:56 +000077template <class T> class RoundTripTest : public ::testing::Test {
78public:
79 RoundTripTest() : Data(), OS(Data) {
Dean Michael Berris5de005f2018-11-09 06:26:48 +000080 H.Version = 4;
Dean Michael Berris65574472018-08-31 08:04:56 +000081 H.Type = 1;
82 H.ConstantTSC = true;
83 H.NonstopTSC = true;
84 H.CycleFrequency = 3e9;
85
86 Writer = make_unique<FDRTraceWriter>(OS, H);
Roman Lebedevab5aae52018-08-31 08:59:15 +000087 Rec = MakeRecord<T>();
Dean Michael Berris65574472018-08-31 08:04:56 +000088 }
89
90protected:
91 std::string Data;
92 raw_string_ostream OS;
93 XRayFileHeader H;
94 std::unique_ptr<FDRTraceWriter> Writer;
Roman Lebedevab5aae52018-08-31 08:59:15 +000095 std::unique_ptr<Record> Rec;
Dean Michael Berris65574472018-08-31 08:04:56 +000096};
97
98TYPED_TEST_CASE_P(RoundTripTest);
99
Dean Michael Berris5de005f2018-11-09 06:26:48 +0000100template <class T> class RoundTripTestV5 : public ::testing::Test {
101public:
102 RoundTripTestV5() : Data(), OS(Data) {
103 H.Version = 5;
104 H.Type = 1;
105 H.ConstantTSC = true;
106 H.NonstopTSC = true;
107 H.CycleFrequency = 3e9;
108
109 Writer = make_unique<FDRTraceWriter>(OS, H);
110 Rec = MakeRecord<T>();
111 }
112
113protected:
114 std::string Data;
115 raw_string_ostream OS;
116 XRayFileHeader H;
117 std::unique_ptr<FDRTraceWriter> Writer;
118 std::unique_ptr<Record> Rec;
119};
120
121TYPED_TEST_CASE_P(RoundTripTestV5);
122
Dean Michael Berris65574472018-08-31 08:04:56 +0000123// This test ensures that the writing and reading implementations are in sync --
124// that given write(read(write(R))) == R.
125TYPED_TEST_P(RoundTripTest, RoundTripsSingleValue) {
Dean Michael Berris5de005f2018-11-09 06:26:48 +0000126 // Always write a buffer extents record which will cover the correct size of
127 // the record, for version 3 and up.
128 BufferExtents BE(200);
129 ASSERT_FALSE(errorToBool(BE.apply(*this->Writer)));
Roman Lebedevab5aae52018-08-31 08:59:15 +0000130 auto &R = this->Rec;
Dean Michael Berris65574472018-08-31 08:04:56 +0000131 ASSERT_FALSE(errorToBool(R->apply(*this->Writer)));
132 this->OS.flush();
133
Dean Michael Berrisbff6dcb2018-08-31 16:08:38 +0000134 DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8);
Dean Michael Berris65574472018-08-31 08:04:56 +0000135 uint32_t OffsetPtr = 0;
136 auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr);
137 if (!HeaderOrErr)
138 FAIL() << HeaderOrErr.takeError();
139
140 FileBasedRecordProducer P(HeaderOrErr.get(), DE, OffsetPtr);
141 std::vector<std::unique_ptr<Record>> Records;
142 LogBuilderConsumer C(Records);
143 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {
144 auto R = P.produce();
145 if (!R)
146 FAIL() << R.takeError();
147 if (auto E = C.consume(std::move(R.get())))
148 FAIL() << E;
149 }
150 ASSERT_THAT(Records, Not(IsEmpty()));
151 std::string Data2;
152 raw_string_ostream OS2(Data2);
153 FDRTraceWriter Writer2(OS2, this->H);
154 for (auto &P : Records)
155 ASSERT_FALSE(errorToBool(P->apply(Writer2)));
156 OS2.flush();
157
158 EXPECT_EQ(Data2.substr(sizeof(XRayFileHeader)),
159 this->Data.substr(sizeof(XRayFileHeader)));
Dean Michael Berris5de005f2018-11-09 06:26:48 +0000160 ASSERT_THAT(Records, SizeIs(2));
161 EXPECT_THAT(Records[1]->getRecordType(), Eq(R->getRecordType()));
Dean Michael Berris65574472018-08-31 08:04:56 +0000162}
163
164REGISTER_TYPED_TEST_CASE_P(RoundTripTest, RoundTripsSingleValue);
165
Dean Michael Berris5de005f2018-11-09 06:26:48 +0000166// We duplicate the above case for the V5 version using different types and
167// encodings.
168TYPED_TEST_P(RoundTripTestV5, RoundTripsSingleValue) {
169 BufferExtents BE(200);
170 ASSERT_FALSE(errorToBool(BE.apply(*this->Writer)));
171 auto &R = this->Rec;
172 ASSERT_FALSE(errorToBool(R->apply(*this->Writer)));
173 this->OS.flush();
174
175 DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8);
176 uint32_t OffsetPtr = 0;
177 auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr);
178 if (!HeaderOrErr)
179 FAIL() << HeaderOrErr.takeError();
180
181 FileBasedRecordProducer P(HeaderOrErr.get(), DE, OffsetPtr);
182 std::vector<std::unique_ptr<Record>> Records;
183 LogBuilderConsumer C(Records);
184 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {
185 auto R = P.produce();
186 if (!R)
187 FAIL() << R.takeError();
188 if (auto E = C.consume(std::move(R.get())))
189 FAIL() << E;
190 }
191 ASSERT_THAT(Records, Not(IsEmpty()));
192 std::string Data2;
193 raw_string_ostream OS2(Data2);
194 FDRTraceWriter Writer2(OS2, this->H);
195 for (auto &P : Records)
196 ASSERT_FALSE(errorToBool(P->apply(Writer2)));
197 OS2.flush();
198
199 EXPECT_EQ(Data2.substr(sizeof(XRayFileHeader)),
200 this->Data.substr(sizeof(XRayFileHeader)));
201 ASSERT_THAT(Records, SizeIs(2));
202 EXPECT_THAT(Records[1]->getRecordType(), Eq(R->getRecordType()));
203}
204
205REGISTER_TYPED_TEST_CASE_P(RoundTripTestV5, RoundTripsSingleValue);
206
207// These are the record types we support for v4 and below.
Dean Michael Berris65574472018-08-31 08:04:56 +0000208using RecordTypes =
Dean Michael Berris5de005f2018-11-09 06:26:48 +0000209 ::testing::Types<NewBufferRecord, NewCPUIDRecord, TSCWrapRecord,
210 WallclockRecord, CustomEventRecord, CallArgRecord,
211 PIDRecord, FunctionRecord>;
Dean Michael Berris65574472018-08-31 08:04:56 +0000212INSTANTIATE_TYPED_TEST_CASE_P(Records, RoundTripTest, RecordTypes);
213
Dean Michael Berris5de005f2018-11-09 06:26:48 +0000214// For V5, we have two new types we're supporting.
215using RecordTypesV5 =
216 ::testing::Types<NewBufferRecord, NewCPUIDRecord, TSCWrapRecord,
217 WallclockRecord, CustomEventRecordV5, TypedEventRecord,
218 CallArgRecord, PIDRecord, FunctionRecord>;
219INSTANTIATE_TYPED_TEST_CASE_P(Records, RoundTripTestV5, RecordTypesV5);
220
Dean Michael Berris65574472018-08-31 08:04:56 +0000221} // namespace
222} // namespace xray
223} // namespace llvm