Skip to content

Commit 9866b28

Browse files
committed
refactor(profiling): split stack sampler helpers
1 parent 1a6d423 commit 9866b28

2 files changed

Lines changed: 45 additions & 32 deletions

File tree

ddtrace/internal/datadog/profiling/stack/src/echion/threads.cc

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -707,29 +707,19 @@ ThreadInfo::unwind_greenlets(EchionSampler& echion, PyThreadState* tstate, unsig
707707
}
708708
}
709709

710-
// ----------------------------------------------------------------------------
711-
Result<void>
712-
ThreadInfo::sample(EchionSampler& echion, PyThreadState* tstate, microsecond_t delta)
710+
namespace {
711+
712+
void
713+
render_unwound_stacks(EchionSampler& echion, ThreadInfo& thread)
713714
{
714715
auto& renderer = echion.renderer();
715-
renderer.render_thread_begin(tstate, name, delta, thread_id, native_id);
716-
717-
microsecond_t previous_cpu_time = cpu_time;
718-
auto update_cpu_time_success = update_cpu_time();
719-
if (!update_cpu_time_success) {
720-
return ErrorKind::CpuTimeError;
721-
}
722-
723-
renderer.render_cpu_time(cpu_time - previous_cpu_time);
724-
725-
this->unwind(echion, tstate);
726716

727717
// Render in this order of priority
728718
// 1. asyncio Tasks stacks (if any)
729719
// 2. Greenlets stacks (if any)
730720
// 3. The normal thread stack (if no asyncio tasks or greenlets)
731-
if (!current_tasks.empty()) {
732-
for (auto& task_stack_info : current_tasks) {
721+
if (!thread.current_tasks.empty()) {
722+
for (auto& task_stack_info : thread.current_tasks) {
733723
task_stack_info->task_name.visit_string(
734724
[&](std::string_view task_name) { renderer.render_task_begin(task_name, task_stack_info->on_cpu); });
735725

@@ -738,9 +728,9 @@ ThreadInfo::sample(EchionSampler& echion, PyThreadState* tstate, microsecond_t d
738728
renderer.render_stack_end();
739729
}
740730

741-
current_tasks.clear();
742-
} else if (!current_greenlets.empty()) {
743-
for (auto& greenlet_stack : current_greenlets) {
731+
thread.current_tasks.clear();
732+
} else if (!thread.current_greenlets.empty()) {
733+
for (auto& greenlet_stack : thread.current_greenlets) {
744734
greenlet_stack->task_name.visit_string(
745735
[&](std::string_view task_name) { renderer.render_task_begin(task_name, greenlet_stack->on_cpu); });
746736

@@ -750,11 +740,32 @@ ThreadInfo::sample(EchionSampler& echion, PyThreadState* tstate, microsecond_t d
750740
renderer.render_stack_end();
751741
}
752742

753-
current_greenlets.clear();
743+
thread.current_greenlets.clear();
754744
} else {
755-
python_stack.render(echion);
745+
thread.python_stack.render(echion);
756746
renderer.render_stack_end();
757747
}
748+
}
749+
750+
} // namespace
751+
752+
// ----------------------------------------------------------------------------
753+
Result<void>
754+
ThreadInfo::sample(EchionSampler& echion, PyThreadState* tstate, microsecond_t delta)
755+
{
756+
auto& renderer = echion.renderer();
757+
renderer.render_thread_begin(tstate, name, delta, thread_id, native_id);
758+
759+
microsecond_t previous_cpu_time = cpu_time;
760+
auto update_cpu_time_success = update_cpu_time();
761+
if (!update_cpu_time_success) {
762+
return ErrorKind::CpuTimeError;
763+
}
764+
765+
renderer.render_cpu_time(cpu_time - previous_cpu_time);
766+
767+
this->unwind(echion, tstate);
768+
render_unwound_stacks(echion, *this);
758769

759770
return Result<void>::ok();
760771
}

ddtrace/internal/datadog/profiling/stack/src/sampler.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ create_thread_with_stack(size_t stack_size, Sampler* sampler, uint64_t seq_num)
8080

8181
namespace {
8282

83+
void
84+
log_thread_registration_failure_once(uint64_t id, uint64_t native_id, const char* name)
85+
{
86+
static bool has_errored = false;
87+
if (!has_errored) {
88+
has_errored = true;
89+
std::cerr << "Failed to register thread: " << std::hex << id << std::dec << " (" << native_id << ") " << name
90+
<< std::endl;
91+
}
92+
}
93+
8394
// Returns the CPU time of the calling thread in microseconds, or 0 on error.
8495
uint64_t
8596
get_thread_cpu_time_us()
@@ -600,29 +611,20 @@ Sampler::register_thread(uint64_t id, uint64_t native_id, const char* name)
600611
// Registering threads requires coordinating with one of echion's global locks, which we take here.
601612
const std::lock_guard<std::mutex> thread_info_guard{ echion->thread_info_map_lock() };
602613

603-
static bool has_errored = false;
604614
auto it = echion->thread_info_map().find(id);
605615
if (it == echion->thread_info_map().end()) {
606616
auto maybe_thread_info = ThreadInfo::create(id, native_id, name);
607617
if (maybe_thread_info) {
608618
echion->thread_info_map().emplace(id, std::move(*maybe_thread_info));
609619
} else {
610-
if (!has_errored) {
611-
has_errored = true;
612-
std::cerr << "Failed to register thread: " << std::hex << id << std::dec << " (" << native_id << ") "
613-
<< name << std::endl;
614-
}
620+
log_thread_registration_failure_once(id, native_id, name);
615621
}
616622
} else {
617623
auto maybe_thread_info = ThreadInfo::create(id, native_id, name);
618624
if (maybe_thread_info) {
619625
it->second = std::move(*maybe_thread_info);
620626
} else {
621-
if (!has_errored) {
622-
has_errored = true;
623-
std::cerr << "Failed to register thread: " << std::hex << id << std::dec << " (" << native_id << ") "
624-
<< name << std::endl;
625-
}
627+
log_thread_registration_failure_once(id, native_id, name);
626628
}
627629
}
628630
}

0 commit comments

Comments
 (0)