Index: compiler-rt/include/xray/xray_log_interface.h =================================================================== --- compiler-rt/include/xray/xray_log_interface.h +++ compiler-rt/include/xray/xray_log_interface.h @@ -21,27 +21,27 @@ /// /// The high-level usage pattern for these APIs look like the following: /// -/// // Before we try initializing the log implementation, we must set it as -/// // the log implementation. We provide the function pointers that define -/// // the various initialization, finalization, and other pluggable hooks -/// // that we need. -/// __xray_set_log_impl({...}); -/// -/// // Once that's done, we can now initialize the implementation. Each -/// // implementation has a chance to let users customize the implementation -/// // with a struct that their implementation supports. Roughly this might -/// // look like: -/// MyImplementationOptions opts; -/// opts.enable_feature = true; -/// ... -/// auto init_status = __xray_log_init( -/// BufferSize, MaxBuffers, &opts, sizeof opts); -/// if (init_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { +/// // We choose the mode which we'd like to install, and check whether this +/// // has succeeded. +/// auto select_status = __xray_log_select_mode("xray-fdr"); +/// if (select_status != XRayLogRegisterStatus::XRAY_REGISTRATION_OK) { +/// // This failed, we should not proceed with attempting to initialise +/// // the currently selected mode. +/// return; +/// } +/// +/// // Once that's done, we can now attempt to configure the implementation. +/// // To do this, we provide the string flags configuration for the mode. +/// auto config_status = __xray_log_init_mode( +/// "xray-fdr", "verbosity=1 some_flag=1 another_flag=2"); +/// if (config_status != XRayLogInitStatus::XRAY_LOG_INITIALIZED) { /// // deal with the error here, if there is one. /// } /// /// // When the log implementation has had the chance to initialize, we can -/// // now patch the sleds. +/// // now patch the instrumentation points. Note that we could have patched +/// // the instrumentation sleds first, but there's no strict ordering to +/// // these operations. /// auto patch_status = __xray_patch(); /// if (patch_status != XRayPatchingStatus::SUCCESS) { /// // deal with the error here, if it is an error. @@ -60,8 +60,8 @@ /// // runtime. /// auto unpatch_status = __xray_unpatch(); /// if (unpatch_status != XRayPatchingStatus::SUCCESS) { -// // deal with the error here, if it is an error. -// } +/// // deal with the error here, if it is an error. +/// } /// /// // If there are logs or data to be flushed somewhere, we can do so only /// // after we've finalized the log. Some implementations may not actually @@ -193,6 +193,10 @@ XRayLogFlushStatus (*flush_log)(); }; +/// DEPRECATED: Use the mode registration workflow instead with +/// __xray_log_register_mode(...) and __xray_log_select_mode(...). See the +/// documentation for those function. +/// /// This function installs a new logging implementation that XRay will use. In /// case there are any nullptr members in Impl, XRay will *uninstall any /// existing implementations*. It does NOT patch the instrumentation sleds. @@ -260,11 +264,30 @@ /// called while in any other states. void __xray_remove_log_impl(); +/// DEPRECATED: Use __xray_log_init_mode() instead, and provide all the options +/// in string form. /// Invokes the installed implementation initialization routine. See /// XRayLogInitStatus for what the return values mean. XRayLogInitStatus __xray_log_init(size_t BufferSize, size_t MaxBuffers, void *Args, size_t ArgsSize); +/// Invokes the installed initialization routine, which *must* support the +/// string based form. +/// +/// NOTE: When this API is used, we still invoke the installed initialization +/// routine, but we will call it with the following convention to signal that we +/// are using the string form: +/// +/// - BufferSize = 0 +/// - MaxBuffers = std::numeric_limit::max() +/// - ArgsSize = 0 +/// - Args will be the pointer to the null-terminated character buffer +/// representing the configuration. +/// +/// FIXME: Updating the XRayLogImpl struct is an ABI breaking change. When we +/// are ready to make a breaking change, we should clean this up appropriately. +XRayLogInitStatus __xray_log_init_mode(const char* Mode, const char* Config); + /// Invokes the installed implementation finalization routine. See /// XRayLogInitStatus for what the return values mean. XRayLogInitStatus __xray_log_finalize(); @@ -325,12 +348,16 @@ namespace __xray { +/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag +/// configuration strings to set the options instead. /// Options used by the LLVM XRay FDR logging implementation. struct FDRLoggingOptions { bool ReportErrors = false; int Fd = -1; }; +/// DEPRECATED: Use __xray_log_init_mode(...) instead, and provide flag +/// configuration strings to set the options instead. /// Options used by the LLVM XRay Basic (Naive) logging implementation. struct BasicLoggingOptions { int DurationFilterMicros = 0; Index: compiler-rt/lib/xray/xray_log_interface.cc =================================================================== --- compiler-rt/lib/xray/xray_log_interface.cc +++ compiler-rt/lib/xray/xray_log_interface.cc @@ -139,6 +139,23 @@ return GlobalXRayImpl->log_init(BufferSize, MaxBuffers, Args, ArgsSize); } +XRayLogInitStatus __xray_log_init_mode(const char *Mode, const char *Config) + XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayImplMutex); + if (!GlobalXRayImpl) + return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + + // Check first whether the current mode is the same as what we expect. + if (CurrentMode == nullptr || internal_strcmp(CurrentMode->Mode, Mode) != 0) + return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + + // Here we do some work to coerce the pointer we're provided, so that + // the implementations that still take void* pointers can handle the + // data provided in the Config argument. + return GlobalXRayImpl->log_init( + 0, 0, const_cast(static_cast(Config)), 0); +} + XRayLogInitStatus __xray_log_finalize() XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayImplMutex); if (!GlobalXRayImpl) Index: compiler-rt/test/xray/TestCases/Posix/logging-modes.cc =================================================================== --- compiler-rt/test/xray/TestCases/Posix/logging-modes.cc +++ compiler-rt/test/xray/TestCases/Posix/logging-modes.cc @@ -1,6 +1,7 @@ // Check that we can install an implementation associated with a mode. // -// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: rm xray-log.logging-modes* || true +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=none // RUN: %run %t | FileCheck %s // // UNSUPPORTED: target-is-mips64,target-is-mips64el @@ -32,7 +33,15 @@ } [[clang::xray_never_instrument]] XRayLogInitStatus -printing_init(size_t, size_t, void *, size_t) { +printing_init(size_t BufferSize, size_t MaxBuffers, void *Config, + size_t ArgsSize) { + // We require that the printing init is called through the + // __xray_log_init_mode(...) implementation, and that the promised contract is + // enforced. + assert(BufferSize == 0); + assert(MaxBuffers == 0); + assert(Config != nullptr); + assert(ArgsSize == 0); __xray_log_set_buffer_iterator(next_buffer); return XRayLogInitStatus::XRAY_LOG_INITIALIZED; } @@ -48,26 +57,22 @@ [[clang::xray_always_instrument]] void callme() { std::printf("called me!\n"); } -static auto buffer_counter = 0; +static auto volatile buffer_counter = 0; void process_buffer(const char *, XRayBuffer) { ++buffer_counter; } -static bool unused = [] { +int main(int argc, char **argv) { assert(__xray_log_register_mode("custom", {printing_init, printing_finalize, printing_handler, printing_flush_log}) == XRayLogRegisterStatus::XRAY_REGISTRATION_OK); - return true; -}(); - -int main(int argc, char **argv) { assert(__xray_log_select_mode("custom") == XRayLogRegisterStatus::XRAY_REGISTRATION_OK); assert(__xray_log_get_current_mode() != nullptr); std::string current_mode = __xray_log_get_current_mode(); assert(current_mode == "custom"); assert(__xray_patch() == XRayPatchingStatus::SUCCESS); - assert(__xray_log_init(0, 0, nullptr, 0) == + assert(__xray_log_init_mode("custom", "flags_config_here=true") == XRayLogInitStatus::XRAY_LOG_INITIALIZED); // CHECK: printing {{.*}} callme(); // CHECK: called me! Index: llvm/docs/XRay.rst =================================================================== --- llvm/docs/XRay.rst +++ llvm/docs/XRay.rst @@ -171,20 +171,6 @@ | xray_logfile_base | ``const char*`` | ``xray-log.`` | Filename base for the | | | | | XRay logfile. | +-------------------+-----------------+---------------+------------------------+ -| xray_naive_log | ``bool`` | ``false`` | **DEPRECATED:** Use | -| | | | xray_mode=xray-basic | -| | | | instead. Whether to | -| | | | install the basic log | -| | | | the naive log | -| | | | implementation. | -+-------------------+-----------------+---------------+------------------------+ -| xray_fdr_log | ``bool`` | ``false`` | **DEPRECATED:** Use | -| | | | xray_mode=xray-fdr | -| | | | instead. Whether to | -| | | | install the Flight | -| | | | Data Recorder | -| | | | (FDR) mode. | -+-------------------+-----------------+---------------+------------------------+ | verbosity | ``int`` | ``0`` | Runtime verbosity | | | | | level. | +-------------------+-----------------+---------------+------------------------+ @@ -193,30 +179,45 @@ If you choose to not use the default logging implementation that comes with the XRay runtime and/or control when/how the XRay instrumentation runs, you may use the XRay APIs directly for doing so. To do this, you'll need to include the -``xray_interface.h`` from the compiler-rt ``xray`` directory. The important API +``xray_log_interface.h`` from the compiler-rt ``xray`` directory. The important API functions we list below: -- ``__xray_set_handler(void (*entry)(int32_t, XRayEntryType))``: Install your - own logging handler for when an event is encountered. See - ``xray/xray_interface.h`` for more details. -- ``__xray_remove_handler()``: Removes whatever the installed handler is. -- ``__xray_patch()``: Patch all the instrumentation points defined in the - binary. -- ``__xray_unpatch()``: Unpatch the instrumentation points defined in the - binary. - -There are some requirements on the logging handler to be installed for the -thread-safety of operations to be performed by the XRay runtime library: - -- The function should be thread-safe, as multiple threads may be invoking the - function at the same time. If the logging function needs to do - synchronisation, it must do so internally as XRay does not provide any - synchronisation guarantees outside from the atomicity of updates to the - pointer. -- The pointer provided to ``__xray_set_handler(...)`` must be live even after - calls to ``__xray_remove_handler()`` and ``__xray_unpatch()`` have succeeded. - XRay cannot guarantee that all threads that have ever gotten a copy of the - pointer will not invoke the function. +- ``__xray_log_register_mode(...)``: Register a logging implementation against + a string Mode identifier. The implementation is an instance of + ``XRayLogImpl`` defined in ``xray/xray_log_interface.h``. +- ``__xray_log_select_mode(...)``: Select the mode to install, associated with + a string Mode identifier. Only implementations registered with + ``__xray_log_register_mode(...)`` can be chosen with this function. +- ``__xray_log_init_mode(...)``: This function allows for initializing and + re-initializing an installed logging implementation. See + ``xray/xray_log_interface.h`` for details, part of the XRay compiler-rt + installation. + +Once a logging implementation has been initialized, it can be "stopped" by +finalizing the implementation through the ``__xray_log_finalize()`` function. +The finalization routine is the opposite of the initialization. When finalized, +an implementation's data can be cleared out through the +``__xray_log_flushLog()`` function. For implementations that support in-memory +processing, these should register an iterator function to provide access to the +data via the ``__xray_log_set_buffer_iterator(...)`` which allows code calling +the ``__xray_log_process_buffers(...)`` function to deal with the data in +memory. + +All of this is better explained in the ``xray/xray_log_interface.h`` header. + +Basic Mode +---------- + +XRay supports a basic logging mode which will trace the application's +execution, and periodically append to a single log. This mode can be +installed/enabled by setting ``xray_mode=xray-basic`` in the ``XRAY_OPTIONS`` +environment variable. Combined with ``patch_premain=true`` this can allow for +tracing applications from start to end. + +Like all the other modes installed through ``__xray_log_select_mode(...)``, the +implementation can be configured through the ``__xray_log_init_mode(...)`` +function, providing the mode string and the flag options. Basic-mode specific +defaults can be provided in the ``XRAY_BASIC_OPTIONS`` environment variable. Flight Data Recorder Mode ------------------------- @@ -226,9 +227,12 @@ very much like a plane's "black box" which keeps recording data to memory in a fixed-size circular queue of buffers, and have the data available programmatically until the buffers are finalized and flushed. To use FDR mode -on your application, you may set the ``xray_fdr_log`` option to ``true`` in the -``XRAY_OPTIONS`` environment variable (while also optionally setting the -``xray_naive_log`` to ``false``). +on your application, you may set the ``xray_mode`` variable to ``xray-fdr`` in +the ``XRAY_OPTIONS`` environment variable. Additional options to the FDR mode +implementation can be provided in the ``XRAY_FDR_OPTIONS`` environment +variable. Programmatic configuration can be done by calling +``__xray_log_init_mode("xray-fdr", )`` once it has been +selected/installed. When the buffers are flushed to disk, the result is a binary trace format described by `XRay FDR format `_ @@ -260,34 +264,15 @@ } The default settings for the FDR mode implementation will create logs named -similarly to the naive log implementation, but will have a different log +similarly to the basic log implementation, but will have a different log format. All the trace analysis tools (and the trace reading library) will support all versions of the FDR mode format as we add more functionality and record types in the future. - **NOTE:** We do not however promise perpetual support for when we update the - log versions we support going forward. Deprecation of the formats will be + **NOTE:** We do not promise perpetual support for when we update the log + versions we support going forward. Deprecation of the formats will be announced and discussed on the developers mailing list. -XRay allows for replacing the default FDR mode logging implementation using the -following API: - -- ``__xray_set_log_impl(...)``: This function takes a struct of type - ``XRayLogImpl``, which is defined in ``xray/xray_log_interface.h``, part of - the XRay compiler-rt installation. -- ``__xray_log_register_mode(...)``: Register a logging implementation against - a string Mode. The implementation is an instance of ``XRayLogImpl`` defined - in ``xray/xray_log_interface.h``. -- ``__xray_log_select_mode(...)``: Select the mode to install, associated with - a string Mode. Only implementations registered with - ``__xray_log_register_mode(...)`` can be chosen with this function. When - successful, has the same effects as calling ``__xray_set_log_impl(...)`` with - the registered logging implementation. -- ``__xray_log_init(...)``: This function allows for initializing and - re-initializing an installed logging implementation. See - ``xray/xray_log_interface.h`` for details, part of the XRay compiler-rt - installation. - Trace Analysis Tools -------------------- @@ -301,7 +286,7 @@ options for sorting, and output formats (supports CSV, YAML, and console-friendly TEXT). - ``convert``: Converts an XRay log file from one format to another. We can - convert from binary XRay traces (both naive and FDR mode) to YAML, + convert from binary XRay traces (both basic and FDR mode) to YAML, `flame-graph `_ friendly text formats, as well as `Chrome Trace Viewer (catapult) ` formats.