1 //===-- fdr_log_writer_test.cpp -------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of XRay, a function call tracing system.
11 //===----------------------------------------------------------------------===//
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"
26 static constexpr size_t kSize
= 4096;
28 using ::llvm::HasValue
;
29 using ::llvm::xray::testing::FuncId
;
30 using ::llvm::xray::testing::RecordType
;
31 using ::testing::AllOf
;
32 using ::testing::ElementsAre
;
34 using ::testing::IsEmpty
;
35 using ::testing::IsNull
;
37 // Exercise the common code path where we initialize a buffer and are able to
38 // write some records successfully.
39 TEST(FdrLogWriterTest
, WriteSomeRecords
) {
41 BufferQueue
Buffers(kSize
, 1, Success
);
42 BufferQueue::Buffer B
;
43 ASSERT_EQ(Buffers
.getBuffer(B
), BufferQueue::ErrorCode::Ok
);
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}),
52 ASSERT_THAT(Writer
.writeMetadataRecords(Preamble
),
53 Eq(sizeof(MetadataRecord
) * 3));
54 ASSERT_TRUE(Writer
.writeMetadata
<MetadataRecord::RecordKinds::NewCPUId
>(1));
56 Writer
.writeFunction(FDRLogWriter::FunctionRecordKind::Enter
, 1, 1));
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
);
63 // We then need to go through each element of the Buffers, and re-create a
64 // flat buffer that we would see if they were laid out in a file. This also
65 // 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
);
72 AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER
)),
73 AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT
)))));
76 // Ensure that we can handle buffer re-use.
77 TEST(FdrLogWriterTest
, ReuseBuffers
) {
79 BufferQueue
Buffers(kSize
, 1, Success
);
80 BufferQueue::Buffer B
;
81 ASSERT_EQ(Buffers
.getBuffer(B
), BufferQueue::ErrorCode::Ok
);
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}),
91 // First we write the first set of records into the single buffer in the
92 // 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}));
99 Writer
.writeFunction(FDRLogWriter::FunctionRecordKind::Enter
, 1, TSC
++));
101 Writer
.writeFunction(FDRLogWriter::FunctionRecordKind::Exit
, 1, TSC
++));
102 ASSERT_EQ(Buffers
.releaseBuffer(B
), BufferQueue::ErrorCode::Ok
);
103 ASSERT_THAT(B
.Data
, IsNull());
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}));
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
);
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
)))));
127 TEST(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
);
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}),
140 ASSERT_THAT(Writer
.writeMetadataRecords(Preamble
),
141 Eq(sizeof(MetadataRecord
) * 3));
142 ASSERT_TRUE(Writer
.writeMetadata
<MetadataRecord::RecordKinds::NewCPUId
>(1));
144 Writer
.writeFunction(FDRLogWriter::FunctionRecordKind::Enter
, 1, 1));
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
);
152 // We've un-done the two function records we've written, and now we expect
153 // 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()));
161 } // namespace __xray