Index: include/CMakeLists.txt =================================================================== --- include/CMakeLists.txt +++ include/CMakeLists.txt @@ -12,7 +12,8 @@ sanitizer/tsan_interface_atomic.h) set(XRAY_HEADERS - xray/xray_interface.h) + xray/xray_interface.h + xray/xray_log_interface.h) set(COMPILER_RT_HEADERS ${SANITIZER_HEADERS} Index: include/xray/xray_log_interface.h =================================================================== --- include/xray/xray_log_interface.h +++ include/xray/xray_log_interface.h @@ -48,4 +48,13 @@ } // extern "C" +namespace __xray { +// Options used by the LLVM XRay FDR implementation. +struct FDRLoggingOptions { + bool ReportErrors = false; + int Fd = -1; +}; + +} // namespace __xray + #endif // XRAY_XRAY_LOG_INTERFACE_H Index: lib/xray/xray_fdr_logging.h =================================================================== --- lib/xray/xray_fdr_logging.h +++ lib/xray/xray_fdr_logging.h @@ -26,14 +26,6 @@ // default mode of always writing fixed-size records. namespace __xray { - -// Options used by the FDR implementation. -struct FDRLoggingOptions { - bool ReportErrors = false; - int Fd = -1; -}; - -// Flight Data Recorder mode implementation interfaces. XRayLogInitStatus fdrLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, size_t OptionsSize); XRayLogInitStatus fdrLoggingFinalize(); Index: lib/xray/xray_fdr_logging.cc =================================================================== --- lib/xray/xray_fdr_logging.cc +++ lib/xray/xray_fdr_logging.cc @@ -51,19 +51,18 @@ XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, void *Options, size_t OptionsSize) XRAY_NEVER_INSTRUMENT { - assert(OptionsSize == sizeof(FDRLoggingOptions)); + if (OptionsSize != sizeof(FDRLoggingOptions)) + return static_cast(__sanitizer::atomic_load( + &LoggingStatus, __sanitizer::memory_order_acquire)); s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; - if (__sanitizer::atomic_compare_exchange_strong( + if (!__sanitizer::atomic_compare_exchange_strong( &LoggingStatus, &CurrentStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZING, __sanitizer::memory_order_release)) return static_cast(CurrentStatus); FDROptions.reset(new FDRLoggingOptions()); - *FDROptions = *reinterpret_cast(Options); - if (FDROptions->ReportErrors) - SetPrintfAndReportCallback(printToStdErr); - + memcpy(FDROptions.get(), Options, OptionsSize); bool Success = false; BQ = std::make_shared(BufferSize, BufferMax, Success); if (!Success) { @@ -77,6 +76,7 @@ __sanitizer::atomic_store(&LoggingStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZED, __sanitizer::memory_order_release); + Report("XRay FDR init successful.\n"); return XRayLogInitStatus::XRAY_LOG_INITIALIZED; } @@ -88,7 +88,7 @@ return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; - if (__sanitizer::atomic_compare_exchange_strong( + if (!__sanitizer::atomic_compare_exchange_strong( &LogFlushStatus, &Result, XRayLogFlushStatus::XRAY_LOG_FLUSHING, __sanitizer::memory_order_release)) return static_cast(Result); @@ -140,7 +140,7 @@ XRayLogInitStatus fdrLoggingFinalize() XRAY_NEVER_INSTRUMENT { s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; - if (__sanitizer::atomic_compare_exchange_strong( + if (!__sanitizer::atomic_compare_exchange_strong( &LoggingStatus, &CurrentStatus, XRayLogInitStatus::XRAY_LOG_FINALIZING, __sanitizer::memory_order_release)) @@ -168,8 +168,7 @@ BQ.reset(); // Spin until the flushing status is flushed. - s32 CurrentFlushingStatus = - XRayLogFlushStatus::XRAY_LOG_FLUSHED; + s32 CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; while (__sanitizer::atomic_compare_exchange_weak( &LogFlushStatus, &CurrentFlushingStatus, XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING, Index: lib/xray/xray_log_interface.cc =================================================================== --- lib/xray/xray_log_interface.cc +++ lib/xray/xray_log_interface.cc @@ -35,8 +35,9 @@ *GlobalXRayImpl = Impl; } -XRayLogInitStatus __xray_init(size_t BufferSize, size_t MaxBuffers, void *Args, - size_t ArgsSize) XRAY_NEVER_INSTRUMENT { +XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers, + void *Args, + size_t ArgsSize) XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); if (!GlobalXRayImpl) return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; Index: lib/xray/xray_utils.cc =================================================================== --- lib/xray/xray_utils.cc +++ lib/xray/xray_utils.cc @@ -94,7 +94,6 @@ int getLogFD() XRAY_NEVER_INSTRUMENT { // FIXME: Figure out how to make this less stderr-dependent. - SetPrintfAndReportCallback(printToStdErr); // Open a temporary file once for the log. static char TmpFilename[256] = {}; static char TmpWildcardPattern[] = "XXXXXX"; @@ -119,8 +118,7 @@ TmpFilename); return -1; } - if (Verbosity()) - fprintf(stderr, "XRay: Log file in '%s'\n", TmpFilename); + Report("XRay: Log file in '%s'\n", TmpFilename); return Fd; } Index: test/xray/TestCases/Linux/fdr-mode.cc =================================================================== --- /dev/null +++ test/xray/TestCases/Linux/fdr-mode.cc @@ -0,0 +1,67 @@ +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1" %run %t 2>&1 | FileCheck %s +// FIXME: %llvm_xray convert -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix TRACE +// RUN: rm fdr-logging-test-* + +#include "xray/xray_log_interface.h" +#include +#include +#include +#include +#include +#include +#include + +constexpr auto kBufferSize = 16384; +constexpr auto kBufferMax = 10; + +thread_local uint64_t var = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) fC() { ++var; } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fB() { fC(); } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fA() { fB(); } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fD() { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); +} + +int main(int argc, char *argv[]) { + using namespace __xray; + FDRLoggingOptions Options; + std::cout << "Logging before init." << std::endl; + // CHECK: Logging before init. + auto status = __xray_log_init(kBufferSize, kBufferMax, &Options, + sizeof(FDRLoggingOptions)); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + std::cout << "Init status " << status << std::endl; + // CHECK: Init status {{.*}} + std::cout << "Patching..." << std::endl; + // CHECK: Patching... + __xray_patch(); + fA(); + fC(); + fB(); + fA(); + fC(); + std::thread other_thread([]() { + fC(); + fB(); + fA(); + std::cout << "Thread execution var = " << var << std::endl; + }); + other_thread.join(); + std::cout << "Joined" << std::endl; + // CHECK: Joined + std::cout << "Finalize status " << __xray_log_finalize() << std::endl; + // CHECK: Finalize status {{.*}} + fC(); + std::cout << "Main execution var = " << var << std::endl; + // CHECK: Main execution var = 6 + std::cout << "Flush status " << __xray_log_flushLog() << std::endl; + // CHECK: Flush status {{.*}} + __xray_unpatch(); + return 0; +} + +// TRACE: { function } Index: test/xray/lit.cfg =================================================================== --- test/xray/lit.cfg +++ test/xray/lit.cfg @@ -16,6 +16,9 @@ def build_invocation(compile_flags): return ' ' + ' '.join([config.clang] + compile_flags) + ' ' +# Assume that llvm-xray is in the config.llvm_tools_dir. +llvm_xray = os.path.join(config.llvm_tools_dir, 'llvm-xray') + # Setup substitutions. config.substitutions.append( ('%clang ', build_invocation([config.target_cflags]))) @@ -26,6 +29,8 @@ ('%clang_xray ', build_invocation(clang_xray_cflags))) config.substitutions.append( ('%clangxx_xray', build_invocation(clang_xray_cxxflags))) +config.substitutions.append( + ('%llvm_xray', llvm_xray)) # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp']