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