Index: compiler-rt/lib/xray/CMakeLists.txt =================================================================== --- compiler-rt/lib/xray/CMakeLists.txt +++ compiler-rt/lib/xray/CMakeLists.txt @@ -18,9 +18,10 @@ xray_basic_flags.cc xray_basic_logging.cc) -set(XRAY_PROFILER_MODE_SOURCES +set(XRAY_PROFILING_MODE_SOURCES xray_profile_collector.cc - xray_profiler_flags.cc) + xray_profiling.cc + xray_profiling_flags.cc) # Implementation files for all XRay architectures. set(x86_64_SOURCES @@ -101,10 +102,10 @@ SOURCES ${XRAY_BASIC_MODE_SOURCES} CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(RTXrayPROFILER + add_compiler_rt_object_libraries(RTXrayPROFILING OS ${XRAY_SUPPORTED_OS} ARCHS ${XRAY_SUPPORTED_ARCH} - SOURCES ${XRAY_PROFILER_MODE_SOURCES} + SOURCES ${XRAY_PROFILING_MODE_SOURCES} CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS}) @@ -141,11 +142,11 @@ LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} LINK_LIBS ${XRAY_LINK_LIBS} PARENT_TARGET xray) - add_compiler_rt_runtime(clang_rt.xray-profiler + add_compiler_rt_runtime(clang_rt.xray-profiling STATIC OS ${XRAY_SUPPORTED_OS} ARCHS ${XRAY_SUPPORTED_ARCH} - OBJECT_LIBS RTXrayPROFILER + OBJECT_LIBS RTXrayPROFILING CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS} LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} @@ -168,9 +169,9 @@ ARCHS ${arch} SOURCES ${XRAY_BASIC_MODE_SOURCES} CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(RTXrayPROFILER + add_compiler_rt_object_libraries(RTXrayPROFILING ARCHS ${arch} - SOURCES ${XRAY_PROFILER_MODE_SOURCES} CFLAGS ${XRAY_CFLAGS} + SOURCES ${XRAY_PROFILING_MODE_SOURCES} CFLAGS ${XRAY_CFLAGS} DEFS ${XRAY_COMMON_DEFINITIONS}) # Common XRay archive for instrumented binaries. @@ -197,13 +198,14 @@ DEFS ${XRAY_COMMON_DEFINITIONS} OBJECT_LIBS RTXrayBASIC PARENT_TARGET xray) - add_compiler_rt_runtime(clang_rt.xray-profiler - STATIC - ARCHS ${arch} - CFLAGS ${XRAY_CFLAGS} - DEFS ${XRAY_COMMON_DEFINITIONS} - OBJECT_LIBS RTXrayPROFILER - PARENT_TARGET xray) + # Profiler Mode runtime + add_compiler_rt_runtime(clang_rt.xray-profiling + STATIC + ARCHS ${arch} + CFLAGS ${XRAY_CFLAGS} + DEFS ${XRAY_COMMON_DEFINITIONS} + OBJECT_LIBS RTXrayPROFILING + PARENT_TARGET xray) endforeach() endif() # not Apple Index: compiler-rt/lib/xray/tests/CMakeLists.txt =================================================================== --- compiler-rt/lib/xray/tests/CMakeLists.txt +++ compiler-rt/lib/xray/tests/CMakeLists.txt @@ -72,7 +72,7 @@ add_xray_lib("RTXRay.test.osx" $ $ - $ + $ $ $) else() @@ -80,7 +80,7 @@ add_xray_lib("RTXRay.test.${arch}" $ $ - $ + $ $ $) endforeach() Index: compiler-rt/lib/xray/tests/unit/function_call_trie_test.cc =================================================================== --- compiler-rt/lib/xray/tests/unit/function_call_trie_test.cc +++ compiler-rt/lib/xray/tests/unit/function_call_trie_test.cc @@ -27,13 +27,13 @@ TEST(FunctionCallTrieTest, ConstructWithTLSAllocators) { // FIXME: Support passing in configuration for allocators in the allocator // constructors. - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); FunctionCallTrie::Allocators Allocators = FunctionCallTrie::InitAllocators(); FunctionCallTrie Trie(Allocators); } TEST(FunctionCallTrieTest, EnterAndExitFunction) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); auto A = FunctionCallTrie::InitAllocators(); FunctionCallTrie Trie(A); @@ -71,7 +71,7 @@ } TEST(FunctionCallTrieTest, MultipleRoots) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); auto A = FunctionCallTrie::InitAllocators(); FunctionCallTrie Trie(A); @@ -114,7 +114,7 @@ // accounting local time to `f2` from d = (t3 - t2), then local time to `f1` // as d' = (t3 - t1) - d, and then local time to `f0` as d'' = (t3 - t0) - d'. TEST(FunctionCallTrieTest, MissingIntermediaryExit) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); auto A = FunctionCallTrie::InitAllocators(); FunctionCallTrie Trie(A); @@ -156,7 +156,7 @@ // TODO: Test that we can handle cross-CPU migrations, where TSCs are not // guaranteed to be synchronised. TEST(FunctionCallTrieTest, DeepCopy) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); auto A = FunctionCallTrie::InitAllocators(); FunctionCallTrie Trie(A); @@ -197,7 +197,7 @@ } TEST(FunctionCallTrieTest, MergeInto) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); auto A = FunctionCallTrie::InitAllocators(); FunctionCallTrie T0(A); FunctionCallTrie T1(A); Index: compiler-rt/lib/xray/tests/unit/profile_collector_test.cc =================================================================== --- compiler-rt/lib/xray/tests/unit/profile_collector_test.cc +++ compiler-rt/lib/xray/tests/unit/profile_collector_test.cc @@ -13,7 +13,7 @@ #include "gtest/gtest.h" #include "xray_profile_collector.h" -#include "xray_profiler_flags.h" +#include "xray_profiling_flags.h" #include #include #include @@ -25,7 +25,7 @@ static constexpr auto kHeaderSize = 16u; void ValidateBlock(XRayBuffer B) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); ASSERT_NE(static_cast(B.Data), nullptr); ASSERT_NE(B.Size, 0u); ASSERT_GE(B.Size, kHeaderSize); @@ -84,7 +84,7 @@ } TEST(profileCollectorServiceTest, PostSerializeCollect) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); // The most basic use-case (the one we actually only care about) is the one // where we ensure that we can post FunctionCallTrie instances, which are then // destroyed but serialized properly. @@ -157,7 +157,7 @@ } TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) { - profilerFlags()->setDefaults(); + profilingFlags()->setDefaults(); std::thread t1(threadProcessing); std::thread t2(threadProcessing); Index: compiler-rt/lib/xray/xray_function_call_trie.h =================================================================== --- compiler-rt/lib/xray/xray_function_call_trie.h +++ compiler-rt/lib/xray/xray_function_call_trie.h @@ -15,7 +15,7 @@ #ifndef XRAY_FUNCTION_CALL_TRIE_H #define XRAY_FUNCTION_CALL_TRIE_H -#include "xray_profiler_flags.h" +#include "xray_profiling_flags.h" #include "xray_segmented_array.h" #include #include // For placement new. @@ -223,26 +223,26 @@ auto NodeAllocator = reinterpret_cast( InternalAlloc(sizeof(Allocators::NodeAllocatorType))); new (NodeAllocator) Allocators::NodeAllocatorType( - profilerFlags()->per_thread_allocator_max, 0); + profilingFlags()->per_thread_allocator_max, 0); A.NodeAllocator = NodeAllocator; auto RootAllocator = reinterpret_cast( InternalAlloc(sizeof(Allocators::RootAllocatorType))); new (RootAllocator) Allocators::RootAllocatorType( - profilerFlags()->per_thread_allocator_max, 0); + profilingFlags()->per_thread_allocator_max, 0); A.RootAllocator = RootAllocator; auto ShadowStackAllocator = reinterpret_cast( InternalAlloc(sizeof(Allocators::ShadowStackAllocatorType))); new (ShadowStackAllocator) Allocators::ShadowStackAllocatorType( - profilerFlags()->per_thread_allocator_max, 0); + profilingFlags()->per_thread_allocator_max, 0); A.ShadowStackAllocator = ShadowStackAllocator; auto NodeIdPairAllocator = reinterpret_cast( InternalAlloc(sizeof(NodeIdPairAllocatorType))); new (NodeIdPairAllocator) - NodeIdPairAllocatorType(profilerFlags()->per_thread_allocator_max, 0); + NodeIdPairAllocatorType(profilingFlags()->per_thread_allocator_max, 0); A.NodeIdPairAllocator = NodeIdPairAllocator; return A; } @@ -360,7 +360,7 @@ using Stack = Array; typename Stack::AllocatorType StackAllocator( - profilerFlags()->stack_allocator_max, 0); + profilingFlags()->stack_allocator_max, 0); Stack DFSStack(StackAllocator); // TODO: Figure out what to do if we fail to allocate any more stack @@ -398,7 +398,7 @@ }; using Stack = Array; typename Stack::AllocatorType StackAllocator( - profilerFlags()->stack_allocator_max, 0); + profilingFlags()->stack_allocator_max, 0); Stack DFSStack(StackAllocator); for (const auto Root : getRoots()) { 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 @@ -15,7 +15,7 @@ #include "xray_profile_collector.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_vector.h" -#include "xray_profiler_flags.h" +#include "xray_profiling_flags.h" #include #include #include @@ -128,7 +128,7 @@ const FunctionCallTrie &Trie) { using StackArray = Array; using StackAllocator = typename StackArray::AllocatorType; - StackAllocator StackAlloc(profilerFlags()->stack_allocator_max, 0); + StackAllocator StackAlloc(profilingFlags()->stack_allocator_max, 0); StackArray DFSStack(StackAlloc); for (const auto R : Trie.getRoots()) { DFSStack.Append(R); @@ -198,9 +198,9 @@ // Then repopulate the global ProfileBuffers. for (u32 I = 0; I < ThreadTries.Size(); ++I) { using ProfileRecordAllocator = typename ProfileRecordArray::AllocatorType; - ProfileRecordAllocator PRAlloc(profilerFlags()->global_allocator_max, 0); + ProfileRecordAllocator PRAlloc(profilingFlags()->global_allocator_max, 0); ProfileRecord::PathAllocator PathAlloc( - profilerFlags()->global_allocator_max, 0); + profilingFlags()->global_allocator_max, 0); ProfileRecordArray ProfileRecords(PRAlloc); // First, we want to compute the amount of space we're going to need. We'll Index: compiler-rt/lib/xray/xray_profiling.cc =================================================================== --- /dev/null +++ compiler-rt/lib/xray/xray_profiling.cc @@ -0,0 +1,298 @@ +//===-- xray_profiling.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. +// +// This is the implementation of a profiling handler. +// +//===----------------------------------------------------------------------===// +#include + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" + +#include "xray_flags.h" +#include "xray_profile_collector.h" +#include "xray_profiling_flags.h" +#include "xray_tsc.h" +#include "xray_utils.h" +#include + +namespace __xray { + +namespace { + +__sanitizer::atomic_sint32_t ProfilerLogFlushStatus = { + XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; + +__sanitizer::atomic_sint32_t ProfilerLogStatus = { + XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; + +__sanitizer::SpinMutex ProfilerOptionsMutex; + +struct alignas(64) ProfilingData { + FunctionCallTrie::Allocators *Allocators = nullptr; + FunctionCallTrie *FCT = nullptr; +}; + +static pthread_key_t ProfilingKey; + +ProfilingData &getThreadLocalData() XRAY_NEVER_INSTRUMENT { + thread_local std::aligned_storage::type ThreadStorage; + if (pthread_getspecific(ProfilingKey) == NULL) { + new (&ThreadStorage) ProfilingData{}; + pthread_setspecific(ProfilingKey, &ThreadStorage); + } + + auto &TLD = *reinterpret_cast(&ThreadStorage); + + // We need to check whether the global flag to finalizing/finalized has been + // switched. If it is, then we ought to not actually initialise the data. + auto Status = __sanitizer::atomic_load(&ProfilerLogStatus, + __sanitizer::memory_order_acquire); + if (Status == XRayLogInitStatus::XRAY_LOG_FINALIZING || + Status == XRayLogInitStatus::XRAY_LOG_FINALIZED) + return TLD; + + // If we're live, then we re-initialize TLD if the pointers are not null. + if (UNLIKELY(TLD.Allocators == nullptr && TLD.FCT == nullptr)) { + TLD.Allocators = reinterpret_cast( + InternalAlloc(sizeof(FunctionCallTrie::Allocators))); + new (TLD.Allocators) FunctionCallTrie::Allocators(); + *TLD.Allocators = FunctionCallTrie::InitAllocators(); + TLD.FCT = reinterpret_cast( + InternalAlloc(sizeof(FunctionCallTrie))); + new (TLD.FCT) FunctionCallTrie(*TLD.Allocators); + } + + return TLD; +} + +} // namespace + +const char *profilingCompilerDefinedFlags() XRAY_NEVER_INSTRUMENT { +#ifdef XRAY_PROFILER_DEFAULT_OPTIONS + return SANITIZER_STRINGIFY(XRAY_PROFILER_DEFAULT_OPTIONS); +#else + return ""; +#endif +} + +__sanitizer::atomic_sint32_t ProfileFlushStatus = { + 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) { + if (__sanitizer::Verbosity()) + Report("Not flushing profiles, profiling not been finalized.\n"); + return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; + } + + s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; + if (!__sanitizer::atomic_compare_exchange_strong( + &ProfilerLogFlushStatus, &Result, + XRayLogFlushStatus::XRAY_LOG_FLUSHING, + __sanitizer::memory_order_acq_rel)) { + if (__sanitizer::Verbosity()) + Report("Not flushing profiles, implementation still finalizing.\n"); + } + + profileCollectorService::reset(); + + __sanitizer::atomic_store(&ProfilerLogStatus, + XRayLogFlushStatus::XRAY_LOG_FLUSHED, + __sanitizer::memory_order_release); + + return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +} + +namespace { + +thread_local volatile bool ReentranceGuard = false; + +void postCurrentThreadFCT(ProfilingData &TLD) { + if (TLD.Allocators == nullptr || TLD.FCT == nullptr) + return; + + profileCollectorService::post(*TLD.FCT, GetTid()); + TLD.FCT->~FunctionCallTrie(); + TLD.Allocators->~Allocators(); + InternalFree(TLD.FCT); + InternalFree(TLD.Allocators); + TLD.FCT = nullptr; + TLD.Allocators = nullptr; +} + +} // namespace + +void profilingHandleArg0(int32_t FuncId, + XRayEntryType Entry) XRAY_NEVER_INSTRUMENT { + unsigned char CPU; + auto TSC = readTSC(CPU); + if (ReentranceGuard) + return; + ReentranceGuard = true; + + auto Status = __sanitizer::atomic_load(&ProfilerLogStatus, + __sanitizer::memory_order_acquire); + auto &TLD = getThreadLocalData(); + if (UNLIKELY(Status == XRayLogInitStatus::XRAY_LOG_FINALIZED || + Status == XRayLogInitStatus::XRAY_LOG_FINALIZING)) { + postCurrentThreadFCT(TLD); + ReentranceGuard = false; + return; + } + + switch (Entry) { + case XRayEntryType::ENTRY: + case XRayEntryType::LOG_ARGS_ENTRY: + TLD.FCT->enterFunction(FuncId, TSC); + break; + case XRayEntryType::EXIT: + case XRayEntryType::TAIL: + TLD.FCT->exitFunction(FuncId, TSC); + break; + default: + // FIXME: Handle bugs. + break; + } + + ReentranceGuard = false; +} + +void profilingHandleArg1(int32_t FuncId, XRayEntryType Entry, + uint64_t) XRAY_NEVER_INSTRUMENT { + return profilingHandleArg0(FuncId, Entry); +} + +XRayLogInitStatus profilingFinalize() XRAY_NEVER_INSTRUMENT { + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_INITIALIZED; + if (!__sanitizer::atomic_compare_exchange_strong( + &ProfilerLogStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_FINALIZING, + __sanitizer::memory_order_release)) { + if (__sanitizer::Verbosity()) + Report("Cannot finalize profile, the profiling is not initialized.\n"); + return static_cast(CurrentStatus); + } + + // Wait a grace period to allow threads to see that we're finalizing. + __sanitizer::SleepForMillis(profilingFlags()->grace_period_ms); + + // We also want to make sure that the current thread's data is cleaned up, + // if we have any. + auto &TLD = getThreadLocalData(); + postCurrentThreadFCT(TLD); + + // Then we force serialize the log data. + profileCollectorService::serialize(); + + __sanitizer::atomic_store(&ProfilerLogStatus, + XRayLogInitStatus::XRAY_LOG_FINALIZED, + __sanitizer::memory_order_release); + return XRayLogInitStatus::XRAY_LOG_FINALIZED; +} + +XRayLogInitStatus +profilingLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, + size_t OptionsSize) XRAY_NEVER_INSTRUMENT { + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + if (!__sanitizer::atomic_compare_exchange_strong( + &ProfilerLogStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZING, + __sanitizer::memory_order_release)) { + if (__sanitizer::Verbosity()) + Report("Cannot initialize already initialised profiling " + "implementation.\n"); + return static_cast(CurrentStatus); + } + + // Here we use the sanitizer flag parsing mechanism. When PR36790 is fixed, + // migrate to using a different API for configuration. + { + SpinMutexLock Lock(&ProfilerOptionsMutex); + FlagParser ConfigParser; + auto *F = profilingFlags(); + F->setDefaults(); + registerProfilerFlags(&ConfigParser, F); + const char *ProfilerCompileFlags = profilingCompilerDefinedFlags(); + ConfigParser.ParseString(ProfilerCompileFlags); + ConfigParser.ParseString(static_cast(Options)); + if (Verbosity()) + ReportUnrecognizedFlags(); + } + + // We need to reset the profile data collection implementation now. + profileCollectorService::reset(); + + // We need to set up the at-thread-exit handler. + static bool UNUSED Once = [] { + pthread_key_create(&ProfilingKey, +[](void *P) { + // This is the thread-exit handler. + auto &TLD = *reinterpret_cast(P); + if (TLD.Allocators == nullptr && TLD.FCT == nullptr) + return; + + postCurrentThreadFCT(TLD); + }); + return false; + }(); + + __xray_log_set_buffer_iterator(profileCollectorService::nextBuffer); + __xray_set_handler(profilingHandleArg0); + __xray_set_handler_arg1(profilingHandleArg1); + + __sanitizer::atomic_store(&ProfilerLogStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZED, + __sanitizer::memory_order_release); + if (__sanitizer::Verbosity()) + Report("XRay Profiling init successful.\n"); + + return XRayLogInitStatus::XRAY_LOG_INITIALIZED; +} + +bool profilingDynamicInitializer() XRAY_NEVER_INSTRUMENT { + // Set up the flag defaults from the static defaults and the + // compiler-provided defaults. + { + SpinMutexLock Lock(&ProfilerOptionsMutex); + auto *F = profilingFlags(); + F->setDefaults(); + FlagParser ProfilingParser; + registerProfilerFlags(&ProfilingParser, F); + const char *ProfilerCompileFlags = profilingCompilerDefinedFlags(); + ProfilingParser.ParseString(ProfilerCompileFlags); + } + + XRayLogImpl Impl{ + profilingLoggingInit, + profilingFinalize, + profilingHandleArg0, + profilingFlush, + }; + auto RegistrationResult = __xray_log_register_mode("xray-profiling", Impl); + if (RegistrationResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK && + __sanitizer::Verbosity()) + Report("Cannot register XRay Profiling mode to 'xray-profiling'; error = " + "%d\n", + RegistrationResult); + if (!__sanitizer::internal_strcmp(flags()->xray_mode, "xray-profiling")) + __xray_set_log_impl(Impl); + return true; +} + +} // namespace __xray + +static auto UNUSED Unused = __xray::profilingDynamicInitializer(); Index: compiler-rt/lib/xray/xray_profiling_flags.h =================================================================== --- compiler-rt/lib/xray/xray_profiling_flags.h +++ compiler-rt/lib/xray/xray_profiling_flags.h @@ -1,4 +1,4 @@ -//===-- xray_profiler_flags.h ----------------------------------*- C++ -*-===// +//===-- xray_profiling_flags.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -9,7 +9,7 @@ // // This file is a part of XRay, a dynamic runtime instrumentation system. // -// XRay profiler runtime flags. +// XRay profiling runtime flags. //===----------------------------------------------------------------------===// #ifndef XRAY_PROFILER_FLAGS_H @@ -22,15 +22,15 @@ struct ProfilerFlags { #define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; -#include "xray_profiler_flags.inc" +#include "xray_profiling_flags.inc" #undef XRAY_FLAG void setDefaults(); }; -extern ProfilerFlags xray_profiler_flags_dont_use_directly; -inline ProfilerFlags *profilerFlags() { - return &xray_profiler_flags_dont_use_directly; +extern ProfilerFlags xray_profiling_flags_dont_use_directly; +inline ProfilerFlags *profilingFlags() { + return &xray_profiling_flags_dont_use_directly; } void registerProfilerFlags(FlagParser *P, ProfilerFlags *F); Index: compiler-rt/lib/xray/xray_profiling_flags.cc =================================================================== --- compiler-rt/lib/xray/xray_profiling_flags.cc +++ compiler-rt/lib/xray/xray_profiling_flags.cc @@ -12,7 +12,7 @@ // XRay runtime flags. //===----------------------------------------------------------------------===// -#include "xray_profiler_flags.h" +#include "xray_profiling_flags.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_libc.h" @@ -20,12 +20,12 @@ namespace __xray { -// Storage for the profiler flags. -ProfilerFlags xray_profiler_flags_dont_use_directly; +// Storage for the profiling flags. +ProfilerFlags xray_profiling_flags_dont_use_directly; void ProfilerFlags::setDefaults() XRAY_NEVER_INSTRUMENT { #define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; -#include "xray_profiler_flags.inc" +#include "xray_profiling_flags.inc" #undef XRAY_FLAG } @@ -33,7 +33,7 @@ ProfilerFlags *F) XRAY_NEVER_INSTRUMENT { #define XRAY_FLAG(Type, Name, DefaultValue, Description) \ RegisterFlag(P, #Name, Description, &F->Name); -#include "xray_profiler_flags.inc" +#include "xray_profiling_flags.inc" #undef XRAY_FLAG } Index: compiler-rt/lib/xray/xray_profiling_flags.inc =================================================================== --- compiler-rt/lib/xray/xray_profiling_flags.inc +++ compiler-rt/lib/xray/xray_profiling_flags.inc @@ -1,4 +1,4 @@ -//===-- xray_flags.inc ------------------------------------------*- C++ -*-===// +//===-- xray_profiling_flags.inc --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // Index: compiler-rt/test/xray/TestCases/Posix/profiling-multi-threaded.cc =================================================================== --- /dev/null +++ compiler-rt/test/xray/TestCases/Posix/profiling-multi-threaded.cc @@ -0,0 +1,53 @@ +// Check that we can get a profile from a single-threaded application, on +// demand through the XRay logging implementation API. +// +// FIXME: Make -fxray-modes=xray-profiling part of the default? +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiling +// RUN: %run %t +// +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include +#include +#include +#include + +#define XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]] +#define XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]] + +XRAY_ALWAYS_INSTRUMENT void f2() { return; } +XRAY_ALWAYS_INSTRUMENT void f1() { f2(); } +XRAY_ALWAYS_INSTRUMENT void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +XRAY_NEVER_INSTRUMENT void process_buffer(const char *, XRayBuffer) { + // FIXME: Actually assert the contents of the buffer. + ++buffer_counter; +} + +XRAY_ALWAYS_INSTRUMENT int main(int, char **) { + assert(__xray_log_select_mode("xray-profiling") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_get_current_mode() != nullptr); + std::string current_mode = __xray_log_get_current_mode(); + assert(current_mode == "xray-profiling"); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + assert(__xray_log_init(0, 0, nullptr, 0) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + std::thread t0([] { f0(); }); + std::thread t1([] { f0(); }); + f0(); + t0.join(); + t1.join(); + 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); + assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +} Index: compiler-rt/test/xray/TestCases/Posix/profiling-single-threaded.cc =================================================================== --- /dev/null +++ compiler-rt/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -0,0 +1,48 @@ +// Check that we can get a profile from a single-threaded application, on +// demand through the XRay logging implementation API. +// +// FIXME: Make -fxray-modes=xray-profiling part of the default? +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiling +// RUN: %run %t +// +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include +#include +#include + +#define ALWAYS_INSTRUMENT [[clang::xray_always_instrument]] +#define NEVER_INSTRUMENT [[clang::xray_never_instrument]] + +ALWAYS_INSTRUMENT void f2() { return; } +ALWAYS_INSTRUMENT void f1() { f2(); } +ALWAYS_INSTRUMENT void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +NEVER_INSTRUMENT void process_buffer(const char *, XRayBuffer) { + // FIXME: Actually assert the contents of the buffer. + ++buffer_counter; +} + +ALWAYS_INSTRUMENT int main(int, char **) { + assert(__xray_log_select_mode("xray-profiling") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_get_current_mode() != nullptr); + std::string current_mode = __xray_log_get_current_mode(); + assert(current_mode == "xray-profiling"); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + assert(__xray_log_init(0, 0, nullptr, 0) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + f0(); + assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); + f0(); + assert(__xray_log_process_buffers(process_buffer) == + XRayLogFlushStatus::XRAY_LOG_FLUSHED); + assert(buffer_counter == 1); + assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +}