From bc821e04b5903da1e87031d4c6112eace2cb0b32 Mon Sep 17 00:00:00 2001 From: Dean Michael Berris Date: Tue, 31 Jul 2018 04:16:54 +0000 Subject: [XRay][compiler-rt] Profiling Mode: Include file header in buffers Summary: This change provides access to the file header even in the in-memory buffer processing. This allows in-memory processing of the buffers to also check the version, and the format, of the profile data. Reviewers: eizan, kpw Reviewed By: eizan Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D50037 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@338347 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/xray/tests/unit/profile_collector_test.cc | 36 ++++++++++++++++++++-- lib/xray/xray_profile_collector.cc | 30 +++++++++++++++++- lib/xray/xray_profiling.cc | 19 +----------- .../TestCases/Posix/profiling-multi-threaded.cc | 5 +-- .../TestCases/Posix/profiling-single-threaded.cc | 7 +++-- 5 files changed, 72 insertions(+), 25 deletions(-) diff --git a/lib/xray/tests/unit/profile_collector_test.cc b/lib/xray/tests/unit/profile_collector_test.cc index b7dbe5673..00a7d53dc 100644 --- a/lib/xray/tests/unit/profile_collector_test.cc +++ b/lib/xray/tests/unit/profile_collector_test.cc @@ -15,6 +15,8 @@ #include "xray_profile_collector.h" #include "xray_profiling_flags.h" #include +#include +#include #include #include #include @@ -24,6 +26,29 @@ namespace { static constexpr auto kHeaderSize = 16u; +constexpr uptr ExpectedProfilingVersion = 0x20180424; + +struct ExpectedProfilingFileHeader { + const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling + // files 'xrayprof' in hex. + const uptr Version = ExpectedProfilingVersion; + uptr Timestamp = 0; + uptr PID = 0; +}; + +void ValidateFileHeaderBlock(XRayBuffer B) { + ASSERT_NE(static_cast(B.Data), nullptr); + ASSERT_EQ(B.Size, sizeof(ExpectedProfilingFileHeader)); + typename std::aligned_storage::type + FileHeaderStorage; + ExpectedProfilingFileHeader ExpectedHeader; + std::memcpy(&FileHeaderStorage, B.Data, B.Size); + auto &FileHeader = + *reinterpret_cast(&FileHeaderStorage); + ASSERT_EQ(ExpectedHeader.MagicBytes, FileHeader.MagicBytes); + ASSERT_EQ(ExpectedHeader.Version, FileHeader.Version); +} + void ValidateBlock(XRayBuffer B) { profilingFlags()->setDefaults(); ASSERT_NE(static_cast(B.Data), nullptr); @@ -107,9 +132,13 @@ TEST(profileCollectorServiceTest, PostSerializeCollect) { // Then we serialize the data. profileCollectorService::serialize(); - // Then we go through a single buffer to see whether we're getting the data we - // expect. + // Then we go through two buffers to see whether we're getting the data we + // expect. The first block must always be as large as a file header, which + // will have a fixed size. auto B = profileCollectorService::nextBuffer({nullptr, 0}); + ValidateFileHeaderBlock(B); + + B = profileCollectorService::nextBuffer(B); ValidateBlock(B); u32 BlockSize; u32 BlockNum; @@ -169,6 +198,9 @@ TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) { // Ensure that we see two buffers. auto B = profileCollectorService::nextBuffer({nullptr, 0}); + ValidateFileHeaderBlock(B); + + B = profileCollectorService::nextBuffer(B); ValidateBlock(B); B = profileCollectorService::nextBuffer(B); diff --git a/lib/xray/xray_profile_collector.cc b/lib/xray/xray_profile_collector.cc index a43744d9a..17a611eea 100644 --- a/lib/xray/xray_profile_collector.cc +++ b/lib/xray/xray_profile_collector.cc @@ -37,6 +37,19 @@ struct ProfileBuffer { size_t Size; }; +// Current version of the profile format. +constexpr u64 XRayProfilingVersion = 0x20180424; + +// Identifier for XRay profiling files 'xrayprof' in hex. +constexpr u64 XRayMagicBytes = 0x7872617970726f66; + +struct XRayProfilingFileHeader { + const u64 MagicBytes = XRayMagicBytes; + const u64 Version = XRayProfilingVersion; + u64 Timestamp = 0; // System time in nanoseconds. + u64 PID = 0; // Process ID. +}; + struct BlockHeader { u32 BlockSize; u32 BlockNum; @@ -302,7 +315,22 @@ XRayBuffer nextBuffer(XRayBuffer B) { if (ProfileBuffers == nullptr || ProfileBuffers->Size() == 0) return {nullptr, 0}; - if (B.Data == nullptr) + static pthread_once_t Once = PTHREAD_ONCE_INIT; + static typename std::aligned_storage::type + FileHeaderStorage; + pthread_once(&Once, + +[] { new (&FileHeaderStorage) XRayProfilingFileHeader{}; }); + + if (UNLIKELY(B.Data == nullptr)) { + // The first buffer should always contain the file header information. + auto &FileHeader = + *reinterpret_cast(&FileHeaderStorage); + FileHeader.Timestamp = NanoTime(); + FileHeader.PID = internal_getpid(); + return {&FileHeaderStorage, sizeof(XRayProfilingFileHeader)}; + } + + if (UNLIKELY(B.Data == &FileHeaderStorage)) return {(*ProfileBuffers)[0].Data, (*ProfileBuffers)[0].Size}; BlockHeader Header; diff --git a/lib/xray/xray_profiling.cc b/lib/xray/xray_profiling.cc index 786084c77..d4b4345d7 100644 --- a/lib/xray/xray_profiling.cc +++ b/lib/xray/xray_profiling.cc @@ -32,16 +32,6 @@ namespace __xray { namespace { -constexpr uptr XRayProfilingVersion = 0x20180424; - -struct XRayProfilingFileHeader { - const u64 MagicBytes = 0x7872617970726f66; // Identifier for XRay profiling - // files 'xrayprof' in hex. - const uptr Version = XRayProfilingVersion; - uptr Timestamp = 0; // System time in nanoseconds. - uptr PID = 0; // Process ID. -}; - atomic_sint32_t ProfilerLogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; @@ -144,14 +134,7 @@ XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT { if (Verbosity()) Report("profiling: Failed to flush to file, dropping data.\n"); } else { - XRayProfilingFileHeader Header; - Header.Timestamp = NanoTime(); - Header.PID = internal_getpid(); - retryingWriteAll(Fd, reinterpret_cast(&Header), - reinterpret_cast(&Header) + - sizeof(Header)); - - // Now for each of the threads, write out the profile data as we would + // Now for each of the buffers, write out the profile data as we would // see it in memory, verbatim. while (B.Data != nullptr && B.Size != 0) { retryingWriteAll(Fd, reinterpret_cast(B.Data), diff --git a/test/xray/TestCases/Posix/profiling-multi-threaded.cc b/test/xray/TestCases/Posix/profiling-multi-threaded.cc index 7ccad1bac..45e5e7022 100644 --- a/test/xray/TestCases/Posix/profiling-multi-threaded.cc +++ b/test/xray/TestCases/Posix/profiling-multi-threaded.cc @@ -51,7 +51,8 @@ volatile int buffer_counter = 0; assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); assert(__xray_log_process_buffers(process_buffer) == XRayLogFlushStatus::XRAY_LOG_FLUSHED); - // We're running three threds, so we expect three buffers. - assert(buffer_counter == 3); + // We're running three threads, so we expect four buffers (including the file + // header buffer). + assert(buffer_counter == 4); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); } diff --git a/test/xray/TestCases/Posix/profiling-single-threaded.cc b/test/xray/TestCases/Posix/profiling-single-threaded.cc index fd508b1ac..fc518145e 100644 --- a/test/xray/TestCases/Posix/profiling-single-threaded.cc +++ b/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -47,7 +47,10 @@ volatile int buffer_counter = 0; f0(); assert(__xray_log_process_buffers(process_buffer) == XRayLogFlushStatus::XRAY_LOG_FLUSHED); - assert(buffer_counter == 1); + // There's always at least one buffer, containing the profile file header. We + // assert that we have two, to indicate that we're expecting exactly one + // thread's worth of data. + assert(buffer_counter == 2); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); // Let's reset the counter. @@ -60,6 +63,6 @@ volatile int buffer_counter = 0; f0(); assert(__xray_log_process_buffers(process_buffer) == XRayLogFlushStatus::XRAY_LOG_FLUSHED); - assert(buffer_counter == 1); + assert(buffer_counter == 2); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); } -- cgit v1.2.3