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
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ target_link_libraries(
PRIVATE
"$<$<AND:$<C_COMPILER_ID:GNU>,$<CONFIG:SanitizedDebug>>:-Wl,-Bstatic;-lubsan;-lasan;-lstdc++;-Wl,-Bdynamic>"
)
target_link_libraries(dd_profiling-embedded PUBLIC dl pthread rt absl::base absl::str_format)
target_link_libraries(dd_profiling-embedded PUBLIC dl pthread rt absl::base absl::str_format
systemtap)

set(LIBDD_PROFILING_EMBEDDED_OBJECT "${CMAKE_BINARY_DIR}/libdd_profiling-embedded.o")
set(LIBDD_PROFILING_EMBEDDED_HASH_HEADER "${CMAKE_BINARY_DIR}/libdd_profiling-embedded_hash.h")
Expand Down Expand Up @@ -365,7 +366,8 @@ target_include_directories(dd_profiling-static PUBLIC ${CMAKE_SOURCE_DIR}/includ
set_target_properties(dd_profiling-static
PROPERTIES PUBLIC_HEADER "${CMAKE_SOURCE_DIR}/include/lib/dd_profiling.h")
target_link_libraries(dd_profiling-static PRIVATE ddprof_exe_object)
target_link_libraries(dd_profiling-static PUBLIC dl pthread rt absl::base absl::str_format)
target_link_libraries(dd_profiling-static PUBLIC dl pthread rt absl::base absl::str_format
systemtap)

if(USE_LOADER)
# When using a loader, libdd_profiling.so is a loader that embeds both libdd_profiling-embedded.so
Expand Down Expand Up @@ -398,7 +400,8 @@ else()
PRIVATE
"$<$<AND:$<C_COMPILER_ID:GNU>,$<CONFIG:SanitizedDebug>>:-Wl,-Bstatic;-lubsan;-lasan;-lstdc++;-Wl,-Bdynamic>"
)
target_link_libraries(dd_profiling-shared PUBLIC dl pthread rt absl::base absl::str_format)
target_link_libraries(dd_profiling-shared PUBLIC dl pthread rt absl::base absl::str_format
systemtap)
endif()

target_static_libcxx(dd_profiling-shared)
Expand Down
9 changes: 5 additions & 4 deletions include/lib/allocation_tracker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class AllocationTracker {

enum AllocationTrackingFlags {
kTrackDeallocations = 0x1,
kDeterministicSampling = 0x2
kDeterministicSampling = 0x2,
kOtelProfilerMode = 0x4,
};

struct IntervalTimerCheck {
Expand Down Expand Up @@ -101,9 +102,8 @@ class AllocationTracker {

uint64_t next_sample_interval(std::minstd_rand &gen) const;

DDRes init(uint64_t mem_profile_interval, bool deterministic_sampling,
bool track_deallocations, uint32_t stack_sample_size,
const RingBufferInfo &ring_buffer,
DDRes init(uint64_t mem_profile_interval, uint32_t flags,
uint32_t stack_sample_size, const RingBufferInfo &ring_buffer,
const IntervalTimerCheck &timer_check);
void free();

Expand Down Expand Up @@ -141,6 +141,7 @@ class AllocationTracker {
uint32_t _stack_sample_size;
PEvent _pevent;
bool _deterministic_sampling;
bool _otel_profiler_mode;

AddressBitset _allocated_address_set;
IntervalTimerCheck _interval_timer_check;
Expand Down
74 changes: 50 additions & 24 deletions src/lib/allocation_tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <atomic>
#include <cassert>
#include <cstdlib>
#include <sys/sdt.h>
#include <unistd.h>

namespace ddprof {
Expand Down Expand Up @@ -100,45 +101,49 @@ DDRes AllocationTracker::allocation_tracking_init(
DDRES_RETURN_ERROR_LOG(DD_WHAT_UKNW, "Allocation profiler already started");
}

DDRES_CHECK_FWD(instance->init(allocation_profiling_rate,
flags & kDeterministicSampling,
flags & kTrackDeallocations, stack_sample_size,
ring_buffer, timer_check));
DDRES_CHECK_FWD(instance->init(allocation_profiling_rate, flags,
stack_sample_size, ring_buffer, timer_check));
_instance = instance;

state.init(true, flags & kTrackDeallocations);

return {};
}

DDRes AllocationTracker::init(uint64_t mem_profile_interval,
bool deterministic_sampling,
bool track_deallocations,
DDRes AllocationTracker::init(uint64_t mem_profile_interval, uint32_t flags,
uint32_t stack_sample_size,
const RingBufferInfo &ring_buffer,
const IntervalTimerCheck &timer_check) {
_sampling_interval = mem_profile_interval;
_deterministic_sampling = deterministic_sampling;
_deterministic_sampling = flags & kDeterministicSampling;
_stack_sample_size = stack_sample_size;
if (ring_buffer.ring_buffer_type !=
static_cast<int>(RingBufferType::kMPSCRingBuffer)) {
return ddres_error(DD_WHAT_PERFRB);
_otel_profiler_mode = flags & kOtelProfilerMode;

if (!_otel_profiler_mode) {
if (ring_buffer.ring_buffer_type !=
static_cast<int>(RingBufferType::kMPSCRingBuffer)) {
return ddres_error(DD_WHAT_PERFRB);
}

DDRES_CHECK_FWD(ddprof::ring_buffer_attach(ring_buffer, &_pevent));

const auto &rb = _pevent.rb;
if (rb.tsc_available) {
TscClock::init(TscClock::CalibrationParams{
.offset = TscClock::time_point{TscClock::duration{rb.time_zero}},
.mult = rb.time_mult,
.shift = rb.time_shift});
}
PerfClock::init(static_cast<PerfClockSource>(rb.perf_clock_source));
} else {
PerfClock::init(PerfClockSource::kClockMonotonic);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because monotonic is what the full host profiler would expect, and tsc logic is not available

Copy link
Collaborator Author

@nsavoire nsavoire Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On otel profiler mode, PerfClock is not used to timestamp samples (since it's done on eBFP side), I had to initialize it because it's also used to determine when periodically check for newly loaded libraries.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And indeed TSC calibration is done on ddprof side and is not available here.

}
if (track_deallocations) {

if (flags & kTrackDeallocations) {
// 16 times as we want to probability of collision to be low enough
_allocated_address_set = AddressBitset(liveallocation::kMaxTracked *
k_ratio_max_elt_to_bitset_size);
}
DDRES_CHECK_FWD(ddprof::ring_buffer_attach(ring_buffer, &_pevent));

const auto &rb = _pevent.rb;
if (rb.tsc_available) {
TscClock::init(TscClock::CalibrationParams{
.offset = TscClock::time_point{TscClock::duration{rb.time_zero}},
.mult = rb.time_mult,
.shift = rb.time_shift});
}
PerfClock::init(static_cast<PerfClockSource>(rb.perf_clock_source));

_interval_timer_check = timer_check;
if (_interval_timer_check.is_set()) {
Expand Down Expand Up @@ -282,6 +287,7 @@ void AllocationTracker::track_deallocation(uintptr_t addr,
DDRes AllocationTracker::push_lost_sample(MPSCRingBufferWriter &writer,
TrackerThreadLocalState &tl_state,
bool &notify_needed) {
DDPROF_DCHECK_FATAL(!_otel_profiler_mode);
auto lost_count = _state.lost_count.exchange(0, std::memory_order_acq_rel);
if (lost_count == 0) {
return {};
Expand Down Expand Up @@ -322,6 +328,12 @@ DDRes AllocationTracker::push_lost_sample(MPSCRingBufferWriter &writer,
// Return true if consumer should be notified
DDRes AllocationTracker::push_clear_live_allocation(
TrackerThreadLocalState &tl_state) {
if (_otel_profiler_mode) {
// NOLINTNEXTLINE
DTRACE_PROBE(ddprof, clear_live_allocations);
check_timer(PerfClock::now(), tl_state);
return {};
}
MPSCRingBufferWriter writer{&_pevent.rb};
bool timeout = false;

Expand Down Expand Up @@ -361,6 +373,13 @@ DDRes AllocationTracker::push_clear_live_allocation(

DDRes AllocationTracker::push_dealloc_sample(
uintptr_t addr, TrackerThreadLocalState &tl_state) {
if (_otel_profiler_mode) {
// NOLINTNEXTLINE
DTRACE_PROBE1(ddprof, deallocation, addr);
check_timer(PerfClock::now(), tl_state);
return {};
}

MPSCRingBufferWriter writer{&_pevent.rb};
bool notify_consumer{false};

Expand Down Expand Up @@ -414,6 +433,13 @@ DDRes AllocationTracker::push_dealloc_sample(
DDRes AllocationTracker::push_alloc_sample(uintptr_t addr,
uint64_t allocated_size,
TrackerThreadLocalState &tl_state) {
if (_otel_profiler_mode) {
// NOLINTNEXTLINE
DTRACE_PROBE2(ddprof, allocation, addr, allocated_size);
check_timer(PerfClock::now(), tl_state);
return {};
}

MPSCRingBufferWriter writer{&_pevent.rb};
bool notify_consumer{false};

Expand All @@ -427,12 +453,12 @@ DDRes AllocationTracker::push_alloc_sample(uintptr_t addr,
const auto *stack_base_ptr = reinterpret_cast<const std::byte *>(&p);
auto stack_size = to_address(tl_state.stack_bounds.end()) - stack_base_ptr;

// stack will be saved in save_context, add some margin to account for call
// stack will be saved in save_context, add some ` to account for call
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor, comment was broken here

// frames
#ifdef NDEBUG
constexpr int64_t kStackMargin = 192;
#else
constexpr int64_t kStackMargin = 720;
constexpr int64_t kStackMargin = 4000;
#endif
uint32_t const sample_stack_size =
align_up(std::min(std::max(stack_size + kStackMargin, 0L),
Expand Down
37 changes: 37 additions & 0 deletions src/lib/dd_profiling.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "symbol_overrides.hpp"
#include "syscalls.hpp"

#include <absl/strings/numbers.h>
#include <cassert>
#include <cerrno>
#include <charconv>
Expand Down Expand Up @@ -46,6 +47,7 @@ struct ProfilerState {
bool allocation_profiling_started = false;
bool follow_execs = true;
pid_t profiler_pid = 0;
bool otel_profiler_mode = false;

decltype(&::getenv) getenv = &::getenv;
decltype(&::putenv) putenv = &::putenv;
Expand Down Expand Up @@ -151,6 +153,8 @@ void init_state() {

auto *follow_execs_env = g_state.getenv(k_allocation_profiling_follow_execs);
g_state.follow_execs = !(follow_execs_env && arg_no(follow_execs_env));
g_state.otel_profiler_mode =
g_state.getenv("DD_PROFILING_NATIVE_OTEL_MODE") != nullptr;

init_logger();
g_state.initialized = true;
Expand Down Expand Up @@ -323,6 +327,38 @@ int ddprof_start_profiling_internal() {
return -1;
}

if (g_state.otel_profiler_mode) {
auto *allocation_profiling_rate_str =
g_state.getenv("DD_PROFILING_NATIVE_ALLOCATION_PROFILING_RATE");
int64_t allocation_profiling_rate = 524288;
if (allocation_profiling_rate_str) {
(void)absl::SimpleAtoi(allocation_profiling_rate_str,
&allocation_profiling_rate);
}
uint32_t flags = AllocationTracker::kOtelProfilerMode;
if (allocation_profiling_rate < 0) {
flags |= AllocationTracker::kDeterministicSampling;
allocation_profiling_rate = -allocation_profiling_rate;
}
constexpr std::chrono::milliseconds initial_loaded_libs_check_delay{5000};
constexpr std::chrono::milliseconds loaded_libs_check_interval{59000};

try {
if (IsDDResOK(AllocationTracker::allocation_tracking_init(
allocation_profiling_rate, flags, 0, RingBufferInfo{},
{update_overrides, initial_loaded_libs_check_delay,
loaded_libs_check_interval}))) {
setup_overrides();
g_state.allocation_profiling_started = true;
} else {
LG_ERR("Failed to start allocation profiling\n");
return -1;
}
} catch (const DDException &e) { return -1; }

return 0;
}

auto socket_path = get_ddprof_socket_path();
pid_t const target_pid = getpid();

Expand Down Expand Up @@ -398,6 +434,7 @@ int ddprof_start_profiling_internal() {
g_state.allocation_profiling_started = true;
} else {
LG_ERR("Failed to start allocation profiling\n");
return -1;
}
}
} catch (const DDException &e) { return -1; }
Expand Down
12 changes: 9 additions & 3 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -314,13 +314,19 @@ set(ALLOCATION_TRACKER_UT_SRCS

add_unit_test(
allocation_tracker-ut ${ALLOCATION_TRACKER_UT_SRCS}
LIBRARIES ${ELFUTILS_LIBRARIES} llvm-demangle dl rt Datadog::Profiling
LIBRARIES ${ELFUTILS_LIBRARIES} llvm-demangle dl rt Datadog::Profiling systemtap
DEFINITIONS ${DDPROF_DEFINITION_LIST} KMAX_TRACKED_ALLOCATIONS=16384)

if(TARGET jemalloc::jemalloc_shared)
add_unit_test(
allocation_tracker_jemalloc-ut ${ALLOCATION_TRACKER_UT_SRCS}
LIBRARIES ${ELFUTILS_LIBRARIES} llvm-demangle dl rt jemalloc::jemalloc_shared Datadog::Profiling
LIBRARIES ${ELFUTILS_LIBRARIES}
llvm-demangle
dl
rt
jemalloc::jemalloc_shared
Datadog::Profiling
systemtap
DEFINITIONS ${DDPROF_DEFINITION_LIST} KMAX_TRACKED_ALLOCATIONS=16384 USE_JEMALLOC=1)
endif()

Expand Down Expand Up @@ -431,7 +437,7 @@ add_benchmark(
../src/tsc_clock.cc
../src/user_override.cc
../src/sys_utils.cc
LIBRARIES ${ELFUTILS_LIBRARIES} llvm-demangle
LIBRARIES ${ELFUTILS_LIBRARIES} llvm-demangle systemtap
DEFINITIONS ${DDPROF_DEFINITION_LIST} KMAX_TRACKED_ALLOCATIONS=16384)

if(NOT CMAKE_BUILD_TYPE STREQUAL "SanitizedDebug")
Expand Down
1 change: 1 addition & 0 deletions third_party/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(CLI)
add_subdirectory(llvm)
add_subdirectory(systemtap)
2 changes: 2 additions & 0 deletions third_party/systemtap/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_library(systemtap INTERFACE)
target_include_directories(systemtap INTERFACE include/)
6 changes: 6 additions & 0 deletions third_party/systemtap/include/sys/sdt-config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* @configure_input@

This file just defines _SDT_ASM_SECTION_AUTOGROUP_SUPPORT to 0 or 1 to
indicate whether the assembler supports "?" in .pushsection directives. */

#define _SDT_ASM_SECTION_AUTOGROUP_SUPPORT 1
Loading