Index: lib/xray/CMakeLists.txt =================================================================== --- lib/xray/CMakeLists.txt +++ lib/xray/CMakeLists.txt @@ -10,6 +10,7 @@ # Implementation files for all XRay modes. set(XRAY_FDR_MODE_SOURCES + xray_fdr_flags.cc xray_buffer_queue.cc xray_fdr_logging.cc) Index: lib/xray/xray_fdr_flags.h =================================================================== --- lib/xray/xray_fdr_flags.h +++ lib/xray/xray_fdr_flags.h @@ -0,0 +1,38 @@ +//===-- xray_fdr_flags.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// This file defines the flags for the flight-data-recorder mode implementation. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FDR_FLAGS_H +#define XRAY_FDR_FLAGS_H + +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __xray { + +struct FDRFlags { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "xray_fdr_flags.inc" +#undef XRAY_FLAG + + void setDefaults(); +}; + +extern FDRFlags xray_fdr_flags_dont_use_directly; +extern void registerXRayFDRFlags(FlagParser *P, FDRFlags *F); +const char *useCompilerDefinedFDRFlags(); +inline FDRFlags *fdrFlags() { return &xray_fdr_flags_dont_use_directly; } + +} // namespace __xray + +#endif // XRAY_FDR_FLAGS_H Index: lib/xray/xray_fdr_flags.cc =================================================================== --- lib/xray/xray_fdr_flags.cc +++ lib/xray/xray_fdr_flags.cc @@ -0,0 +1,48 @@ +//===-- xray_fdr_flags.cc ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of XRay, a dynamic runtime instrumentation system. +// +// XRay FDR flag parsing logic. +//===----------------------------------------------------------------------===// + +#include "xray_fdr_flags.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_libc.h" +#include "xray_defs.h" + +using namespace __sanitizer; + +namespace __xray { + +FDRFlags xray_fdr_flags_dont_use_directly; // use via fdrFlags(). + +void FDRFlags::setDefaults() XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; +#include "xray_fdr_flags.inc" +#undef XRAY_FLAG +} + +void registerXRayFDRFlags(FlagParser *P, FDRFlags *F) XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(P, #Name, Description, &F->Name); +#include "xray_fdr_flags.inc" +#undef XRAY_FLAG +} + +const char *useCompilerDefinedFDRFlags() XRAY_NEVER_INSTRUMENT { +#ifdef XRAY_FDR_OPTIONS + return SANITIZER_STRINGIFY(XRAY_FDR_OPTIONS); +#else + return ""; +#endif +} + +} // namespace __xray Index: lib/xray/xray_fdr_flags.inc =================================================================== --- lib/xray/xray_fdr_flags.inc +++ lib/xray/xray_fdr_flags.inc @@ -0,0 +1,27 @@ +//===-- xray_fdr_flags.inc --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// XRay FDR Mode runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FLAG +#error "Define XRAY_FLAG prior to including this file!" +#endif + +// FDR (Flight Data Recorder) Mode logging options. +XRAY_FLAG(int, func_duration_threshold_us, 5, + "FDR logging will try to skip functions that execute for fewer " + "microseconds than this threshold.") +XRAY_FLAG(int, grace_period_ms, 100, + "FDR logging will wait this much time in milliseconds before " + "actually flushing the log; this gives a chance for threads to " + "notice that the log has been finalized and clean up.") +XRAY_FLAG(int, buffer_size, 16384, + "Size of buffers in the circular buffer queue.") +XRAY_FLAG(int, buffer_max, 100, "Maximum number of buffers in the queue.") Index: lib/xray/xray_fdr_logging.cc =================================================================== --- lib/xray/xray_fdr_logging.cc +++ lib/xray/xray_fdr_logging.cc @@ -27,6 +27,7 @@ #include "xray/xray_records.h" #include "xray_buffer_queue.h" #include "xray_defs.h" +#include "xray_fdr_flags.h" #include "xray_fdr_logging_impl.h" #include "xray_flags.h" #include "xray_tsc.h" @@ -72,7 +73,7 @@ // We wait a number of milliseconds to allow threads to see that we've // finalised before attempting to flush the log. - __sanitizer::SleepForMillis(flags()->xray_fdr_log_grace_period_ms); + __sanitizer::SleepForMillis(fdrFlags()->grace_period_ms); // We write out the file in the following format: // @@ -83,8 +84,12 @@ // (fixed-sized) and let the tools reading the buffers deal with the data // afterwards. // + // FIXME: Support the case for letting users handle the data through + // __xray_process_buffers(...) and provide an option to skip writing files. int Fd = -1; { + // FIXME: Remove this section of the code, when we remove the struct-based + // configuration API. __sanitizer::SpinMutexLock Guard(&FDROptionsMutex); Fd = FDROptions.Fd; } @@ -168,33 +173,6 @@ return XRayLogInitStatus::XRAY_LOG_FINALIZED; } -XRayLogInitStatus fdrLoggingReset() XRAY_NEVER_INSTRUMENT { - s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_FINALIZED; - if (__sanitizer::atomic_compare_exchange_strong( - &LoggingStatus, &CurrentStatus, - XRayLogInitStatus::XRAY_LOG_INITIALIZED, - __sanitizer::memory_order_release)) - return static_cast(CurrentStatus); - - // Release the in-memory buffer queue. - delete BQ; - BQ = nullptr; - - // Spin until the flushing status is flushed. - s32 CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; - while (__sanitizer::atomic_compare_exchange_weak( - &LogFlushStatus, &CurrentFlushingStatus, - XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING, - __sanitizer::memory_order_release)) { - if (CurrentFlushingStatus == XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING) - break; - CurrentFlushingStatus = XRayLogFlushStatus::XRAY_LOG_FLUSHED; - } - - // At this point, we know that the status is flushed, and that we can assume - return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; -} - struct TSCAndCPU { uint64_t TSC = 0; unsigned char CPU = 0; @@ -346,16 +324,12 @@ endBufferIfFull(); } -XRayLogInitStatus fdrLoggingInit(std::size_t BufferSize, std::size_t BufferMax, +XRayLogInitStatus fdrLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, size_t OptionsSize) XRAY_NEVER_INSTRUMENT { - if (OptionsSize != sizeof(FDRLoggingOptions)) { - if (__sanitizer::Verbosity()) - Report("Cannot initialize FDR logging; wrong size for options: %d\n", - OptionsSize); - return static_cast(__sanitizer::atomic_load( - &LoggingStatus, __sanitizer::memory_order_acquire)); - } + if (Options == nullptr) + return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; if (!__sanitizer::atomic_compare_exchange_strong( &LoggingStatus, &CurrentStatus, @@ -366,7 +340,56 @@ return static_cast(CurrentStatus); } - { + // Because of __xray_log_init_mode(...) which guarantees that this will be + // called with BufferSize == 0 and BufferMax == 0 we parse the configuration + // provided in the Options pointer as a string instead. + if (BufferSize == 0 && BufferMax == 0) { + if (__sanitizer::Verbosity()) + Report("Initializing FDR mode with options: %s\n", + static_cast(Options)); + + // TODO: Factor out the flags specific to the FDR mode implementation. For + // now, use the global/single definition of the flags, since the FDR mode + // flags are already defined there. + FlagParser FDRParser; + FDRFlags FDRFlags; + registerXRayFDRFlags(&FDRParser, &FDRFlags); + FDRFlags.setDefaults(); + + // Override first from the general XRAY_DEFAULT_OPTIONS compiler-provided + // options until we migrate everyone to use the XRAY_FDR_OPTIONS + // compiler-provided options. + FDRParser.ParseString(useCompilerDefinedFlags()); + FDRParser.ParseString(useCompilerDefinedFDRFlags()); + auto *EnvOpts = GetEnv("XRAY_FDR_OPTIONS"); + if (EnvOpts == nullptr) + EnvOpts = ""; + FDRParser.ParseString(EnvOpts); + FDRParser.ParseString(static_cast(Options)); + *fdrFlags() = FDRFlags; + + BufferSize = FDRFlags.buffer_size; + BufferMax = FDRFlags.buffer_max; + + // FIXME: Remove this when we fully remove the deprecated flags. + if (internal_strlen(EnvOpts) != 0) { + flags()->xray_fdr_log_func_duration_threshold_us = + FDRFlags.func_duration_threshold_us; + flags()->xray_fdr_log_grace_period_ms = FDRFlags.grace_period_ms; + } + } else if (OptionsSize != sizeof(FDRLoggingOptions)) { + // FIXME: This is deprecated, and should really be removed. + // At this point we use the flag parser specific to the FDR mode + // implementation. + if (__sanitizer::Verbosity()) + Report("Cannot initialize FDR logging; wrong size for options: %d\n", + OptionsSize); + return static_cast(__sanitizer::atomic_load( + &LoggingStatus, __sanitizer::memory_order_acquire)); + } else { + if (__sanitizer::Verbosity()) + Report("XRay FDR: struct-based init is deprecated, please use " + "string-based configuration instead.\n"); __sanitizer::SpinMutexLock Guard(&FDROptionsMutex); memcpy(&FDROptions, Options, OptionsSize); } Index: lib/xray/xray_flags.h =================================================================== --- lib/xray/xray_flags.h +++ lib/xray/xray_flags.h @@ -29,6 +29,8 @@ }; extern Flags xray_flags_dont_use_directly; +extern void registerXRayFlags(FlagParser *P, Flags *F); +const char *useCompilerDefinedFlags(); inline Flags *flags() { return &xray_flags_dont_use_directly; } void initializeFlags(); Index: lib/xray/xray_flags.cc =================================================================== --- lib/xray/xray_flags.cc +++ lib/xray/xray_flags.cc @@ -30,7 +30,7 @@ #undef XRAY_FLAG } -static void registerXRayFlags(FlagParser *P, Flags *F) XRAY_NEVER_INSTRUMENT { +void registerXRayFlags(FlagParser *P, Flags *F) XRAY_NEVER_INSTRUMENT { #define XRAY_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(P, #Name, Description, &F->Name); #include "xray_flags.inc" @@ -42,12 +42,13 @@ // options that control XRay. This means users/deployments can tweak the // defaults that override the hard-coded defaults in the xray_flags.inc at // compile-time using the XRAY_DEFAULT_OPTIONS macro. -static const char *useCompilerDefinedFlags() XRAY_NEVER_INSTRUMENT { +const char *useCompilerDefinedFlags() XRAY_NEVER_INSTRUMENT { #ifdef XRAY_DEFAULT_OPTIONS -// Do the double-layered string conversion to prevent badly crafted strings -// provided through the XRAY_DEFAULT_OPTIONS from causing compilation issues (or -// changing the semantics of the implementation through the macro). This ensures -// that we convert whatever XRAY_DEFAULT_OPTIONS is defined as a string literal. + // Do the double-layered string conversion to prevent badly crafted strings + // provided through the XRAY_DEFAULT_OPTIONS from causing compilation issues + // (or changing the semantics of the implementation through the macro). This + // ensures that we convert whatever XRAY_DEFAULT_OPTIONS is defined as a + // string literal. return SANITIZER_STRINGIFY(XRAY_DEFAULT_OPTIONS); #else return ""; Index: lib/xray/xray_flags.inc =================================================================== --- lib/xray/xray_flags.inc +++ lib/xray/xray_flags.inc @@ -39,11 +39,11 @@ XRAY_FLAG(bool, xray_fdr_log, false, "DEPRECATED: Use xray_mode=xray-fdr instead.") XRAY_FLAG(int, xray_fdr_log_func_duration_threshold_us, 5, - "FDR logging will try to skip functions that execute for fewer " - "microseconds than this threshold.") + "DEPRECATED: use the environment variable XRAY_FDR_OPTIONS and set " + "func_duration_threshold_us instead.") XRAY_FLAG(int, xray_fdr_log_grace_period_us, 0, - "DEPRECATED: use xray_fdr_log_grace_period_ms instead.") + "DEPRECATED: use the environment variable XRAY_FDR_OPTIONS and set " + "grace_period_ms instead.") XRAY_FLAG(int, xray_fdr_log_grace_period_ms, 100, - "FDR logging will wait this much time in microseconds before " - "actually flushing the log; this gives a chance for threads to " - "notice that the log has been finalized and clean up.") + "DEPRECATED: use the environment variable XRAY_FDR_OPTIONS and set " + "grace_period_ms instead.") Index: test/xray/TestCases/Posix/fdr-mode.cc =================================================================== --- test/xray/TestCases/Posix/fdr-mode.cc +++ test/xray/TestCases/Posix/fdr-mode.cc @@ -1,10 +1,21 @@ // RUN: %clangxx_xray -g -std=c++11 %s -o %t // RUN: rm fdr-logging-test-* || true // RUN: rm fdr-unwrite-test-* || true -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-logging-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | FileCheck %s -// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false xray_logfile_base=fdr-unwrite-test- xray_fdr_log=true verbosity=1 xray_fdr_log_func_duration_threshold_us=5000" %run %t 2>&1 | FileCheck %s -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-logging-test-* | head -1`" | FileCheck %s --check-prefix=TRACE -// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t "`ls fdr-unwrite-test-* | head -1`" | FileCheck %s --check-prefix=UNWRITE +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-logging-test- \ +// RUN: xray_mode=xray-fdr verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="func_duration_threshold_us=0" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: XRAY_OPTIONS="patch_premain=false \ +// RUN: xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr \ +// RUN: verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="func_duration_threshold_us=5000" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-logging-test-* | head -1`" \ +// RUN: | FileCheck %s --check-prefix=TRACE +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-unwrite-test-* | head -1`" \ +// RUN: | FileCheck %s --check-prefix=UNWRITE // RUN: rm fdr-logging-test-* // RUN: rm fdr-unwrite-test-* // FIXME: Make llvm-xray work on non-x86_64 as well. @@ -20,9 +31,6 @@ #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; } @@ -35,11 +43,12 @@ 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(__xray_log_select_mode("xray-fdr") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + auto status = + __xray_log_init_mode("xray-fdr", "buffer_size=16384:buffer_max=10"); assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); std::cout << "Init status " << status << std::endl; // CHECK: Init status {{.*}}