162 lines · cpp
1//===-- fdr_log_writer_test.cpp -------------------------------------------===//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// This file is a part of XRay, a function call tracing system.10//11//===----------------------------------------------------------------------===//12#include <time.h>13 14#include "test_helpers.h"15#include "xray/xray_records.h"16#include "xray_fdr_log_writer.h"17#include "llvm/Support/DataExtractor.h"18#include "llvm/Testing/Support/Error.h"19#include "llvm/XRay/Trace.h"20#include "gmock/gmock.h"21#include "gtest/gtest.h"22 23namespace __xray {24namespace {25 26static constexpr size_t kSize = 4096;27 28using ::llvm::HasValue;29using ::llvm::xray::testing::FuncId;30using ::llvm::xray::testing::RecordType;31using ::testing::AllOf;32using ::testing::ElementsAre;33using ::testing::Eq;34using ::testing::IsEmpty;35using ::testing::IsNull;36 37// Exercise the common code path where we initialize a buffer and are able to38// write some records successfully.39TEST(FdrLogWriterTest, WriteSomeRecords) {40 bool Success = false;41 BufferQueue Buffers(kSize, 1, Success);42 BufferQueue::Buffer B;43 ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);44 45 FDRLogWriter Writer(B);46 MetadataRecord Preamble[] = {47 createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(int32_t{1}),48 createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(49 int64_t{1}, int32_t{2}),50 createMetadataRecord<MetadataRecord::RecordKinds::Pid>(int32_t{1}),51 };52 ASSERT_THAT(Writer.writeMetadataRecords(Preamble),53 Eq(sizeof(MetadataRecord) * 3));54 ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(1));55 ASSERT_TRUE(56 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, 1));57 ASSERT_TRUE(58 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, 1, 1));59 ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);60 ASSERT_EQ(B.Data, nullptr);61 ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);62 63 // We then need to go through each element of the Buffers, and re-create a64 // flat buffer that we would see if they were laid out in a file. This also65 // means we need to write out the header manually.66 std::string Serialized = serialize(Buffers, 3);67 llvm::DataExtractor DE(Serialized, true, 8);68 auto TraceOrErr = llvm::xray::loadTrace(DE);69 EXPECT_THAT_EXPECTED(70 TraceOrErr,71 HasValue(ElementsAre(72 AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)),73 AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));74}75 76// Ensure that we can handle buffer re-use.77TEST(FdrLogWriterTest, ReuseBuffers) {78 bool Success = false;79 BufferQueue Buffers(kSize, 1, Success);80 BufferQueue::Buffer B;81 ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);82 83 FDRLogWriter Writer(B);84 MetadataRecord Preamble[] = {85 createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(int32_t{1}),86 createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(87 int64_t{1}, int32_t{2}),88 createMetadataRecord<MetadataRecord::RecordKinds::Pid>(int32_t{1}),89 };90 91 // First we write the first set of records into the single buffer in the92 // queue which includes one enter and one exit record.93 ASSERT_THAT(Writer.writeMetadataRecords(Preamble),94 Eq(sizeof(MetadataRecord) * 3));95 ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(96 uint16_t{1}, uint64_t{1}));97 uint64_t TSC = 1;98 ASSERT_TRUE(99 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, TSC++));100 ASSERT_TRUE(101 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, 1, TSC++));102 ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);103 ASSERT_THAT(B.Data, IsNull());104 105 // Then we re-use the buffer, but only write one record.106 ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);107 Writer.resetRecord();108 ASSERT_THAT(Writer.writeMetadataRecords(Preamble),109 Eq(sizeof(MetadataRecord) * 3));110 ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(111 uint16_t{1}, uint64_t{1}));112 ASSERT_TRUE(113 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, TSC++));114 ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);115 ASSERT_THAT(B.Data, IsNull());116 ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);117 118 // Then we validate that we only see the single enter record.119 std::string Serialized = serialize(Buffers, 3);120 llvm::DataExtractor DE(Serialized, true, 8);121 auto TraceOrErr = llvm::xray::loadTrace(DE);122 EXPECT_THAT_EXPECTED(123 TraceOrErr, HasValue(ElementsAre(AllOf(124 FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)))));125}126 127TEST(FdrLogWriterTest, UnwriteRecords) {128 bool Success = false;129 BufferQueue Buffers(kSize, 1, Success);130 BufferQueue::Buffer B;131 ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);132 133 FDRLogWriter Writer(B);134 MetadataRecord Preamble[] = {135 createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(int32_t{1}),136 createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(137 int64_t{1}, int32_t{2}),138 createMetadataRecord<MetadataRecord::RecordKinds::Pid>(int32_t{1}),139 };140 ASSERT_THAT(Writer.writeMetadataRecords(Preamble),141 Eq(sizeof(MetadataRecord) * 3));142 ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(1));143 ASSERT_TRUE(144 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, 1));145 ASSERT_TRUE(146 Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, 1, 1));147 Writer.undoWrites(sizeof(FunctionRecord) * 2);148 ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);149 ASSERT_EQ(B.Data, nullptr);150 ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);151 152 // We've un-done the two function records we've written, and now we expect153 // that we don't have any function records in the trace.154 std::string Serialized = serialize(Buffers, 3);155 llvm::DataExtractor DE(Serialized, true, 8);156 auto TraceOrErr = llvm::xray::loadTrace(DE);157 EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(IsEmpty()));158}159 160} // namespace161} // namespace __xray162