Index: compiler-rt/lib/xray/xray_profile_collector.cc =================================================================== --- compiler-rt/lib/xray/xray_profile_collector.cc +++ compiler-rt/lib/xray/xray_profile_collector.cc @@ -14,9 +14,9 @@ //===----------------------------------------------------------------------===// #include -#include "xray_profile_collector.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_vector.h" +#include "xray_profile_collector.h" #include "xray_profiler_flags.h" #include @@ -260,7 +260,7 @@ // FIXME: Find a way to identify the buffers, somehow, from within this // function. SpinMutexLock Lock(&GlobalMutex); - if (B.Data == nullptr && ProfileBuffers.Size()) + if (B.Data == nullptr) return {ProfileBuffers[0].Data, ProfileBuffers[0].Size}; BlockHeader Header; Index: compiler-rt/lib/xray/xray_profiler.cc =================================================================== --- compiler-rt/lib/xray/xray_profiler.cc +++ compiler-rt/lib/xray/xray_profiler.cc @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// #include +#include #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_flags.h" @@ -30,6 +31,16 @@ 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. +}; + __sanitizer::atomic_sint32_t ProfilerLogFlushStatus = { XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; @@ -88,8 +99,6 @@ XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT { - // When flushing, all we really do is reset the global state, and only when - // the log has already been finalized. if (__sanitizer::atomic_load(&ProfilerLogStatus, __sanitizer::memory_order_acquire) != XRayLogInitStatus::XRAY_LOG_FINALIZED) { @@ -107,6 +116,37 @@ Report("Not flushing profiles, implementation still finalizing.\n"); } + // At this point, we'll create the file that will contain the profile, but + // only if the options say so. + if (!profilerFlags()->xray_profiling_no_flush) { + int Fd = -1; + Fd = getLogFD(); + if (Fd == -1) { + if (__sanitizer::Verbosity()) + Report( + "profiler: Failed to acquire a file descriptor, 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 see + // it in memory, verbatim. + XRayBuffer B = profileCollectorService::nextBuffer({nullptr, 0}); + while (B.Data != nullptr && B.Size != 0) { + retryingWriteAll(Fd, reinterpret_cast(B.Data), + reinterpret_cast(B.Data) + B.Size); + B = profileCollectorService::nextBuffer(B); + } + + // Then we close out the file. + internal_close(Fd); + } + } + profileCollectorService::reset(); __sanitizer::atomic_store(&ProfilerLogStatus, @@ -225,8 +265,16 @@ auto *F = profilerFlags(); F->setDefaults(); registerProfilerFlags(&ConfigParser, F); + + // Use the compile-time provided configuration string first. const char *ProfilerCompileFlags = profilerCompilerDefinedFlags(); ConfigParser.ParseString(ProfilerCompileFlags); + + // Check the environment variables to determine the defaults from the + // environment next. + ConfigParser.ParseString(GetEnv("XRAY_PROFILER_OPTIONS")); + + // Then parse the configuration string provided. ConfigParser.ParseString(static_cast(Options)); if (Verbosity()) ReportUnrecognizedFlags(); Index: compiler-rt/lib/xray/xray_profiler_flags.inc =================================================================== --- compiler-rt/lib/xray/xray_profiler_flags.inc +++ compiler-rt/lib/xray/xray_profiler_flags.inc @@ -24,3 +24,6 @@ "Profile collection will wait this much time in milliseconds before " "resetting the global state. This gives a chance to threads to " "notice that the profiler has been finalized and clean up.") +XRAY_FLAG(bool, xray_profiling_no_flush, false, + "Set to true if we want the profiling implementation to not write " + "out files.") Index: compiler-rt/lib/xray/xray_utils.h =================================================================== --- compiler-rt/lib/xray/xray_utils.h +++ compiler-rt/lib/xray/xray_utils.h @@ -24,7 +24,7 @@ void printToStdErr(const char *Buffer); // EINTR-safe write routine, provided a file descriptor and a character range. -void retryingWriteAll(int Fd, char *Begin, char *End); +void retryingWriteAll(int Fd, const char *Begin, const char *End); // Reads a long long value from a provided file. bool readValueFromFile(const char *Filename, long long *Value); Index: compiler-rt/lib/xray/xray_utils.cc =================================================================== --- compiler-rt/lib/xray/xray_utils.cc +++ compiler-rt/lib/xray/xray_utils.cc @@ -15,11 +15,11 @@ #include "sanitizer_common/sanitizer_common.h" #include "xray_defs.h" #include "xray_flags.h" -#include #include #include #include #include +#include #include #include #include @@ -31,7 +31,7 @@ fprintf(stderr, "%s", Buffer); } -void retryingWriteAll(int Fd, char *Begin, char *End) XRAY_NEVER_INSTRUMENT { +void retryingWriteAll(int Fd, const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT { if (Begin == End) return; auto TotalBytes = std::distance(Begin, End); @@ -94,10 +94,10 @@ int getLogFD() XRAY_NEVER_INSTRUMENT { // Open a temporary file once for the log. - static char TmpFilename[256] = {}; - static char TmpWildcardPattern[] = "XXXXXX"; - auto Argv = GetArgv(); - const char *Progname = Argv[0] == nullptr ? "(unknown)" : Argv[0]; + char TmpFilename[256] = {}; + char TmpWildcardPattern[] = "XXXXXX"; + auto **Argv = GetArgv(); + const char *Progname = !Argv ? "(unknown)" : Argv[0]; const char *LastSlash = internal_strrchr(Progname, '/'); if (LastSlash != nullptr) Index: compiler-rt/test/xray/TestCases/Posix/profiling-multi-threaded.cc =================================================================== --- compiler-rt/test/xray/TestCases/Posix/profiling-multi-threaded.cc +++ compiler-rt/test/xray/TestCases/Posix/profiling-multi-threaded.cc @@ -3,7 +3,13 @@ // // FIXME: Make -fxray-modes=xray-profiling part of the default? // RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiler -// RUN: %run %t +// RUN: rm xray-log.profiling-multi-* || true +// RUN: XRAY_OPTIONS=verbosity=1 \ +// RUN: XRAY_PROFILER_OPTIONS=xray_profiling_no_flush=1 %run %t +// RUN: XRAY_OPTIONS=verbosity=1 %run %t +// RUN: PROFILES=`ls xray-log.profiling-multi-* | wc -l` +// RUN: [ $PROFILES -eq 1 ] +// RUN: rm xray-log.profiling-multi-* || true // // UNSUPPORTED: target-is-mips64,target-is-mips64el Index: compiler-rt/test/xray/TestCases/Posix/profiling-single-threaded.cc =================================================================== --- compiler-rt/test/xray/TestCases/Posix/profiling-single-threaded.cc +++ compiler-rt/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -3,7 +3,13 @@ // // FIXME: Make -fxray-modes=xray-profiling part of the default? // RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiler -// RUN: %run %t +// RUN: rm xray-log.profiling-single-* || true +// RUN: XRAY_OPTIONS=verbosity=1 \ +// RUN: XRAY_PROFILER_OPTIONS=xray_profiling_no_flush=true %run %t +// RUN: XRAY_OPTIONS=verbosity=1 %run %t +// RUN: PROFILES=`ls xray-log.profiling-single-* | wc -l` +// RUN: [ $PROFILES -eq 1 ] +// RUN: rm xray-log.profiling-single-* || true // // UNSUPPORTED: target-is-mips64,target-is-mips64el