Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/context_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "guards.h"
#include "otel_context.h"
#include "profiler.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include <cstring>

/**
Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/counters.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
X(SAFECOPY_FAILED, "safecopy_failed") \
X(SAFEFETCH_FAILED, "safefetch_failed") \
X(STACKWALK_LONGJMP_RECOVERED, "stackwalk_longjmp_recovered") \
X(SAMPLES_DROPPED_TLS_POOL_EXHAUSTED, "thread_local_pool_exhausted") \
DD_COUNTER_TABLE_FAULT_INJECTION(X) \
DD_COUNTER_TABLE_FI_DEBUG(X) \
DD_COUNTER_TABLE_DEBUG(X)
Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/ctimer_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "log.h"
#include "profiler.h"
#include "signalCookie.h"
#include "threadLocalData.inline.h"
#include "threadState.inline.h"
#include <assert.h>
#include <errno.h>
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/faultInjection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

#include "counters.h" // Counters::increment (FAULTS_INJECTED)
#include "os.h" // OS::page_size
#include "threadLocalData.h" // ProfiledThread::current / nextFiRandom
#include "threadLocalData.inline.h" // ProfiledThread::current / nextFiRandom
#include <atomic>
#include <sys/mman.h>

Expand Down
14 changes: 12 additions & 2 deletions ddprof-lib/src/main/cpp/faultInjection.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@
//
// return INJECT_FAULT_BOOL_LIKELY(dlopen(name, flags) != nullptr);
//
// The three tiers name their firing frequency: RARE 0.01%, UNLIKELY 0.1%,
// LIKELY 1%. See faultInjection.cpp for the poison-address and PRNG details.
// The four tiers name their firing frequency: RARE 0.01%, UNLIKELY 0.1%,
// LIKELY 1%, HIGH 10%. See faultInjection.cpp for the poison-address and PRNG
// details.

#ifndef _FAULT_INJECTION_H
#define _FAULT_INJECTION_H
Expand All @@ -56,6 +57,7 @@ namespace faultinj {
constexpr u64 PROB_RARE = 1844674407370955ULL; // 1e-4 (0.01%)
constexpr u64 PROB_UNLIKELY = 18446744073709552ULL; // 1e-3 (0.1%)
constexpr u64 PROB_LIKELY = 184467440737095520ULL; // 1e-2 (1%)
constexpr u64 PROB_HIGH = 1844674407370955162ULL; // 1e-1 (10%)

// Called once at profiler startup (off the signal path) to mmap the PROT_NONE
// guard region used by poisonAddress(). Safe to call before any injection.
Expand Down Expand Up @@ -106,31 +108,39 @@ inline T injectValue(T orig, T faulty, u64 threshold, const char* fn) {
::faultinj::injectAddress((ptr), ::faultinj::PROB_UNLIKELY, __func__)
#define INJECT_FAULT_ADDRESS_LIKELY(ptr) \
::faultinj::injectAddress((ptr), ::faultinj::PROB_LIKELY, __func__)
#define INJECT_FAULT_ADDRESS_HIGH(ptr) \
::faultinj::injectAddress((ptr), ::faultinj::PROB_HIGH, __func__)

#define INJECT_FAULT_BOOL_RARE(v) \
::faultinj::injectValue((v), false, ::faultinj::PROB_RARE, __func__)
#define INJECT_FAULT_BOOL_UNLIKELY(v) \
::faultinj::injectValue((v), false, ::faultinj::PROB_UNLIKELY, __func__)
#define INJECT_FAULT_BOOL_LIKELY(v) \
::faultinj::injectValue((v), false, ::faultinj::PROB_LIKELY, __func__)
#define INJECT_FAULT_BOOL_HIGH(v) \
::faultinj::injectValue((v), false, ::faultinj::PROB_HIGH, __func__)

#else // __FAULT_INJECTION__ not defined — strict identity, zero cost.

#define INJECT_FAULT_ADDRESS_RARE(ptr) (ptr)
#define INJECT_FAULT_ADDRESS_UNLIKELY(ptr) (ptr)
#define INJECT_FAULT_ADDRESS_LIKELY(ptr) (ptr)
#define INJECT_FAULT_ADDRESS_HIGH(ptr) (ptr)

#define INJECT_FAULT_INT_RARE(v) (v)
#define INJECT_FAULT_INT_UNLIKELY(v) (v)
#define INJECT_FAULT_INT_LIKELY(v) (v)
#define INJECT_FAULT_INT_HIGH(v) (v)

#define INJECT_FAULT_LONG_RARE(v) (v)
#define INJECT_FAULT_LONG_UNLIKELY(v) (v)
#define INJECT_FAULT_LONG_LIKELY(v) (v)
#define INJECT_FAULT_LONG_HIGH(v) (v)

#define INJECT_FAULT_BOOL_RARE(v) (v)
#define INJECT_FAULT_BOOL_UNLIKELY(v) (v)
#define INJECT_FAULT_BOOL_LIKELY(v) (v)
#define INJECT_FAULT_BOOL_HIGH(v) (v)

#define NO_INJECTION_ASSERT(a) (assert(a))

Expand Down
1 change: 1 addition & 0 deletions ddprof-lib/src/main/cpp/flightRecorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "unwindStats.h"
#include "symbols.h"
#include "threadFilter.h"
#include "threadLocalData.inline.h"
#include "threadState.h"
#include "tsc.h"
#include "hotspot/vmStructs.h"
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/guards.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "guards.h"
#include "common.h"
#include "os.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"

// Signal-context tracking — backed by ProfiledThread::_signal_depth; see
// the comment block in guards.h for the rationale (initial-exec TLS was
Expand Down
23 changes: 12 additions & 11 deletions ddprof-lib/src/main/cpp/hotspot/hotspotSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "profiler.h"
#include "stackWalker.inline.h"
#include "threadLocal.h"
#include "threadLocalData.inline.h"

using StackWalkValidation::inDeadZone;
using StackWalkValidation::aligned;
Expand Down Expand Up @@ -240,7 +241,7 @@ __attribute__((no_sanitize("address"))) int HotspotSupport::walkVM(void* ucontex
// VMStructs is only available for hotspot JVM
assert(VM::isHotspot());

ProfiledThread* prof_thread = ProfiledThread::current();
ProfiledThread* prof_thread = ProfiledThread::acquireCurrent();
if (prof_thread == nullptr) {
Counters::increment(SAMPLES_DROPPED_THREAD_LOCAL);
return 0;
Expand Down Expand Up @@ -1210,12 +1211,16 @@ int HotspotSupport::walkJavaStack(StackWalkRequest& request) {
// AsyncGetCallTrace. Install a jmp ctx here too, so a SIGSEGV anywhere in
// walkJavaStack, except HotSpot's AsyncGetCallTrace call, is caught by
// Profiler::checkFault() and siglongjmp'd back here instead of crashing the process.
ProfiledThread* prof_thread = ProfiledThread::current();
const bool prev_unwinding_java = prof_thread != nullptr ? prof_thread->is_unwinding_Java() : false;
ProfiledThread* prof_thread = ProfiledThread::acquireCurrent();
if (prof_thread == nullptr) {
Counters::increment(SAMPLES_DROPPED_THREAD_LOCAL);
return 0;
}
const bool prev_unwinding_java = prof_thread->is_unwinding_Java();
sigjmp_buf crash_protection_ctx;
sigjmp_buf* prev_jmp_buf = prof_thread != nullptr ? prof_thread->getJmpCtx() : nullptr;
sigjmp_buf* prev_jmp_buf = prof_thread->getJmpCtx();

if (prof_thread != nullptr && sigsetjmp(crash_protection_ctx, 1) != 0) {
if (sigsetjmp(crash_protection_ctx, 1) != 0) {
// checkFault() does a siglongjmp from inside segvHandler, bypassing
// segvHandler's SignalHandlerScope destructor. Compensate.
SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP();
Expand All @@ -1228,9 +1233,7 @@ int HotspotSupport::walkJavaStack(StackWalkRequest& request) {
}
return java_frames;
}
if (prof_thread != nullptr) {
prof_thread->setJmpCtx(&crash_protection_ctx);
}
prof_thread->setJmpCtx(&crash_protection_ctx);

if (features.mixed) {
java_frames = walkVM(ucontext, frames, max_depth, features, eventTypeFromBCI(request.event_type), lock_index, truncated);
Expand Down Expand Up @@ -1284,9 +1287,7 @@ int HotspotSupport::walkJavaStack(StackWalkRequest& request) {
}
}

if (prof_thread != nullptr) {
prof_thread->setJmpCtx(prev_jmp_buf);
}
prof_thread->setJmpCtx(prev_jmp_buf);
return java_frames;
}

Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/hotspot/vmStructs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "jvmThread.h"
#include "safeAccess.h"
#include "spinLock.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include "threadState.h"

CodeCache* VMStructs::_libjvm = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/hotspot/vmStructs.inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "hotspot/vmStructs.h"
#include "jvmThread.h"
#include "safeAccess.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"

inline bool crashProtectionActive() {
ProfiledThread* pt = ProfiledThread::current();
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/itimer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "profiler.h"
#include "signalInflight.h"
#include "stackWalker.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include "threadState.inline.h"
#include "guards.h"
#include <sys/time.h>
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/javaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include "os.h"
#include "otel_process_ctx.h"
#include "profiler.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include "tsc.h"
#include "vmEntry.h"
#include <errno.h>
Expand Down
10 changes: 9 additions & 1 deletion ddprof-lib/src/main/cpp/jvmSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include "jvmSupport.inline.h"

#include "asyncSampleMutex.h"
#include "common.h"
#include "frames.h"
#include "os.h"
#include "profiler.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include "threadLocalDataPool.h"
#include "vmEntry.h"

#include "hotspot/hotspotSupport.h"
Expand Down Expand Up @@ -38,6 +40,12 @@ bool JVMSupport::initialize() {
return false;
}

if (ProfiledThread::supportPriming()) {
Comment thread
zhengyu123 marked this conversation as resolved.
ThreadLocalDataPool::initialize();
} else {
LOG_WARN("Thread priming is not supported");
}

// Check ProfiledThread key, it is critical for storing per-thread metadata
return ProfiledThread::isThreadKeyValid();
}
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/perfEvents_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
#include "stackFrame.h"
#include "stackWalker.h"
#include "symbols.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include "threadState.inline.h"
#include <dlfcn.h>
#include <errno.h>
Expand Down
5 changes: 3 additions & 2 deletions ddprof-lib/src/main/cpp/profiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "stackFrame.h"
#include "stackWalker.h"
#include "symbols.h"
#include "threadLocalData.inline.h"
#include "tsc.h"
#include "utils.h"
#include "wallClock.h"
Expand Down Expand Up @@ -865,10 +866,10 @@ bool Profiler::prewarmUnwinder() {
// libgcc_s.so.1 has been the stable SONAME since 2002; a bump would
// constitute a glibc/GCC C++ ABI break and is treated as a fixed contract.
//
// INJECT_FAULT_BOOL_LIKELY lets fault-injection builds force this to
// INJECT_FAULT_BOOL_HIGH lets fault-injection builds force this to
// report failure without the library actually being absent, so
// checkState()'s "Missing libgcc_s.so" path can be exercised in CI.
return INJECT_FAULT_BOOL_LIKELY(dlopen("libgcc_s.so.1", RTLD_LAZY | RTLD_GLOBAL) != nullptr);
return INJECT_FAULT_BOOL_HIGH(dlopen("libgcc_s.so.1", RTLD_LAZY | RTLD_GLOBAL) != nullptr);
#else
return true;
#endif
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/refCountGuard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include "log.h"
#include "os.h"
#include "primeProbing.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"
#include <atomic>
#include <time.h>

Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/safeAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include <signal.h>
#include <ucontext.h>
#ifdef DEBUG
#include "threadLocalData.h" // ProfiledThread::current / isProtected
#include "threadLocalData.inline.h" // ProfiledThread::current / isProtected
#endif

extern "C" int safefetch32_cont(int* adr, int errValue);
Expand Down
2 changes: 1 addition & 1 deletion ddprof-lib/src/main/cpp/signalSafety.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define _SIGNAL_SAFETY_H

#include "guards.h" // isInSignalContext, SIGNAL_HANDLER_GUARD, ...
#include "threadLocalData.h" // ProfiledThread::current
#include "threadLocalData.inline.h" // ProfiledThread::current

// Detect ASAN using compiler-provided macros so the ASAN_ENABLED guard below
// works in every TU that includes this header, independent of include order.
Expand Down
35 changes: 19 additions & 16 deletions ddprof-lib/src/main/cpp/stackWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "symbols.h"
#include "jvmSupport.inline.h"
#include "jvmThread.h"
#include "threadLocalData.h"
#include "threadLocalData.inline.h"

// Use validation helpers from header (shared with tests)
using StackWalkValidation::inDeadZone;
Expand Down Expand Up @@ -45,11 +45,15 @@ int StackWalker::walkFP(void* ucontext, const void** callchain, int max_depth, S
// falls inside this library while a jmp ctx is installed gets caught by
// Profiler::checkFault() from the SEGV handler and siglongjmp'd back here,
// instead of crashing the process.
ProfiledThread* prof_thread = ProfiledThread::current();
ProfiledThread* prof_thread = ProfiledThread::acquireCurrent();
if (prof_thread == nullptr) {
Counters::increment(SAMPLES_DROPPED_THREAD_LOCAL);
return 0;
}
sigjmp_buf crash_protection_ctx;
sigjmp_buf* prev_jmp_buf = prof_thread != nullptr ? prof_thread->getJmpCtx() : nullptr;
sigjmp_buf* prev_jmp_buf = prof_thread->getJmpCtx();

if (prof_thread != nullptr && sigsetjmp(crash_protection_ctx, 1) != 0) {
if (sigsetjmp(crash_protection_ctx, 1) != 0) {
// checkFault() does a siglongjmp from inside segvHandler, bypassing
// segvHandler's SignalHandlerScope destructor. Compensate.
SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP();
Expand All @@ -62,9 +66,7 @@ int StackWalker::walkFP(void* ucontext, const void** callchain, int max_depth, S
}
return depth;
}
if (prof_thread != nullptr) {
prof_thread->setJmpCtx(&crash_protection_ctx);
}
prof_thread->setJmpCtx(&crash_protection_ctx);

// Walk until the bottom of the stack or until the first Java frame
while (depth < actual_max_depth) {
Expand Down Expand Up @@ -132,11 +134,16 @@ int StackWalker::walkDwarf(void* ucontext, const void** callchain, int max_depth
// falls inside this library while a jmp ctx is installed gets caught by
// Profiler::checkFault() from the SEGV handler and siglongjmp'd back here,
// instead of crashing the process.
ProfiledThread* prof_thread = ProfiledThread::current();
ProfiledThread* prof_thread = ProfiledThread::acquireCurrent();
if (prof_thread == nullptr) {
Counters::increment(SAMPLES_DROPPED_THREAD_LOCAL);
return 0;
}

sigjmp_buf crash_protection_ctx;
sigjmp_buf* prev_jmp_buf = prof_thread != nullptr ? prof_thread->getJmpCtx() : nullptr;
sigjmp_buf* prev_jmp_buf = prof_thread->getJmpCtx();

if (prof_thread != nullptr && sigsetjmp(crash_protection_ctx, 1) != 0) {
if (sigsetjmp(crash_protection_ctx, 1) != 0) {
// checkFault() does a siglongjmp from inside segvHandler, bypassing
// segvHandler's SignalHandlerScope destructor. Compensate.
SIGNAL_HANDLER_UNWIND_AFTER_LONGJMP();
Expand All @@ -149,9 +156,7 @@ int StackWalker::walkDwarf(void* ucontext, const void** callchain, int max_depth
}
return depth;
}
if (prof_thread != nullptr) {
prof_thread->setJmpCtx(&crash_protection_ctx);
}
prof_thread->setJmpCtx(&crash_protection_ctx);

// Walk until the bottom of the stack or until the first Java frame
while (depth < actual_max_depth) {
Expand Down Expand Up @@ -229,9 +234,7 @@ int StackWalker::walkDwarf(void* ucontext, const void** callchain, int max_depth
}
}

if (prof_thread != nullptr) {
prof_thread->setJmpCtx(prev_jmp_buf);
}
prof_thread->setJmpCtx(prev_jmp_buf);

if (truncated && depth > max_depth) {
*truncated = true;
Expand Down
4 changes: 4 additions & 0 deletions ddprof-lib/src/main/cpp/threadLocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ class ThreadLocal {
return _key != INVALID_KEY;
}

pthread_key_t key() const {
return _key;
}

/**
* set(nullptr) will result in the value being recreated when get() is called
* when CREATE_FUNC is not nullptr.
Expand Down
Loading
Loading