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
15 changes: 14 additions & 1 deletion libdd-profiling-heap-allocator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
//! # Example
//!
//! ```no_run
//! use libdd_profiling_heap_allocator::{set_default_sampling_distance, SampledAllocator};
//! use libdd_profiling_heap_allocator::{
//! is_profiler_attached, set_default_sampling_distance, SampledAllocator,
//! };
//! use std::alloc::System;
//!
//! #[global_allocator]
Expand All @@ -41,6 +43,17 @@ mod allocator;

pub use allocator::SampledAllocator;

/// Returns true when an external profiler is currently attached to the
/// allocator's `ddheap:alloc` USDT.
///
/// This is a direct read of the USDT semaphore. It is intentionally racy: a
/// profiler can attach or detach immediately after this returns. Use it as a
/// best-effort readiness/diagnostic signal, not as a synchronization primitive.
#[inline]
pub fn is_profiler_attached() -> bool {
libdd_profiling_heap_sampler::is_profiler_attached()
}

/// Set the default mean sample distance (bytes between samples) for the
/// heap sampler.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@

#include <datadog/heap/tl_state.h>

#ifdef __linux__
# include <usdt.h>
#else
# define USDT_IS_ACTIVE(group, name) (1)
#endif

/*
* Return type for dd_allocation_requested, paired with the `req`
* argument of dd_allocation_created.
Expand Down Expand Up @@ -107,6 +113,10 @@ static inline __attribute__((always_inline, warn_unused_result))
dd_alloc_req_t dd_allocation_requested(size_t size, size_t alignment) {
dd_alloc_req_t out = { size, size, alignment, 0 };

// If no tracer is attached to ddheap:alloc, skip all sampling logic.
// Single volatile u16 read; branch is almost always not-taken at runtime.
if (__builtin_expect(!USDT_IS_ACTIVE(ddheap, alloc), 1)) return out;

// If we don't have TLS yet (this is defensive and should never happen), or
// the reentry guard is set (meaning a sampled allocation is already in
// flight on this thread and something in its slow path triggered another
Expand Down
12 changes: 12 additions & 0 deletions libdd-profiling-heap-sampler/include/datadog/heap/probes.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#ifndef DD_SAMPLERS_PROBES_H
#define DD_SAMPLERS_PROBES_H

#include <stdbool.h>
#include <stdint.h>

#ifdef __linux__
Expand Down Expand Up @@ -42,4 +43,15 @@ void dd_probe_alloc(void *user, uint64_t size, uint64_t weight);
*/
void dd_probe_free(void *ptr);

/*
* Returns true when an external profiler is currently attached to the
* ddheap:alloc USDT in this object file.
*
* This is a direct read of the alloc probe's USDT semaphore. It is therefore
* intentionally racy: a profiler can attach or detach immediately after this
* function returns. Use it only as a best-effort readiness/diagnostic signal,
* not as a synchronization primitive.
*/
bool dd_heap_profiler_attached(void);

#endif
28 changes: 28 additions & 0 deletions libdd-profiling-heap-sampler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,34 @@
unsafe { sys::dd_set_default_sampling_interval(distance_bytes) }
}

#[cfg(target_os = "linux")]
extern "C" {
#[link_name = "dd_heap_profiler_attached"]
fn dd_heap_profiler_attached_ffi() -> bool;
}

/// Returns true when an external profiler is currently attached to the
/// `ddheap:alloc` USDT in this object file.
///
/// This is a direct read of the alloc probe's USDT semaphore. It is intentionally
/// racy: a profiler can attach or detach immediately after this returns. Use it
/// as a best-effort readiness/diagnostic signal, not as a synchronization
/// primitive.
#[cfg(target_os = "linux")]
#[inline]
pub fn is_profiler_attached() -> bool {
// SAFETY: dd_heap_profiler_attached performs a single semaphore read and
// has no preconditions.
unsafe { dd_heap_profiler_attached_ffi() }
}

/// Non-Linux builds do not expose USDT heap probes.
#[cfg(not(target_os = "linux"))]
#[inline]
pub fn is_profiler_attached() -> bool {
false
}

/// Whether heap sampling is enabled for this process. Users of this
/// library can use this to check if they should setup allocation tracking
/// or not.
Expand Down Expand Up @@ -192,7 +220,7 @@
);
})
.join()
.unwrap();

Check failure on line 223 in libdd-profiling-heap-sampler/src/lib.rs

View workflow job for this annotation

GitHub Actions / [ubuntu-latest:1.87.0] test report

libdd-profiling-heap-sampler/src/lib.rs.tests::requested_initializes_tls_on_first_use

thread 'tests::requested_initializes_tls_on_first_use' panicked at libdd-profiling-heap-sampler/src/lib.rs:223:10
Raw output
thread 'tests::requested_initializes_tls_on_first_use' panicked at libdd-profiling-heap-sampler/src/lib.rs:223:10:
called `Result::unwrap()` on an `Err` value: Any { .. }
}

#[test]
Expand Down
10 changes: 8 additions & 2 deletions libdd-profiling-heap-sampler/src/probes.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@
#include <datadog/heap/sample_flag.h>

#include <errno.h>
#include <stdbool.h>

/* Save / restore errno: an attached USDT consumer may perturb it. */
void dd_probe_alloc(void *user, uint64_t size, uint64_t weight) {
int saved_errno = errno;
USDT(ddheap, alloc, user, size, weight);
USDT_WITH_SEMA(ddheap, alloc, user, size, weight);
errno = saved_errno;
}

void dd_probe_free(void *ptr) {
#if DD_HEAP_LIVE_TRACKING
if (!USDT_IS_ACTIVE(ddheap, free)) return;
int saved_errno = errno;
USDT(ddheap, free, ptr);
USDT_WITH_SEMA(ddheap, free, ptr);
errno = saved_errno;
#else
(void)ptr;
#endif
}

bool dd_heap_profiler_attached(void) {
return USDT_IS_ACTIVE(ddheap, alloc);
}
Loading