179 lines · cpp
1//===- llvm/unittest/XRay/FDRTraceWriterTest.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 a utility that can write out XRay FDR Mode formatted trace files.10//11//===----------------------------------------------------------------------===//12#include "llvm/XRay/FDRTraceWriter.h"13#include "llvm/Support/raw_ostream.h"14#include "llvm/XRay/FDRLogBuilder.h"15#include "llvm/XRay/FDRRecords.h"16#include "llvm/XRay/Trace.h"17#include "gmock/gmock.h"18#include "gtest/gtest.h"19#include <string>20 21namespace llvm {22namespace xray {23namespace {24 25using testing::ElementsAre;26using testing::Eq;27using testing::Field;28using testing::IsEmpty;29using testing::Not;30 31// We want to be able to create an instance of an FDRTraceWriter and associate32// it with a stream, which could be loaded and turned into a Trace instance.33// This test writes out version 3 trace logs.34TEST(FDRTraceWriterTest, WriteToStringBufferVersion3) {35 std::string Data;36 raw_string_ostream OS(Data);37 XRayFileHeader H;38 H.Version = 3;39 H.Type = 1;40 H.ConstantTSC = true;41 H.NonstopTSC = true;42 H.CycleFrequency = 3e9;43 FDRTraceWriter Writer(OS, H);44 auto L = LogBuilder()45 .add<BufferExtents>(80)46 .add<NewBufferRecord>(1)47 .add<WallclockRecord>(1, 1)48 .add<PIDRecord>(1)49 .add<NewCPUIDRecord>(1, 2)50 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)51 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)52 .consume();53 for (auto &P : L)54 ASSERT_FALSE(errorToBool(P->apply(Writer)));55 56 // Then from here we load the Trace file.57 DataExtractor DE(Data, sys::IsLittleEndianHost, 8);58 auto TraceOrErr = loadTrace(DE, true);59 if (!TraceOrErr)60 FAIL() << TraceOrErr.takeError();61 auto &Trace = TraceOrErr.get();62 63 ASSERT_THAT(Trace, Not(IsEmpty()));64 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::FuncId, Eq(1)),65 Field(&XRayRecord::FuncId, Eq(1))));66 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::TId, Eq(1u)),67 Field(&XRayRecord::TId, Eq(1u))));68 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::PId, Eq(1u)),69 Field(&XRayRecord::PId, Eq(1u))));70 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::CPU, Eq(1u)),71 Field(&XRayRecord::CPU, Eq(1u))));72 EXPECT_THAT(Trace,73 ElementsAre(Field(&XRayRecord::Type, Eq(RecordTypes::ENTER)),74 Field(&XRayRecord::Type, Eq(RecordTypes::EXIT))));75}76 77// This version is almost exactly the same as above, except writing version 278// logs, without the PID records.79TEST(FDRTraceWriterTest, WriteToStringBufferVersion2) {80 std::string Data;81 raw_string_ostream OS(Data);82 XRayFileHeader H;83 H.Version = 2;84 H.Type = 1;85 H.ConstantTSC = true;86 H.NonstopTSC = true;87 H.CycleFrequency = 3e9;88 FDRTraceWriter Writer(OS, H);89 auto L = LogBuilder()90 .add<BufferExtents>(64)91 .add<NewBufferRecord>(1)92 .add<WallclockRecord>(1, 1)93 .add<NewCPUIDRecord>(1, 2)94 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)95 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)96 .consume();97 for (auto &P : L)98 ASSERT_FALSE(errorToBool(P->apply(Writer)));99 100 // Then from here we load the Trace file.101 DataExtractor DE(Data, sys::IsLittleEndianHost, 8);102 auto TraceOrErr = loadTrace(DE, true);103 if (!TraceOrErr)104 FAIL() << TraceOrErr.takeError();105 auto &Trace = TraceOrErr.get();106 107 ASSERT_THAT(Trace, Not(IsEmpty()));108 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::FuncId, Eq(1)),109 Field(&XRayRecord::FuncId, Eq(1))));110 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::TId, Eq(1u)),111 Field(&XRayRecord::TId, Eq(1u))));112 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::CPU, Eq(1u)),113 Field(&XRayRecord::CPU, Eq(1u))));114 EXPECT_THAT(Trace,115 ElementsAre(Field(&XRayRecord::Type, Eq(RecordTypes::ENTER)),116 Field(&XRayRecord::Type, Eq(RecordTypes::EXIT))));117}118 119// This covers version 1 of the log, without a BufferExtents record but has an120// explicit EndOfBuffer record.121TEST(FDRTraceWriterTest, WriteToStringBufferVersion1) {122 std::string Data;123 raw_string_ostream OS(Data);124 XRayFileHeader H;125 H.Version = 1;126 H.Type = 1;127 H.ConstantTSC = true;128 H.NonstopTSC = true;129 H.CycleFrequency = 3e9;130 // Write the size of buffers out, arbitrarily it's 4k.131 constexpr uint64_t BufferSize = 4096;132 std::memcpy(H.FreeFormData, reinterpret_cast<const char *>(&BufferSize),133 sizeof(BufferSize));134 FDRTraceWriter Writer(OS, H);135 136 // Ensure that at this point the Data buffer has the file header serialized137 // size.138 ASSERT_THAT(Data.size(), Eq(32u));139 auto L = LogBuilder()140 .add<NewBufferRecord>(1)141 .add<WallclockRecord>(1, 1)142 .add<NewCPUIDRecord>(1, 2)143 .add<FunctionRecord>(RecordTypes::ENTER, 1, 1)144 .add<FunctionRecord>(RecordTypes::EXIT, 1, 100)145 .add<EndBufferRecord>()146 .consume();147 for (auto &P : L)148 ASSERT_FALSE(errorToBool(P->apply(Writer)));149 150 // We need to pad the buffer with 4016 (4096 - 80) bytes of zeros.151 OS.write_zeros(4016);152 153 // For version 1 of the log, we need the whole buffer to be the size of the154 // file header plus 32.155 ASSERT_THAT(Data.size(), Eq(BufferSize + 32));156 157 // Then from here we load the Trace file.158 DataExtractor DE(Data, sys::IsLittleEndianHost, 8);159 auto TraceOrErr = loadTrace(DE, true);160 if (!TraceOrErr)161 FAIL() << TraceOrErr.takeError();162 auto &Trace = TraceOrErr.get();163 164 ASSERT_THAT(Trace, Not(IsEmpty()));165 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::FuncId, Eq(1)),166 Field(&XRayRecord::FuncId, Eq(1))));167 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::TId, Eq(1u)),168 Field(&XRayRecord::TId, Eq(1u))));169 EXPECT_THAT(Trace, ElementsAre(Field(&XRayRecord::CPU, Eq(1u)),170 Field(&XRayRecord::CPU, Eq(1u))));171 EXPECT_THAT(Trace,172 ElementsAre(Field(&XRayRecord::Type, Eq(RecordTypes::ENTER)),173 Field(&XRayRecord::Type, Eq(RecordTypes::EXIT))));174}175 176} // namespace177} // namespace xray178} // namespace llvm179