summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDean Michael Berris <dberris@google.com>2018-09-18 23:59:32 +0000
committerDean Michael Berris <dberris@google.com>2018-09-18 23:59:32 +0000
commitf43b0036debcc028ba42e1ee86666f4028870b55 (patch)
tree5da5c1615b25e680da4597ea58ac9e0c178cefac /lib
parent6c9f8f33863d666b63fd670f108ce90a37d69fa8 (diff)
downloadcompiler-rt-f43b0036debcc028ba42e1ee86666f4028870b55.tar.gz
[XRay][compiler-rt] FDRLogWriter Abstraction
Summary: This change introduces an `FDRLogWriter` type which is responsible for serialising metadata and function records to character buffers. This is the first step in a refactoring of the implementation of the FDR runtime to allow for more granular testing of the individual components of the implementation. The main contribution of this change is a means of hiding the details of how specific records are written to a buffer, and for managing the extents of these buffers. We make use of C++ features (templates and some metaprogramming) to reduce repetition in the act of writing out specific kinds of records to the buffer. In this process, we make a number of changes across both LLVM and compiler-rt to allow us to use the `Trace` abstraction defined in the LLVM project in the testing of the runtime implementation. This gives us a closer end-to-end test which version-locks the runtime implementation with the loading implementation in LLVM. We also allow using gmock in compiler-rt unit tests, by adding the requisite definitions in the `AddCompilerRT.cmake` module. Finally, we've gone ahead and updated the FDR logging implementation to use the FDRLogWriter for the lowest-level record-writing details. Following patches will isolate the state machine transitions which manage the set-up and tear-down of the buffers we're using in multiple threads. Reviewers: mboerger, eizan Subscribers: mgorny, jfb, llvm-commits Differential Revision: https://reviews.llvm.org/D52220 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@342518 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/xray/tests/CMakeLists.txt15
-rw-r--r--lib/xray/tests/unit/CMakeLists.txt4
-rw-r--r--lib/xray/tests/unit/fdr_log_writer_test.cc92
-rw-r--r--lib/xray/xray_fdr_log_records.h5
-rw-r--r--lib/xray/xray_fdr_log_writer.h119
-rw-r--r--lib/xray/xray_fdr_logging.cc131
6 files changed, 279 insertions, 87 deletions
diff --git a/lib/xray/tests/CMakeLists.txt b/lib/xray/tests/CMakeLists.txt
index 11f373167..6e12297f9 100644
--- a/lib/xray/tests/CMakeLists.txt
+++ b/lib/xray/tests/CMakeLists.txt
@@ -19,9 +19,13 @@ set(XRAY_UNITTEST_CFLAGS
${XRAY_CFLAGS}
${COMPILER_RT_UNITTEST_CFLAGS}
${COMPILER_RT_GTEST_CFLAGS}
+ ${COMPILER_RT_GMOCK_CFLAGS}
-I${COMPILER_RT_SOURCE_DIR}/include
-I${COMPILER_RT_SOURCE_DIR}/lib/xray
- -I${COMPILER_RT_SOURCE_DIR}/lib)
+ -I${COMPILER_RT_SOURCE_DIR}/lib
+ -I${LLVM_MAIN_SRC_DIR}/include
+ -I${LLVM_INCLUDE_DIR}
+ )
function(add_xray_lib library)
add_library(${library} STATIC ${ARGN})
@@ -68,11 +72,14 @@ macro(add_xray_unittest testname)
COMPILE_DEPS ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}
${XRAY_HEADERS} ${XRAY_ALL_SOURCE_FILES_ABS_PATHS}
RUNTIME "${XRAY_RUNTIME_LIBS}"
- DEPS gtest xray llvm-xray
+ DEPS gtest xray llvm-xray LLVMXRay LLVMTestingSupport
CFLAGS ${XRAY_UNITTEST_CFLAGS}
- LINK_FLAGS ${TARGET_LINK_FLAGS} ${XRAY_UNITTEST_LINK_FLAGS})
+ LINK_FLAGS ${TARGET_LINK_FLAGS} ${XRAY_UNITTEST_LINK_FLAGS}
+ -lLLVMXRay -lLLVMSupport -lLLVMTestingSupport -ltinfo
+ )
set_target_properties(XRayUnitTests
- PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endforeach()
endif()
endmacro()
diff --git a/lib/xray/tests/unit/CMakeLists.txt b/lib/xray/tests/unit/CMakeLists.txt
index 63c46e41c..b1ead627e 100644
--- a/lib/xray/tests/unit/CMakeLists.txt
+++ b/lib/xray/tests/unit/CMakeLists.txt
@@ -8,3 +8,7 @@ add_xray_unittest(XRayFunctionCallTrieTest SOURCES
function_call_trie_test.cc xray_unit_test_main.cc)
add_xray_unittest(XRayProfileCollectorTest SOURCES
profile_collector_test.cc xray_unit_test_main.cc)
+
+add_xray_unittest(XRayFDRLoggingTest SOURCES
+ fdr_log_writer_test.cc
+ xray_unit_test_main.cc)
diff --git a/lib/xray/tests/unit/fdr_log_writer_test.cc b/lib/xray/tests/unit/fdr_log_writer_test.cc
new file mode 100644
index 000000000..3a2138cd8
--- /dev/null
+++ b/lib/xray/tests/unit/fdr_log_writer_test.cc
@@ -0,0 +1,92 @@
+//===-- fdr_log_writer_test.cc --------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of XRay, a function call tracing system.
+//
+//===----------------------------------------------------------------------===//
+#include <time.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 ::testing::Eq;
+using ::testing::SizeIs;
+
+// 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.
+ // TODO: Isolate the file header writing.
+ std::string Serialized;
+ std::aligned_storage<sizeof(XRayFileHeader), alignof(XRayFileHeader)>::type
+ HeaderStorage;
+ auto *Header = reinterpret_cast<XRayFileHeader *>(&HeaderStorage);
+ new (Header) XRayFileHeader();
+ Header->Version = 3;
+ Header->Type = FileTypes::FDR_LOG;
+ Header->CycleFrequency = 3e9;
+ Header->ConstantTSC = 1;
+ Header->NonstopTSC = 1;
+ Serialized.append(reinterpret_cast<const char *>(&HeaderStorage),
+ sizeof(XRayFileHeader));
+ size_t BufferCount = 0;
+ Buffers.apply([&](const BufferQueue::Buffer &B) {
+ ++BufferCount;
+ auto Size = atomic_load_relaxed(&B.Extents);
+ auto Extents =
+ createMetadataRecord<MetadataRecord::RecordKinds::BufferExtents>(Size);
+ Serialized.append(reinterpret_cast<const char *>(&Extents),
+ sizeof(Extents));
+ Serialized.append(reinterpret_cast<const char *>(B.Data), Size);
+ });
+ ASSERT_EQ(BufferCount, 1u);
+
+ llvm::DataExtractor DE(Serialized, true, 8);
+ auto TraceOrErr = llvm::xray::loadTrace(DE);
+ EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(SizeIs(2)));
+}
+
+} // namespace
+} // namespace __xray
diff --git a/lib/xray/xray_fdr_log_records.h b/lib/xray/xray_fdr_log_records.h
index 87096d4fc..e7b1ee562 100644
--- a/lib/xray/xray_fdr_log_records.h
+++ b/lib/xray/xray_fdr_log_records.h
@@ -12,6 +12,9 @@
//===----------------------------------------------------------------------===//
#ifndef XRAY_XRAY_FDR_LOG_RECORDS_H
#define XRAY_XRAY_FDR_LOG_RECORDS_H
+#include <cstdint>
+
+namespace __xray {
enum class RecordType : uint8_t { Function, Metadata };
@@ -68,4 +71,6 @@ struct alignas(8) FunctionRecord {
static_assert(sizeof(FunctionRecord) == 8, "Wrong size for FunctionRecord.");
+} // namespace __xray
+
#endif // XRAY_XRAY_FDR_LOG_RECORDS_H
diff --git a/lib/xray/xray_fdr_log_writer.h b/lib/xray/xray_fdr_log_writer.h
new file mode 100644
index 000000000..28af356e7
--- /dev/null
+++ b/lib/xray/xray_fdr_log_writer.h
@@ -0,0 +1,119 @@
+//===-- xray_fdr_log_writer.h ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of XRay, a function call tracing system.
+//
+//===----------------------------------------------------------------------===//
+#ifndef COMPILER_RT_LIB_XRAY_XRAY_FDR_LOG_WRITER_H_
+#define COMPILER_RT_LIB_XRAY_XRAY_FDR_LOG_WRITER_H_
+
+#include "xray_buffer_queue.h"
+#include "xray_fdr_log_records.h"
+#include <functional>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace __xray {
+
+template <size_t Index> struct SerializerImpl {
+ template <class Tuple,
+ typename std::enable_if<
+ Index<std::tuple_size<
+ typename std::remove_reference<Tuple>::type>::value,
+ int>::type = 0> static void serializeTo(char *Buffer,
+ Tuple &&T) {
+ auto P = reinterpret_cast<const char *>(&std::get<Index>(T));
+ constexpr auto Size = sizeof(std::get<Index>(T));
+ internal_memcpy(Buffer, P, Size);
+ SerializerImpl<Index + 1>::serializeTo(Buffer + Size,
+ std::forward<Tuple>(T));
+ }
+
+ template <class Tuple,
+ typename std::enable_if<
+ Index >= std::tuple_size<typename std::remove_reference<
+ Tuple>::type>::value,
+ int>::type = 0>
+ static void serializeTo(char *, Tuple &&){};
+};
+
+using Serializer = SerializerImpl<0>;
+
+template <MetadataRecord::RecordKinds Kind, class... DataTypes>
+MetadataRecord createMetadataRecord(DataTypes &&... Ds) {
+ MetadataRecord R;
+ R.Type = 1;
+ R.RecordKind = static_cast<uint8_t>(Kind);
+ Serializer::serializeTo(R.Data,
+ std::make_tuple(std::forward<DataTypes>(Ds)...));
+ return R;
+}
+
+class FDRLogWriter {
+ BufferQueue::Buffer &Buffer;
+ char *NextRecord = nullptr;
+
+ template <class T> void writeRecord(const T &R) {
+ internal_memcpy(NextRecord, reinterpret_cast<const char *>(&R), sizeof(T));
+ NextRecord += sizeof(T);
+ atomic_fetch_add(&Buffer.Extents, sizeof(T), memory_order_acq_rel);
+ }
+
+public:
+ explicit FDRLogWriter(BufferQueue::Buffer &B, char *P)
+ : Buffer(B), NextRecord(P) {
+ DCHECK_NE(Buffer.Data, nullptr);
+ DCHECK_NE(NextRecord, nullptr);
+ }
+
+ explicit FDRLogWriter(BufferQueue::Buffer &B)
+ : FDRLogWriter(B, static_cast<char *>(B.Data)) {}
+
+ template <MetadataRecord::RecordKinds Kind, class... Data>
+ bool writeMetadata(Data &&... Ds) {
+ // TODO: Check boundary conditions:
+ // 1) Buffer is full, and cannot handle one metadata record.
+ // 2) Buffer queue is finalising.
+ writeRecord(createMetadataRecord<Kind>(std::forward<Data>(Ds)...));
+ return true;
+ }
+
+ template <size_t N> size_t writeMetadataRecords(MetadataRecord (&Recs)[N]) {
+ constexpr auto Size = sizeof(MetadataRecord) * N;
+ internal_memcpy(NextRecord, reinterpret_cast<const char *>(Recs), Size);
+ NextRecord += Size;
+ atomic_fetch_add(&Buffer.Extents, Size, memory_order_acq_rel);
+ return Size;
+ }
+
+ enum class FunctionRecordKind : uint8_t {
+ Enter = 0x00,
+ Exit = 0x01,
+ TailExit = 0x02,
+ EnterArg = 0x03,
+ };
+
+ bool writeFunction(FunctionRecordKind Kind, int32_t FuncId, int32_t Delta) {
+ FunctionRecord R;
+ R.Type = 0;
+ R.RecordKind = uint8_t(Kind);
+ R.FuncId = FuncId;
+ R.TSCDelta = Delta;
+ writeRecord(R);
+ return true;
+ }
+
+ char *getNextRecord() const { return NextRecord; }
+
+}; // namespace __xray
+
+} // namespace __xray
+
+#endif // COMPILER-RT_LIB_XRAY_XRAY_FDR_LOG_WRITER_H_
diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc
index 131c137b6..bb9492bc9 100644
--- a/lib/xray/xray_fdr_logging.cc
+++ b/lib/xray/xray_fdr_logging.cc
@@ -34,6 +34,7 @@
#include "xray_buffer_queue.h"
#include "xray_defs.h"
#include "xray_fdr_flags.h"
+#include "xray_fdr_log_writer.h"
#include "xray_flags.h"
#include "xray_recursion_guard.h"
#include "xray_tsc.h"
@@ -138,59 +139,35 @@ static ThreadLocalData &getThreadLocalData() {
static void writeNewBufferPreamble(tid_t Tid, timespec TS,
pid_t Pid) XRAY_NEVER_INSTRUMENT {
- static constexpr int InitRecordsCount = 3;
+ static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes");
auto &TLD = getThreadLocalData();
- MetadataRecord Metadata[InitRecordsCount];
- {
- // Write out a MetadataRecord to signify that this is the start of a new
- // buffer, associated with a particular thread, with a new CPU. For the
- // data, we have 15 bytes to squeeze as much information as we can. At this
- // point we only write down the following bytes:
- // - Thread ID (tid_t, cast to 4 bytes type due to Darwin being 8 bytes)
- auto &NewBuffer = Metadata[0];
- NewBuffer.Type = uint8_t(RecordType::Metadata);
- NewBuffer.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewBuffer);
- int32_t tid = static_cast<int32_t>(Tid);
- internal_memcpy(&NewBuffer.Data, &tid, sizeof(tid));
- }
-
- // Also write the WalltimeMarker record.
- {
- static_assert(sizeof(time_t) <= 8, "time_t needs to be at most 8 bytes");
- auto &WalltimeMarker = Metadata[1];
- WalltimeMarker.Type = uint8_t(RecordType::Metadata);
- WalltimeMarker.RecordKind =
- uint8_t(MetadataRecord::RecordKinds::WalltimeMarker);
-
- // We only really need microsecond precision here, and enforce across
- // platforms that we need 64-bit seconds and 32-bit microseconds encoded in
- // the Metadata record.
- int32_t Micros = TS.tv_nsec / 1000;
- int64_t Seconds = TS.tv_sec;
- internal_memcpy(WalltimeMarker.Data, &Seconds, sizeof(Seconds));
- internal_memcpy(WalltimeMarker.Data + sizeof(Seconds), &Micros,
- sizeof(Micros));
- }
-
- // Also write the Pid record.
- {
- // Write out a MetadataRecord that contains the current pid
- auto &PidMetadata = Metadata[2];
- PidMetadata.Type = uint8_t(RecordType::Metadata);
- PidMetadata.RecordKind = uint8_t(MetadataRecord::RecordKinds::Pid);
- int32_t pid = static_cast<int32_t>(Pid);
- internal_memcpy(&PidMetadata.Data, &pid, sizeof(pid));
- }
+ MetadataRecord Metadata[] = {
+ // Write out a MetadataRecord to signify that this is the start of a new
+ // buffer, associated with a particular thread, with a new CPU. For the
+ // data, we have 15 bytes to squeeze as much information as we can. At
+ // this point we only write down the following bytes:
+ // - Thread ID (tid_t, cast to 4 bytes type due to Darwin being 8 bytes)
+ createMetadataRecord<MetadataRecord::RecordKinds::NewBuffer>(
+ static_cast<int32_t>(Tid)),
+
+ // Also write the WalltimeMarker record. We only really need microsecond
+ // precision here, and enforce across platforms that we need 64-bit
+ // seconds and 32-bit microseconds encoded in the Metadata record.
+ createMetadataRecord<MetadataRecord::RecordKinds::WalltimeMarker>(
+ static_cast<int64_t>(TS.tv_sec),
+ static_cast<int32_t>(TS.tv_nsec / 1000)),
+
+ // Also write the Pid record.
+ createMetadataRecord<MetadataRecord::RecordKinds::Pid>(
+ static_cast<int32_t>(Pid)),
+ };
TLD.NumConsecutiveFnEnters = 0;
TLD.NumTailCalls = 0;
if (TLD.BQ == nullptr || TLD.BQ->finalizing())
return;
- internal_memcpy(TLD.RecordPtr, Metadata,
- sizeof(MetadataRecord) * InitRecordsCount);
- TLD.RecordPtr += sizeof(MetadataRecord) * InitRecordsCount;
- atomic_store(&TLD.Buffer.Extents, sizeof(MetadataRecord) * InitRecordsCount,
- memory_order_release);
+ FDRLogWriter Writer(TLD.Buffer);
+ TLD.RecordPtr += Writer.writeMetadataRecords(Metadata);
}
static void setupNewBuffer(int (*wall_clock_reader)(
@@ -198,6 +175,7 @@ static void setupNewBuffer(int (*wall_clock_reader)(
auto &TLD = getThreadLocalData();
auto &B = TLD.Buffer;
TLD.RecordPtr = static_cast<char *>(B.Data);
+ atomic_store(&B.Extents, 0, memory_order_release);
tid_t Tid = GetTid();
timespec TS{0, 0};
pid_t Pid = internal_getpid();
@@ -221,52 +199,38 @@ static void decrementExtents(size_t Subtract) {
static void writeNewCPUIdMetadata(uint16_t CPU,
uint64_t TSC) XRAY_NEVER_INSTRUMENT {
auto &TLD = getThreadLocalData();
- MetadataRecord NewCPUId;
- NewCPUId.Type = uint8_t(RecordType::Metadata);
- NewCPUId.RecordKind = uint8_t(MetadataRecord::RecordKinds::NewCPUId);
+ FDRLogWriter W(TLD.Buffer, TLD.RecordPtr);
// The data for the New CPU will contain the following bytes:
// - CPU ID (uint16_t, 2 bytes)
// - Full TSC (uint64_t, 8 bytes)
// Total = 10 bytes.
- internal_memcpy(&NewCPUId.Data, &CPU, sizeof(CPU));
- internal_memcpy(&NewCPUId.Data[sizeof(CPU)], &TSC, sizeof(TSC));
- internal_memcpy(TLD.RecordPtr, &NewCPUId, sizeof(MetadataRecord));
- TLD.RecordPtr += sizeof(MetadataRecord);
+ W.writeMetadata<MetadataRecord::RecordKinds::NewCPUId>(CPU, TSC);
+ TLD.RecordPtr = W.getNextRecord();
TLD.NumConsecutiveFnEnters = 0;
TLD.NumTailCalls = 0;
- incrementExtents(sizeof(MetadataRecord));
}
static void writeTSCWrapMetadata(uint64_t TSC) XRAY_NEVER_INSTRUMENT {
auto &TLD = getThreadLocalData();
- MetadataRecord TSCWrap;
- TSCWrap.Type = uint8_t(RecordType::Metadata);
- TSCWrap.RecordKind = uint8_t(MetadataRecord::RecordKinds::TSCWrap);
+ FDRLogWriter W(TLD.Buffer, TLD.RecordPtr);
// The data for the TSCWrap record contains the following bytes:
// - Full TSC (uint64_t, 8 bytes)
// Total = 8 bytes.
- internal_memcpy(&TSCWrap.Data, &TSC, sizeof(TSC));
- internal_memcpy(TLD.RecordPtr, &TSCWrap, sizeof(MetadataRecord));
- TLD.RecordPtr += sizeof(MetadataRecord);
+ W.writeMetadata<MetadataRecord::RecordKinds::TSCWrap>(TSC);
+ TLD.RecordPtr = W.getNextRecord();
TLD.NumConsecutiveFnEnters = 0;
TLD.NumTailCalls = 0;
- incrementExtents(sizeof(MetadataRecord));
}
// Call Argument metadata records store the arguments to a function in the
// order of their appearance; holes are not supported by the buffer format.
static void writeCallArgumentMetadata(uint64_t A) XRAY_NEVER_INSTRUMENT {
auto &TLD = getThreadLocalData();
- MetadataRecord CallArg;
- CallArg.Type = uint8_t(RecordType::Metadata);
- CallArg.RecordKind = uint8_t(MetadataRecord::RecordKinds::CallArgument);
-
- internal_memcpy(CallArg.Data, &A, sizeof(A));
- internal_memcpy(TLD.RecordPtr, &CallArg, sizeof(MetadataRecord));
- TLD.RecordPtr += sizeof(MetadataRecord);
- incrementExtents(sizeof(MetadataRecord));
+ FDRLogWriter W(TLD.Buffer, TLD.RecordPtr);
+ W.writeMetadata<MetadataRecord::RecordKinds::CallArgument>(A);
+ TLD.RecordPtr = W.getNextRecord();
}
static void writeFunctionRecord(int32_t FuncId, uint32_t TSCDelta,
@@ -279,8 +243,8 @@ static void writeFunctionRecord(int32_t FuncId, uint32_t TSCDelta,
return;
}
- FunctionRecord FuncRecord;
- FuncRecord.Type = uint8_t(RecordType::Function);
+ auto &TLD = getThreadLocalData();
+ FDRLogWriter W(TLD.Buffer, TLD.RecordPtr);
// Only take 28 bits of the function id.
//
@@ -289,27 +253,25 @@ static void writeFunctionRecord(int32_t FuncId, uint32_t TSCDelta,
// to the first 28 bits. To do this properly, this means we need to mask the
// function id with (2 ^ 28) - 1 == 0x0fffffff.
//
- FuncRecord.FuncId = FuncId & MaxFuncId;
- FuncRecord.TSCDelta = TSCDelta;
+ auto TruncatedId = FuncId & MaxFuncId;
+ auto Kind = FDRLogWriter::FunctionRecordKind::Enter;
- auto &TLD = getThreadLocalData();
switch (EntryType) {
case XRayEntryType::ENTRY:
++TLD.NumConsecutiveFnEnters;
- FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter);
break;
case XRayEntryType::LOG_ARGS_ENTRY:
// We should not rewind functions with logged args.
TLD.NumConsecutiveFnEnters = 0;
TLD.NumTailCalls = 0;
- FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionEnter);
+ Kind = FDRLogWriter::FunctionRecordKind::EnterArg;
break;
case XRayEntryType::EXIT:
// If we've decided to log the function exit, we will never erase the log
// before it.
TLD.NumConsecutiveFnEnters = 0;
TLD.NumTailCalls = 0;
- FuncRecord.RecordKind = uint8_t(FunctionRecord::RecordKinds::FunctionExit);
+ Kind = FDRLogWriter::FunctionRecordKind::Exit;
break;
case XRayEntryType::TAIL:
// If we just entered the function we're tail exiting from or erased every
@@ -324,8 +286,7 @@ static void writeFunctionRecord(int32_t FuncId, uint32_t TSCDelta,
TLD.NumTailCalls = 0;
TLD.NumConsecutiveFnEnters = 0;
}
- FuncRecord.RecordKind =
- uint8_t(FunctionRecord::RecordKinds::FunctionTailExit);
+ Kind = FDRLogWriter::FunctionRecordKind::TailExit;
break;
case XRayEntryType::CUSTOM_EVENT: {
// This is a bug in patching, so we'll report it once and move on.
@@ -346,9 +307,8 @@ static void writeFunctionRecord(int32_t FuncId, uint32_t TSCDelta,
}
}
- internal_memcpy(TLD.RecordPtr, &FuncRecord, sizeof(FunctionRecord));
- TLD.RecordPtr += sizeof(FunctionRecord);
- incrementExtents(sizeof(FunctionRecord));
+ W.writeFunction(Kind, TruncatedId, TSCDelta);
+ TLD.RecordPtr = W.getNextRecord();
}
static atomic_uint64_t TicksPerSec{0};
@@ -423,6 +383,9 @@ static void rewindRecentCall(uint64_t TSC, uint64_t &LastTSC,
static bool releaseThreadLocalBuffer(BufferQueue &BQArg) {
auto &TLD = getThreadLocalData();
auto EC = BQArg.releaseBuffer(TLD.Buffer);
+ if (TLD.Buffer.Data == nullptr)
+ return true;
+
if (EC != BufferQueue::ErrorCode::Ok) {
Report("Failed to release buffer at %p; error=%s\n", TLD.Buffer.Data,
BufferQueue::getErrorString(EC));
@@ -1174,6 +1137,8 @@ XRayLogInitStatus fdrLoggingInit(UNUSED size_t BufferSize,
auto &TLD = *reinterpret_cast<ThreadLocalData *>(TLDPtr);
if (TLD.BQ == nullptr)
return;
+ if (TLD.Buffer.Data == nullptr)
+ return;
auto EC = TLD.BQ->releaseBuffer(TLD.Buffer);
if (EC != BufferQueue::ErrorCode::Ok)
Report("At thread exit, failed to release buffer at %p; error=%s\n",