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-exception
6 //
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
23 namespace __xray {
24 namespace {
25
26 static constexpr size_t kSize = 4096;
27
28 using ::llvm::HasValue;
29 using ::llvm::xray::testing::FuncId;
30 using ::llvm::xray::testing::RecordType;
31 using ::testing::AllOf;
32 using ::testing::ElementsAre;
33 using ::testing::Eq;
34 using ::testing::IsEmpty;
35 using ::testing::IsNull;
36
37 // Exercise the common code path where we initialize a buffer and are able to
38 // write some records successfully.
TEST(FdrLogWriterTest,WriteSomeRecords)39 TEST(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 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);
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.
TEST(FdrLogWriterTest,ReuseBuffers)77 TEST(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 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}));
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
TEST(FdrLogWriterTest,UnwriteRecords)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);
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 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()));
158 }
159
160 } // namespace
161 } // namespace __xray
162