• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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