218 lines · cpp
1//===- llvm/unittest/XRay/FDRProducerConsumerTest.cpp -----------*- C++ -*-===//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-exception6//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 24namespace llvm {25namespace xray {26namespace {27 28using ::testing::Eq;29using ::testing::IsEmpty;30using ::testing::Not;31using ::testing::SizeIs;32 33template <class RecordType> std::unique_ptr<Record> MakeRecord();34 35template <> std::unique_ptr<Record> MakeRecord<NewBufferRecord>() {36 return std::make_unique<NewBufferRecord>(1);37}38 39template <> std::unique_ptr<Record> MakeRecord<NewCPUIDRecord>() {40 return std::make_unique<NewCPUIDRecord>(1, 2);41}42 43template <> std::unique_ptr<Record> MakeRecord<TSCWrapRecord>() {44 return std::make_unique<TSCWrapRecord>(1);45}46 47template <> std::unique_ptr<Record> MakeRecord<WallclockRecord>() {48 return std::make_unique<WallclockRecord>(1, 2);49}50 51template <> std::unique_ptr<Record> MakeRecord<CustomEventRecord>() {52 return std::make_unique<CustomEventRecord>(4, 1, 2, "data");53}54 55template <> std::unique_ptr<Record> MakeRecord<CallArgRecord>() {56 return std::make_unique<CallArgRecord>(1);57}58 59template <> std::unique_ptr<Record> MakeRecord<PIDRecord>() {60 return std::make_unique<PIDRecord>(1);61}62 63template <> std::unique_ptr<Record> MakeRecord<FunctionRecord>() {64 return std::make_unique<FunctionRecord>(RecordTypes::ENTER, 1, 2);65}66 67template <> std::unique_ptr<Record> MakeRecord<CustomEventRecordV5>() {68 return std::make_unique<CustomEventRecordV5>(4, 1, "data");69}70 71template <> std::unique_ptr<Record> MakeRecord<TypedEventRecord>() {72 return std::make_unique<TypedEventRecord>(4, 1, 2, "data");73}74 75template <class T> class RoundTripTest : public ::testing::Test {76public:77 RoundTripTest() : Data(), OS(Data) {78 H.Version = 4;79 H.Type = 1;80 H.ConstantTSC = true;81 H.NonstopTSC = true;82 H.CycleFrequency = 3e9;83 84 Writer = std::make_unique<FDRTraceWriter>(OS, H);85 Rec = MakeRecord<T>();86 }87 88protected:89 std::string Data;90 raw_string_ostream OS;91 XRayFileHeader H;92 std::unique_ptr<FDRTraceWriter> Writer;93 std::unique_ptr<Record> Rec;94};95 96TYPED_TEST_SUITE_P(RoundTripTest);97 98template <class T> class RoundTripTestV5 : public ::testing::Test {99public:100 RoundTripTestV5() : Data(), OS(Data) {101 H.Version = 5;102 H.Type = 1;103 H.ConstantTSC = true;104 H.NonstopTSC = true;105 H.CycleFrequency = 3e9;106 107 Writer = std::make_unique<FDRTraceWriter>(OS, H);108 Rec = MakeRecord<T>();109 }110 111protected:112 std::string Data;113 raw_string_ostream OS;114 XRayFileHeader H;115 std::unique_ptr<FDRTraceWriter> Writer;116 std::unique_ptr<Record> Rec;117};118 119TYPED_TEST_SUITE_P(RoundTripTestV5);120 121// This test ensures that the writing and reading implementations are in sync --122// that given write(read(write(R))) == R.123TYPED_TEST_P(RoundTripTest, RoundTripsSingleValue) {124 // Always write a buffer extents record which will cover the correct size of125 // the record, for version 3 and up.126 BufferExtents BE(200);127 ASSERT_FALSE(errorToBool(BE.apply(*this->Writer)));128 auto &R = this->Rec;129 ASSERT_FALSE(errorToBool(R->apply(*this->Writer)));130 131 DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8);132 uint64_t OffsetPtr = 0;133 auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr);134 if (!HeaderOrErr)135 FAIL() << HeaderOrErr.takeError();136 137 FileBasedRecordProducer P(HeaderOrErr.get(), DE, OffsetPtr);138 std::vector<std::unique_ptr<Record>> Records;139 LogBuilderConsumer C(Records);140 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {141 auto R = P.produce();142 if (!R)143 FAIL() << R.takeError();144 if (auto E = C.consume(std::move(R.get())))145 FAIL() << E;146 }147 ASSERT_THAT(Records, Not(IsEmpty()));148 std::string Data2;149 raw_string_ostream OS2(Data2);150 FDRTraceWriter Writer2(OS2, this->H);151 for (auto &P : Records)152 ASSERT_FALSE(errorToBool(P->apply(Writer2)));153 154 EXPECT_EQ(Data2.substr(sizeof(XRayFileHeader)),155 this->Data.substr(sizeof(XRayFileHeader)));156 ASSERT_THAT(Records, SizeIs(2));157 EXPECT_THAT(Records[1]->getRecordType(), Eq(R->getRecordType()));158}159 160REGISTER_TYPED_TEST_SUITE_P(RoundTripTest, RoundTripsSingleValue);161 162// We duplicate the above case for the V5 version using different types and163// encodings.164TYPED_TEST_P(RoundTripTestV5, RoundTripsSingleValue) {165 BufferExtents BE(200);166 ASSERT_FALSE(errorToBool(BE.apply(*this->Writer)));167 auto &R = this->Rec;168 ASSERT_FALSE(errorToBool(R->apply(*this->Writer)));169 170 DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8);171 uint64_t OffsetPtr = 0;172 auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr);173 if (!HeaderOrErr)174 FAIL() << HeaderOrErr.takeError();175 176 FileBasedRecordProducer P(HeaderOrErr.get(), DE, OffsetPtr);177 std::vector<std::unique_ptr<Record>> Records;178 LogBuilderConsumer C(Records);179 while (DE.isValidOffsetForDataOfSize(OffsetPtr, 1)) {180 auto R = P.produce();181 if (!R)182 FAIL() << R.takeError();183 if (auto E = C.consume(std::move(R.get())))184 FAIL() << E;185 }186 ASSERT_THAT(Records, Not(IsEmpty()));187 std::string Data2;188 raw_string_ostream OS2(Data2);189 FDRTraceWriter Writer2(OS2, this->H);190 for (auto &P : Records)191 ASSERT_FALSE(errorToBool(P->apply(Writer2)));192 193 EXPECT_EQ(Data2.substr(sizeof(XRayFileHeader)),194 this->Data.substr(sizeof(XRayFileHeader)));195 ASSERT_THAT(Records, SizeIs(2));196 EXPECT_THAT(Records[1]->getRecordType(), Eq(R->getRecordType()));197}198 199REGISTER_TYPED_TEST_SUITE_P(RoundTripTestV5, RoundTripsSingleValue);200 201// These are the record types we support for v4 and below.202using RecordTypes =203 ::testing::Types<NewBufferRecord, NewCPUIDRecord, TSCWrapRecord,204 WallclockRecord, CustomEventRecord, CallArgRecord,205 PIDRecord, FunctionRecord>;206INSTANTIATE_TYPED_TEST_SUITE_P(Records, RoundTripTest, RecordTypes, );207 208// For V5, we have two new types we're supporting.209using RecordTypesV5 =210 ::testing::Types<NewBufferRecord, NewCPUIDRecord, TSCWrapRecord,211 WallclockRecord, CustomEventRecordV5, TypedEventRecord,212 CallArgRecord, PIDRecord, FunctionRecord>;213INSTANTIATE_TYPED_TEST_SUITE_P(Records, RoundTripTestV5, RecordTypesV5, );214 215} // namespace216} // namespace xray217} // namespace llvm218