[XRay][profiler] Part 4: Profiler Mode Wiring

Summary:
This is part of the larger XRay Profiling Mode effort.

This patch implements the wiring required to enable us to actually
select the `xray-profiling` mode, and install the handlers to start
measuring the time and frequency of the function calls in call stacks.
The current way to get the profile information is by working with the
XRay API to `__xray_process_buffers(...)`.

In subsequent changes we'll implement profile saving to files, similar
to how the FDR and basic modes operate, as well as means for converting
this format into those that can be loaded/visualised as flame graphs. We
will also be extending the accounting tool in LLVM to support
stack-based function call accounting.

We also continue with the implementation to support building small
histograms of latencies for the `FunctionCallTrie::Node` type, to allow
us to actually approximate the distribution of latencies per function.

Depends on D45758 and D46998.

Reviewers: eizan, kpw, pelikan

Reviewed By: kpw

Subscribers: llvm-commits, mgorny

Differential Revision: https://reviews.llvm.org/D44620

llvm-svn: 334469
This commit is contained in:
Dean Michael Berris 2018-06-12 03:29:39 +00:00
parent c20c182df3
commit cfd7eec3d8
13 changed files with 457 additions and 53 deletions

View File

@ -18,9 +18,10 @@ set(XRAY_BASIC_MODE_SOURCES
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 @@ if (APPLE)
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 @@ if (APPLE)
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 @@ else() # not Apple
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 @@ else() # not Apple
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

View File

@ -33,8 +33,8 @@ set(XRAY_IMPL_FILES
../../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 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
add_xray_lib("RTXRay.test.osx"
$<TARGET_OBJECTS:RTXray.osx>
$<TARGET_OBJECTS:RTXrayFDR.osx>
$<TARGET_OBJECTS:RTXrayPROFILER.osx>
$<TARGET_OBJECTS:RTXrayPROFILING.osx>
$<TARGET_OBJECTS:RTSanitizerCommon.osx>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>)
else()
@ -114,7 +114,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS)
add_xray_lib("RTXRay.test.${arch}"
$<TARGET_OBJECTS:RTXray.${arch}>
$<TARGET_OBJECTS:RTXrayFDR.${arch}>
$<TARGET_OBJECTS:RTXrayPROFILER.${arch}>
$<TARGET_OBJECTS:RTXrayPROFILING.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>)
endforeach()

View File

@ -27,13 +27,13 @@ TEST(FunctionCallTrieTest, Construction) {
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, MissingFunctionExit) {
}
TEST(FunctionCallTrieTest, MultipleRoots) {
profilerFlags()->setDefaults();
profilingFlags()->setDefaults();
auto A = FunctionCallTrie::InitAllocators();
FunctionCallTrie Trie(A);
@ -114,7 +114,7 @@ TEST(FunctionCallTrieTest, MultipleRoots) {
// 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 @@ TEST(FunctionCallTrieTest, MissingIntermediaryExit) {
// 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, DeepCopy) {
}
TEST(FunctionCallTrieTest, MergeInto) {
profilerFlags()->setDefaults();
profilingFlags()->setDefaults();
auto A = FunctionCallTrie::InitAllocators();
FunctionCallTrie T0(A);
FunctionCallTrie T1(A);

View File

@ -13,7 +13,7 @@
#include "gtest/gtest.h"
#include "xray_profile_collector.h"
#include "xray_profiler_flags.h"
#include "xray_profiling_flags.h"
#include <cstdint>
#include <thread>
#include <utility>
@ -25,7 +25,7 @@ namespace {
static constexpr auto kHeaderSize = 16u;
void ValidateBlock(XRayBuffer B) {
profilerFlags()->setDefaults();
profilingFlags()->setDefaults();
ASSERT_NE(static_cast<const void *>(B.Data), nullptr);
ASSERT_NE(B.Size, 0u);
ASSERT_GE(B.Size, kHeaderSize);
@ -84,7 +84,7 @@ std::tuple<Profile, const char *> ParseProfile(const char *P) {
}
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 @@ void threadProcessing() {
}
TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) {
profilerFlags()->setDefaults();
profilingFlags()->setDefaults();
std::thread t1(threadProcessing);
std::thread t2(threadProcessing);

View File

@ -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 <utility>
#include <memory> // For placement new.
@ -223,26 +223,26 @@ public:
auto NodeAllocator = reinterpret_cast<Allocators::NodeAllocatorType *>(
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<Allocators::RootAllocatorType *>(
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<Allocators::ShadowStackAllocatorType *>(
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<NodeIdPairAllocatorType *>(
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 @@ public:
using Stack = Array<NodeAndParent>;
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 @@ public:
};
using Stack = Array<NodeAndTarget>;
typename Stack::AllocatorType StackAllocator(
profilerFlags()->stack_allocator_max, 0);
profilingFlags()->stack_allocator_max, 0);
Stack DFSStack(StackAllocator);
for (const auto Root : getRoots()) {

View File

@ -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 <pthread.h>
#include <memory>
#include <utility>
@ -128,7 +128,7 @@ static void populateRecords(ProfileRecordArray &PRs,
const FunctionCallTrie &Trie) {
using StackArray = Array<const FunctionCallTrie::Node *>;
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 @@ void serialize() {
// 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

View File

@ -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 <memory>
#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 <pthread.h>
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<sizeof(ProfilingData)>::type ThreadStorage;
if (pthread_getspecific(ProfilingKey) == NULL) {
new (&ThreadStorage) ProfilingData{};
pthread_setspecific(ProfilingKey, &ThreadStorage);
}
auto &TLD = *reinterpret_cast<ProfilingData *>(&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<FunctionCallTrie::Allocators *>(
InternalAlloc(sizeof(FunctionCallTrie::Allocators)));
new (TLD.Allocators) FunctionCallTrie::Allocators();
*TLD.Allocators = FunctionCallTrie::InitAllocators();
TLD.FCT = reinterpret_cast<FunctionCallTrie *>(
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<XRayLogInitStatus>(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<XRayLogInitStatus>(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<const char *>(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<ProfilingData *>(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();

View File

@ -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 @@ 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"
#include "xray_profiling_flags.inc"
#undef XRAY_FLAG
}

View File

@ -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 @@ namespace __xray {
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);

View File

@ -1,4 +1,4 @@
//===-- xray_flags.inc ------------------------------------------*- C++ -*-===//
//===-- xray_profiling_flags.inc --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//

View File

@ -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

View File

@ -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 <cassert>
#include <cstdio>
#include <string>
#include <thread>
#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);
}

View File

@ -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 <cassert>
#include <cstdio>
#include <string>
[[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);
}