summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDean Michael Berris <dberris@google.com>2018-07-31 04:16:54 +0000
committerDean Michael Berris <dberris@google.com>2018-07-31 04:16:54 +0000
commitbc821e04b5903da1e87031d4c6112eace2cb0b32 (patch)
tree98a3f49bdf2579f6f227a24fbbdc52cbd82aed43
parent6172f778f61ee72085844a6566b72bdd2be141f4 (diff)
[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
-rw-r--r--lib/xray/tests/unit/profile_collector_test.cc36
-rw-r--r--lib/xray/xray_profile_collector.cc30
-rw-r--r--lib/xray/xray_profiling.cc19
-rw-r--r--test/xray/TestCases/Posix/profiling-multi-threaded.cc5
-rw-r--r--test/xray/TestCases/Posix/profiling-single-threaded.cc7
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 <cstdint>
+#include <cstring>
+#include <memory>
#include <thread>
#include <utility>
#include <vector>
@@ -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<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) {
profilingFlags()->setDefaults();
ASSERT_NE(static_cast<const void *>(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<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};
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<const char *>(&Header),
- reinterpret_cast<const char *>(&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<const char *>(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);
}