Index: compiler-rt/trunk/lib/xray/CMakeLists.txt =================================================================== --- compiler-rt/trunk/lib/xray/CMakeLists.txt +++ compiler-rt/trunk/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 @@ -105,10 +106,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}) @@ -145,11 +146,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} @@ -172,9 +173,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. @@ -201,13 +202,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/trunk/lib/xray/tests/CMakeLists.txt =================================================================== --- compiler-rt/trunk/lib/xray/tests/CMakeLists.txt +++ compiler-rt/trunk/lib/xray/tests/CMakeLists.txt @@ -33,8 +33,8 @@ ../../xray_powerpc64.cc ../../xray_profile_collector.cc ../../xray_profile_collector.h - ../../xray_profiler_flags.cc - ../../xray_profiler_flags.h + ../../xray_profiling_flags.cc + ../../xray_profiling_flags.h ../../xray_recursion_guard.h ../../xray_segmented_array.h ../../xray_trampoline_powerpc64.cc @@ -106,7 +106,7 @@ add_xray_lib("RTXRay.test.osx" $ $ - $ + $ $ $) else() @@ -114,7 +114,7 @@ add_xray_lib("RTXRay.test.${arch}" $ $ - $ + $ $ $) endforeach() Index: compiler-rt/trunk/lib/xray/tests/unit/function_call_trie_test.cc =================================================================== --- compiler-rt/trunk/lib/xray/tests/unit/function_call_trie_test.cc +++ compiler-rt/trunk/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/trunk/lib/xray/tests/unit/profile_collector_test.cc =================================================================== --- compiler-rt/trunk/lib/xray/tests/unit/profile_collector_test.cc +++ compiler-rt/trunk/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/trunk/lib/xray/xray_function_call_trie.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_function_call_trie.h +++ compiler-rt/trunk/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/trunk/lib/xray/xray_profile_collector.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profile_collector.cc +++ compiler-rt/trunk/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/trunk/lib/xray/xray_profiler_flags.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiler_flags.h +++ compiler-rt/trunk/lib/xray/xray_profiler_flags.h @@ -1,39 +0,0 @@ -//===-- xray_profiler_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. -// -// XRay profiler runtime flags. -//===----------------------------------------------------------------------===// - -#ifndef XRAY_PROFILER_FLAGS_H -#define XRAY_PROFILER_FLAGS_H - -#include "sanitizer_common/sanitizer_flag_parser.h" -#include "sanitizer_common/sanitizer_internal_defs.h" - -namespace __xray { - -struct ProfilerFlags { -#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; -#include "xray_profiler_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; -} -void registerProfilerFlags(FlagParser *P, ProfilerFlags *F); - -} // namespace __xray - -#endif // XRAY_PROFILER_FLAGS_H Index: compiler-rt/trunk/lib/xray/xray_profiler_flags.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiler_flags.cc +++ compiler-rt/trunk/lib/xray/xray_profiler_flags.cc @@ -1,40 +0,0 @@ -//===-- xray_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. -// -// XRay runtime flags. -//===----------------------------------------------------------------------===// - -#include "xray_profiler_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" - -namespace __xray { - -// Storage for the profiler flags. -ProfilerFlags xray_profiler_flags_dont_use_directly; - -void ProfilerFlags::setDefaults() XRAY_NEVER_INSTRUMENT { -#define XRAY_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; -#include "xray_profiler_flags.inc" -#undef XRAY_FLAG -} - -void registerProfilerFlags(FlagParser *P, - ProfilerFlags *F) XRAY_NEVER_INSTRUMENT { -#define XRAY_FLAG(Type, Name, DefaultValue, Description) \ - RegisterFlag(P, #Name, Description, &F->Name); -#include "xray_profiler_flags.inc" -#undef XRAY_FLAG -} - -} // namespace __xray Index: compiler-rt/trunk/lib/xray/xray_profiler_flags.inc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiler_flags.inc +++ compiler-rt/trunk/lib/xray/xray_profiler_flags.inc @@ -1,26 +0,0 @@ -//===-- xray_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 profiling runtime flags. -// -//===----------------------------------------------------------------------===// -#ifndef XRAY_FLAG -#error "Define XRAY_FLAG prior to including this file!" -#endif - -XRAY_FLAG(uptr, per_thread_allocator_max, 2 << 20, - "Maximum size of any single per-thread allocator.") -XRAY_FLAG(uptr, global_allocator_max, 2 << 24, - "Maximum size of the global allocator for profile storage.") -XRAY_FLAG(uptr, stack_allocator_max, 2 << 24, - "Maximum size of the traversal stack allocator.") -XRAY_FLAG(int, grace_period_ms, 100, - "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.") Index: compiler-rt/trunk/lib/xray/xray_profiling.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiling.cc +++ compiler-rt/trunk/lib/xray/xray_profiling.cc @@ -0,0 +1,291 @@ +//===-- 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_recursion_guard.h" +#include "xray_tsc.h" +#include "xray_utils.h" +#include + +namespace __xray { + +namespace { + +atomic_sint32_t ProfilerLogFlushStatus = { + XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING}; + +atomic_sint32_t ProfilerLogStatus = {XRayLogInitStatus::XRAY_LOG_UNINITIALIZED}; + +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 = atomic_load(&ProfilerLogStatus, 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 +} + +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 (atomic_load(&ProfilerLogStatus, memory_order_acquire) != + XRayLogInitStatus::XRAY_LOG_FINALIZED) { + if (Verbosity()) + Report("Not flushing profiles, profiling not been finalized.\n"); + return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; + } + + s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING; + if (!atomic_compare_exchange_strong(&ProfilerLogFlushStatus, &Result, + XRayLogFlushStatus::XRAY_LOG_FLUSHING, + memory_order_acq_rel)) { + if (Verbosity()) + Report("Not flushing profiles, implementation still finalizing.\n"); + } + + profileCollectorService::reset(); + + atomic_store(&ProfilerLogStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED, + memory_order_release); + + return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +} + +namespace { + +thread_local atomic_uint8_t ReentranceGuard{0}; + +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); + RecursionGuard G(ReentranceGuard); + if (!G) + return; + + auto Status = atomic_load(&ProfilerLogStatus, memory_order_acquire); + auto &TLD = getThreadLocalData(); + if (UNLIKELY(Status == XRayLogInitStatus::XRAY_LOG_FINALIZED || + Status == XRayLogInitStatus::XRAY_LOG_FINALIZING)) { + postCurrentThreadFCT(TLD); + 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; + } +} + +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 (!atomic_compare_exchange_strong(&ProfilerLogStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_FINALIZING, + memory_order_release)) { + if (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. + 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(); + + atomic_store(&ProfilerLogStatus, XRayLogInitStatus::XRAY_LOG_FINALIZED, + memory_order_release); + return XRayLogInitStatus::XRAY_LOG_FINALIZED; +} + +XRayLogInitStatus +profilingLoggingInit(size_t BufferSize, size_t BufferMax, void *Options, + size_t OptionsSize) XRAY_NEVER_INSTRUMENT { + if (BufferSize != 0 || BufferMax != 0) { + if (Verbosity()) + Report("__xray_log_init() being used, and is unsupported. Use " + "__xray_log_init_mode(...) instead. Bailing out."); + return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + } + + s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED; + if (!atomic_compare_exchange_strong(&ProfilerLogStatus, &CurrentStatus, + XRayLogInitStatus::XRAY_LOG_INITIALIZING, + memory_order_release)) { + if (Verbosity()) + Report("Cannot initialize already initialised profiling " + "implementation.\n"); + return static_cast(CurrentStatus); + } + + { + 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 pthread_once_t Once = PTHREAD_ONCE_INIT; + pthread_once(&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); + }); + }); + + __xray_log_set_buffer_iterator(profileCollectorService::nextBuffer); + __xray_set_handler(profilingHandleArg0); + __xray_set_handler_arg1(profilingHandleArg1); + + atomic_store(&ProfilerLogStatus, XRayLogInitStatus::XRAY_LOG_INITIALIZED, + memory_order_release); + if (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 && + Verbosity()) + Report("Cannot register XRay Profiling mode to 'xray-profiling'; error = " + "%d\n", + RegistrationResult); + if (!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/trunk/lib/xray/xray_profiling_flags.h =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiling_flags.h +++ compiler-rt/trunk/lib/xray/xray_profiling_flags.h @@ -0,0 +1,39 @@ +//===-- xray_profiling_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. +// +// XRay profiling runtime flags. +//===----------------------------------------------------------------------===// + +#ifndef XRAY_PROFILER_FLAGS_H +#define XRAY_PROFILER_FLAGS_H + +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +namespace __xray { + +struct ProfilerFlags { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) Type Name; +#include "xray_profiling_flags.inc" +#undef XRAY_FLAG + + void setDefaults(); +}; + +extern ProfilerFlags xray_profiling_flags_dont_use_directly; +inline ProfilerFlags *profilingFlags() { + return &xray_profiling_flags_dont_use_directly; +} +void registerProfilerFlags(FlagParser *P, ProfilerFlags *F); + +} // namespace __xray + +#endif // XRAY_PROFILER_FLAGS_H Index: compiler-rt/trunk/lib/xray/xray_profiling_flags.cc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiling_flags.cc +++ compiler-rt/trunk/lib/xray/xray_profiling_flags.cc @@ -0,0 +1,40 @@ +//===-- xray_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. +// +// XRay runtime flags. +//===----------------------------------------------------------------------===// + +#include "xray_profiling_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" + +namespace __xray { + +// 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_profiling_flags.inc" +#undef XRAY_FLAG +} + +void registerProfilerFlags(FlagParser *P, + ProfilerFlags *F) XRAY_NEVER_INSTRUMENT { +#define XRAY_FLAG(Type, Name, DefaultValue, Description) \ + RegisterFlag(P, #Name, Description, &F->Name); +#include "xray_profiling_flags.inc" +#undef XRAY_FLAG +} + +} // namespace __xray Index: compiler-rt/trunk/lib/xray/xray_profiling_flags.inc =================================================================== --- compiler-rt/trunk/lib/xray/xray_profiling_flags.inc +++ compiler-rt/trunk/lib/xray/xray_profiling_flags.inc @@ -0,0 +1,26 @@ +//===-- xray_profiling_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 profiling runtime flags. +// +//===----------------------------------------------------------------------===// +#ifndef XRAY_FLAG +#error "Define XRAY_FLAG prior to including this file!" +#endif + +XRAY_FLAG(uptr, per_thread_allocator_max, 2 << 20, + "Maximum size of any single per-thread allocator.") +XRAY_FLAG(uptr, global_allocator_max, 2 << 24, + "Maximum size of the global allocator for profile storage.") +XRAY_FLAG(uptr, stack_allocator_max, 2 << 24, + "Maximum size of the traversal stack allocator.") +XRAY_FLAG(int, grace_period_ms, 100, + "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.") Index: compiler-rt/trunk/test/xray/TestCases/Posix/c-test.cc =================================================================== --- compiler-rt/trunk/test/xray/TestCases/Posix/c-test.cc +++ compiler-rt/trunk/test/xray/TestCases/Posix/c-test.cc @@ -1,4 +1,4 @@ -// RUN: %clang_xray -g -o %t %s +// RUN: %clang_xray -g -fxray-modes=xray-basic,xray-fdr,xray-profiling -o %t %s // RUN: rm xray-log.c-test.* || true // RUN: XRAY_OPTIONS=patch_premain=true:verbosity=1:xray_mode=xray-basic %t \ // RUN: 2>&1 | FileCheck %s Index: compiler-rt/trunk/test/xray/TestCases/Posix/profiling-multi-threaded.cc =================================================================== --- compiler-rt/trunk/test/xray/TestCases/Posix/profiling-multi-threaded.cc +++ compiler-rt/trunk/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/trunk/test/xray/TestCases/Posix/profiling-single-threaded.cc =================================================================== --- compiler-rt/trunk/test/xray/TestCases/Posix/profiling-single-threaded.cc +++ compiler-rt/trunk/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -0,0 +1,58 @@ +// 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 + +[[clang::xray_always_instrument]] void f2() { return; } +[[clang::xray_always_instrument]] void f1() { f2(); } +[[clang::xray_always_instrument]] void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +[[clang::xray_never_instrument]] void process_buffer(const char *, XRayBuffer) { + // FIXME: Actually assert the contents of the buffer. + ++buffer_counter; +} + +[[clang::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_mode("xray-profiling", "") == + 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); + + // Let's reset the counter. + buffer_counter = 0; + + assert(__xray_log_init_mode("xray-profiling", "") == + 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); +}