[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

llvm-svn: 338347
This commit is contained in:
Dean Michael Berris 2018-07-31 04:16:54 +00:00
parent 3587150fcb
commit 3bd20d4605
5 changed files with 72 additions and 25 deletions

View File

@ -15,6 +15,8 @@
#include "xray_profile_collector.h" #include "xray_profile_collector.h"
#include "xray_profiling_flags.h" #include "xray_profiling_flags.h"
#include <cstdint> #include <cstdint>
#include <cstring>
#include <memory>
#include <thread> #include <thread>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -24,6 +26,29 @@ namespace {
static constexpr auto kHeaderSize = 16u; 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<const void *>(B.Data), nullptr);
ASSERT_EQ(B.Size, sizeof(ExpectedProfilingFileHeader));
typename std::aligned_storage<sizeof(ExpectedProfilingFileHeader)>::type
FileHeaderStorage;
ExpectedProfilingFileHeader ExpectedHeader;
std::memcpy(&FileHeaderStorage, B.Data, B.Size);
auto &FileHeader =
*reinterpret_cast<ExpectedProfilingFileHeader *>(&FileHeaderStorage);
ASSERT_EQ(ExpectedHeader.MagicBytes, FileHeader.MagicBytes);
ASSERT_EQ(ExpectedHeader.Version, FileHeader.Version);
}
void ValidateBlock(XRayBuffer B) { void ValidateBlock(XRayBuffer B) {
profilingFlags()->setDefaults(); profilingFlags()->setDefaults();
ASSERT_NE(static_cast<const void *>(B.Data), nullptr); ASSERT_NE(static_cast<const void *>(B.Data), nullptr);
@ -107,9 +132,13 @@ TEST(profileCollectorServiceTest, PostSerializeCollect) {
// Then we serialize the data. // Then we serialize the data.
profileCollectorService::serialize(); profileCollectorService::serialize();
// Then we go through a single buffer to see whether we're getting the data we // Then we go through two buffers to see whether we're getting the data we
// expect. // 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}); auto B = profileCollectorService::nextBuffer({nullptr, 0});
ValidateFileHeaderBlock(B);
B = profileCollectorService::nextBuffer(B);
ValidateBlock(B); ValidateBlock(B);
u32 BlockSize; u32 BlockSize;
u32 BlockNum; u32 BlockNum;
@ -169,6 +198,9 @@ TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) {
// Ensure that we see two buffers. // Ensure that we see two buffers.
auto B = profileCollectorService::nextBuffer({nullptr, 0}); auto B = profileCollectorService::nextBuffer({nullptr, 0});
ValidateFileHeaderBlock(B);
B = profileCollectorService::nextBuffer(B);
ValidateBlock(B); ValidateBlock(B);
B = profileCollectorService::nextBuffer(B); B = profileCollectorService::nextBuffer(B);

View File

@ -37,6 +37,19 @@ struct ProfileBuffer {
size_t Size; 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 { struct BlockHeader {
u32 BlockSize; u32 BlockSize;
u32 BlockNum; u32 BlockNum;
@ -302,7 +315,22 @@ XRayBuffer nextBuffer(XRayBuffer B) {
if (ProfileBuffers == nullptr || ProfileBuffers->Size() == 0) if (ProfileBuffers == nullptr || ProfileBuffers->Size() == 0)
return {nullptr, 0}; return {nullptr, 0};
if (B.Data == nullptr) static pthread_once_t Once = PTHREAD_ONCE_INIT;
static typename std::aligned_storage<sizeof(XRayProfilingFileHeader)>::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<XRayProfilingFileHeader *>(&FileHeaderStorage);
FileHeader.Timestamp = NanoTime();
FileHeader.PID = internal_getpid();
return {&FileHeaderStorage, sizeof(XRayProfilingFileHeader)};
}
if (UNLIKELY(B.Data == &FileHeaderStorage))
return {(*ProfileBuffers)[0].Data, (*ProfileBuffers)[0].Size}; return {(*ProfileBuffers)[0].Data, (*ProfileBuffers)[0].Size};
BlockHeader Header; BlockHeader Header;

View File

@ -32,16 +32,6 @@ namespace __xray {
namespace { 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 = { atomic_sint32_t ProfilerLogFlushStatus = {
XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING};
@ -144,14 +134,7 @@ XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT {
if (Verbosity()) if (Verbosity())
Report("profiling: Failed to flush to file, dropping data.\n"); Report("profiling: Failed to flush to file, dropping data.\n");
} else { } else {
XRayProfilingFileHeader Header; // Now for each of the buffers, write out the profile data as we would
Header.Timestamp = NanoTime();
Header.PID = internal_getpid();
retryingWriteAll(Fd, reinterpret_cast<const char *>(&Header),
reinterpret_cast<const char *>(&Header) +
sizeof(Header));
// Now for each of the threads, write out the profile data as we would
// see it in memory, verbatim. // see it in memory, verbatim.
while (B.Data != nullptr && B.Size != 0) { while (B.Data != nullptr && B.Size != 0) {
retryingWriteAll(Fd, reinterpret_cast<const char *>(B.Data), retryingWriteAll(Fd, reinterpret_cast<const char *>(B.Data),

View File

@ -51,7 +51,8 @@ volatile int buffer_counter = 0;
assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED);
assert(__xray_log_process_buffers(process_buffer) == assert(__xray_log_process_buffers(process_buffer) ==
XRayLogFlushStatus::XRAY_LOG_FLUSHED); XRayLogFlushStatus::XRAY_LOG_FLUSHED);
// We're running three threds, so we expect three buffers. // We're running three threads, so we expect four buffers (including the file
assert(buffer_counter == 3); // header buffer).
assert(buffer_counter == 4);
assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED);
} }

View File

@ -47,7 +47,10 @@ volatile int buffer_counter = 0;
f0(); f0();
assert(__xray_log_process_buffers(process_buffer) == assert(__xray_log_process_buffers(process_buffer) ==
XRayLogFlushStatus::XRAY_LOG_FLUSHED); 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); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED);
// Let's reset the counter. // Let's reset the counter.
@ -60,6 +63,6 @@ volatile int buffer_counter = 0;
f0(); f0();
assert(__xray_log_process_buffers(process_buffer) == assert(__xray_log_process_buffers(process_buffer) ==
XRayLogFlushStatus::XRAY_LOG_FLUSHED); XRayLogFlushStatus::XRAY_LOG_FLUSHED);
assert(buffer_counter == 1); assert(buffer_counter == 2);
assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED);
} }