Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
sanchda authored and taegyunkim committed Jan 30, 2025
1 parent acbcbdb commit c18b1f6
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ class Sampler
// Parameters
uint64_t echion_frame_cache_size = g_default_echion_frame_cache_size;

// Helper function; implementation of the echion sampling thread
void sampling_thread(const uint64_t seq_num);

// This is a singleton, so no public constructor
Sampler();

Expand All @@ -37,7 +34,7 @@ class Sampler
public:
// Singleton instance
static Sampler& get();
void start();
bool start();
void stop();
void register_thread(uint64_t id, uint64_t native_id, const char* name);
void unregister_thread(uint64_t id);
Expand All @@ -46,6 +43,7 @@ class Sampler
PyObject* _asyncio_scheduled_tasks,
PyObject* _asyncio_eager_tasks);
void link_tasks(PyObject* parent, PyObject* child);
void sampling_thread(const uint64_t seq_num);

// The Python side dynamically adjusts the sampling rate based on overhead, so we need to be able to update our
// own intervals accordingly. Rather than a preemptive measure, we assume the rate is ~fairly stable and just
Expand Down
68 changes: 39 additions & 29 deletions ddtrace/internal/datadog/profiling/stack_v2/src/sampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,47 @@

using namespace Datadog;


// Helper class for spawning a std::thread with control over its default stack size
#ifdef __linux__
#include <unistd.h>
#include <sys/resource.h>
template <typename Function, typename... Args>
pthread_t create_thread_with_stack(size_t stack_size, Function&& f, Args&&... args) {
#include <unistd.h>

struct ThreadArgs
{
Sampler* sampler;
uint64_t seq_num;
};

void*
call_sampling_thread(void* args)
{
ThreadArgs* thread_args = static_cast<ThreadArgs*>(args);
Sampler* sampler = thread_args->sampler;
sampler->sampling_thread(thread_args->seq_num);
return nullptr;
}

pthread_t
create_thread_with_stack(size_t stack_size, Sampler* sampler, uint64_t seq_num)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
if (pthread_attr_init(&attr) != 0) {
return 0;
}
if (stack_size > 0) {
pthread_attr_setstacksize(&attr, stack_size);
}

// DAS: I think std::bind here is necessary?
pthread_t thread;
auto* thread_func = new auto(
std::bind(std::forward<Function>(f), std::forward<Args>(args)...)
);

int ret = pthread_create(
&thread,
&attr,
[](void* arg) -> void* {
auto* func = static_cast<decltype(thread_func)>(arg);
(*func)();
delete func;
return nullptr;
},
thread_func
);
pthread_t thread_id;
ThreadArgs thread_args = { sampler, seq_num };
int ret = pthread_create(&thread_id, &attr, call_sampling_thread, &thread_args);

pthread_attr_destroy(&attr);

if (ret != 0) {
delete thread_func;
throw std::runtime_error("Failed to create thread");
return 0;
}
return thread;
return thread_id;
}
#endif

Expand Down Expand Up @@ -175,7 +178,7 @@ Sampler::unregister_thread(uint64_t id)
thread_info_map.erase(id);
}

void
bool
Sampler::start()
{
static std::once_flag once;
Expand All @@ -188,11 +191,18 @@ Sampler::start()
// We might as well get the default stack size and use that
rlimit stack_sz = {};
getrlimit(RLIMIT_STACK, &stack_sz);
create_thread_with_stack(stack_sz.rlim_cur, &Sampler::sampling_thread, this, ++thread_seq_num); // leak the thread
if (create_thread_with_stack(stack_sz.rlim_cur, this, ++thread_seq_num) == 0) {
return false;
}
#else
std::thread t(&Sampler::sampling_thread, this, ++thread_seq_num);
t.detach();
try {
std::thread t(&Sampler::sampling_thread, this, ++thread_seq_num);
t.detach();
} catch (const std::exception& e) {
return false;
}
#endif
return true;
}

void
Expand Down
6 changes: 4 additions & 2 deletions ddtrace/internal/datadog/profiling/stack_v2/src/stack_v2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ _stack_v2_start(PyObject* self, PyObject* args, PyObject* kwargs)
}

Sampler::get().set_interval(min_interval_s);
Sampler::get().start();
Py_RETURN_NONE;
if (Sampler::get().start()) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
}

// Bypasses the old-style cast warning with an unchecked helper function
Expand Down

0 comments on commit c18b1f6

Please sign in to comment.