162 lines
6.3 KiB
C++
162 lines
6.3 KiB
C++
//===-- fdr_log_writer_test.cpp -------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of XRay, a function call tracing system.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include <time.h>
|
|
|
|
#include "test_helpers.h"
|
|
#include "xray/xray_records.h"
|
|
#include "xray_fdr_log_writer.h"
|
|
#include "llvm/Support/DataExtractor.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
#include "llvm/XRay/Trace.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace __xray {
|
|
namespace {
|
|
|
|
static constexpr size_t kSize = 4096;
|
|
|
|
using ::llvm::HasValue;
|
|
using ::llvm::xray::testing::FuncId;
|
|
using ::llvm::xray::testing::RecordType;
|
|
using ::testing::AllOf;
|
|
using ::testing::ElementsAre;
|
|
using ::testing::Eq;
|
|
using ::testing::IsEmpty;
|
|
using ::testing::IsNull;
|
|
|
|
// Exercise the common code path where we initialize a buffer and are able to
|
|
// write some records successfully.
|
|
TEST(FdrLogWriterTest, WriteSomeRecords) {
|
|
bool Success = false;
|
|
BufferQueue Buffers(kSize, 1, Success);
|
|
BufferQueue::Buffer B;
|
|
ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
|
|
FDRLogWriter Writer(B);
|
|
MetadataRecord Preamble[] = {
|
|
createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(int32_t{1}),
|
|
createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(
|
|
int64_t{1}, int32_t{2}),
|
|
createMetadataRecord<MetadataRecord::RecordKinds::Pid>(int32_t{1}),
|
|
};
|
|
ASSERT_THAT(Writer.writeMetadataRecords(Preamble),
|
|
Eq(sizeof(MetadataRecord) * 3));
|
|
ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(1));
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, 1));
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, 1, 1));
|
|
ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
ASSERT_EQ(B.Data, nullptr);
|
|
ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);
|
|
|
|
// We then need to go through each element of the Buffers, and re-create a
|
|
// flat buffer that we would see if they were laid out in a file. This also
|
|
// means we need to write out the header manually.
|
|
std::string Serialized = serialize(Buffers, 3);
|
|
llvm::DataExtractor DE(Serialized, true, 8);
|
|
auto TraceOrErr = llvm::xray::loadTrace(DE);
|
|
EXPECT_THAT_EXPECTED(
|
|
TraceOrErr,
|
|
HasValue(ElementsAre(
|
|
AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)),
|
|
AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
|
|
}
|
|
|
|
// Ensure that we can handle buffer re-use.
|
|
TEST(FdrLogWriterTest, ReuseBuffers) {
|
|
bool Success = false;
|
|
BufferQueue Buffers(kSize, 1, Success);
|
|
BufferQueue::Buffer B;
|
|
ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
|
|
FDRLogWriter Writer(B);
|
|
MetadataRecord Preamble[] = {
|
|
createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(int32_t{1}),
|
|
createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(
|
|
int64_t{1}, int32_t{2}),
|
|
createMetadataRecord<MetadataRecord::RecordKinds::Pid>(int32_t{1}),
|
|
};
|
|
|
|
// First we write the first set of records into the single buffer in the
|
|
// queue which includes one enter and one exit record.
|
|
ASSERT_THAT(Writer.writeMetadataRecords(Preamble),
|
|
Eq(sizeof(MetadataRecord) * 3));
|
|
ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(
|
|
uint16_t{1}, uint64_t{1}));
|
|
uint64_t TSC = 1;
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, TSC++));
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, 1, TSC++));
|
|
ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
ASSERT_THAT(B.Data, IsNull());
|
|
|
|
// Then we re-use the buffer, but only write one record.
|
|
ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
Writer.resetRecord();
|
|
ASSERT_THAT(Writer.writeMetadataRecords(Preamble),
|
|
Eq(sizeof(MetadataRecord) * 3));
|
|
ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(
|
|
uint16_t{1}, uint64_t{1}));
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, TSC++));
|
|
ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
ASSERT_THAT(B.Data, IsNull());
|
|
ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);
|
|
|
|
// Then we validate that we only see the single enter record.
|
|
std::string Serialized = serialize(Buffers, 3);
|
|
llvm::DataExtractor DE(Serialized, true, 8);
|
|
auto TraceOrErr = llvm::xray::loadTrace(DE);
|
|
EXPECT_THAT_EXPECTED(
|
|
TraceOrErr, HasValue(ElementsAre(AllOf(
|
|
FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)))));
|
|
}
|
|
|
|
TEST(FdrLogWriterTest, UnwriteRecords) {
|
|
bool Success = false;
|
|
BufferQueue Buffers(kSize, 1, Success);
|
|
BufferQueue::Buffer B;
|
|
ASSERT_EQ(Buffers.getBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
|
|
FDRLogWriter Writer(B);
|
|
MetadataRecord Preamble[] = {
|
|
createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(int32_t{1}),
|
|
createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(
|
|
int64_t{1}, int32_t{2}),
|
|
createMetadataRecord<MetadataRecord::RecordKinds::Pid>(int32_t{1}),
|
|
};
|
|
ASSERT_THAT(Writer.writeMetadataRecords(Preamble),
|
|
Eq(sizeof(MetadataRecord) * 3));
|
|
ASSERT_TRUE(Writer.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(1));
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Enter, 1, 1));
|
|
ASSERT_TRUE(
|
|
Writer.writeFunction(FDRLogWriter::FunctionRecordKind::Exit, 1, 1));
|
|
Writer.undoWrites(sizeof(FunctionRecord) * 2);
|
|
ASSERT_EQ(Buffers.releaseBuffer(B), BufferQueue::ErrorCode::Ok);
|
|
ASSERT_EQ(B.Data, nullptr);
|
|
ASSERT_EQ(Buffers.finalize(), BufferQueue::ErrorCode::Ok);
|
|
|
|
// We've un-done the two function records we've written, and now we expect
|
|
// that we don't have any function records in the trace.
|
|
std::string Serialized = serialize(Buffers, 3);
|
|
llvm::DataExtractor DE(Serialized, true, 8);
|
|
auto TraceOrErr = llvm::xray::loadTrace(DE);
|
|
EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(IsEmpty()));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace __xray
|