Skip to content

Commit e738daa

Browse files
chore(profiling): improve readability/add comments
1 parent 61c07d1 commit e738daa

File tree

2 files changed

+49
-22
lines changed

2 files changed

+49
-22
lines changed

ddtrace/internal/datadog/profiling/stack_v2/echion/echion/render.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <echion/errors.h>
1414
#include <echion/timing.h>
1515

16+
#include <Python.h>
17+
1618
// Forward declaration
1719
class Frame;
1820

@@ -29,27 +31,52 @@ class RendererInterface
2931
virtual void close() = 0;
3032
virtual void header() = 0;
3133
virtual void metadata(const std::string& label, const std::string& value) = 0;
34+
3235
// If a renderer has its own caching mechanism for frames, this can be used
3336
// to store frame information.
3437
virtual void
3538
frame(uintptr_t key, uintptr_t filename, uintptr_t name, int line, int line_end, int column, int column_end) = 0;
36-
// Refers to the frame stored using above function
39+
40+
// Refers to the frame stored using the renderer's frame function
3741
virtual void frame_ref(uintptr_t key) = 0;
3842
virtual void frame_kernel(const std::string& scope) = 0;
39-
// Simlar to frame/frame_ref functions, helpers for string tables
43+
44+
// If a renderer has its own caching mechanism for strings, this can be used
45+
// to store string information.
4046
virtual void string(uintptr_t key, const std::string& value) = 0;
47+
48+
// Refers to the string stored using the renderer's string function
4149
virtual void string_ref(uintptr_t key) = 0;
4250

51+
// Called to render a message from the profiler.
4352
virtual void render_message(std::string_view msg) = 0;
53+
54+
// Called once for each Thread being sampled.
55+
// Pushes the Thread state but not its current Stack(s).
4456
virtual void render_thread_begin(PyThreadState* tstate,
4557
std::string_view name,
4658
microsecond_t cpu_time,
4759
uintptr_t thread_id,
4860
unsigned long native_id) = 0;
61+
62+
// Called once for each Task being sampled on the Thread.
63+
// Called after render_thread_begin and before render_stack_begin.
4964
virtual void render_task_begin(std::string task_name, bool on_cpu) = 0;
65+
66+
// Called once for each Stack being sampled on the Task.
67+
// Called after render_task_begin and before render_frame.
5068
virtual void render_stack_begin(long long pid, long long iid, const std::string& thread_name) = 0;
69+
70+
// Called once for each Frame being sampled on the Stack.
71+
// Called after render_stack_begin and before render_stack_end.
5172
virtual void render_frame(Frame& frame) = 0;
73+
74+
// Called once for each CPU time being sampled on the Thread.
75+
// Called after render_frame and before render_stack_end.
5276
virtual void render_cpu_time(uint64_t cpu_time) = 0;
77+
78+
// Called once for each Stack being sampled on the Thread.
79+
// Called after render_stack_begin, all render_frame calls and all render_cpu_time calls.
5380
virtual void render_stack_end(MetricType metric_type, uint64_t delta) = 0;
5481

5582
// The validity of the interface is a two-step process

ddtrace/internal/datadog/profiling/stack_v2/echion/echion/threads.h

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -395,23 +395,13 @@ ThreadInfo::sample(int64_t iid, PyThreadState* tstate, microsecond_t delta)
395395

396396
Renderer::get().render_cpu_time(thread_is_running ? cpu_time - previous_cpu_time : 0);
397397

398-
unwind(tstate);
398+
this->unwind(tstate);
399399

400-
// Asyncio tasks
401-
if (current_tasks.empty()) {
402-
// If we don't have any asyncio tasks, we check that we don't have any
403-
// greenlets either. In this case, we print the ordinary thread stack.
404-
// With greenlets, we recover the thread stack from the active greenlet,
405-
// so if we don't skip here we would have a double print.
406-
if (current_greenlets.empty()) {
407-
// Print the PID and thread name
408-
Renderer::get().render_stack_begin(pid, iid, name);
409-
// Print the stack
410-
python_stack.render();
411-
412-
Renderer::get().render_stack_end(MetricType::Time, delta);
413-
}
414-
} else {
400+
// Render in this order of priority
401+
// 1. asyncio Tasks stacks (if any)
402+
// 2. Greenlets stacks (if any)
403+
// 3. The normal thread stack (if no asyncio tasks or greenlets)
404+
if (!current_tasks.empty()) {
415405
for (auto& task_stack_info : current_tasks) {
416406
auto maybe_task_name = string_table.lookup(task_stack_info->task_name);
417407
if (!maybe_task_name) {
@@ -428,10 +418,7 @@ ThreadInfo::sample(int64_t iid, PyThreadState* tstate, microsecond_t delta)
428418
}
429419

430420
current_tasks.clear();
431-
}
432-
433-
// Greenlet stacks
434-
if (!current_greenlets.empty()) {
421+
} else if (!current_greenlets.empty()) {
435422
for (auto& greenlet_stack : current_greenlets) {
436423
auto maybe_task_name = string_table.lookup(greenlet_stack->task_name);
437424
if (!maybe_task_name) {
@@ -449,6 +436,19 @@ ThreadInfo::sample(int64_t iid, PyThreadState* tstate, microsecond_t delta)
449436
}
450437

451438
current_greenlets.clear();
439+
} else {
440+
// If we don't have any asyncio tasks, we check that we don't have any
441+
// greenlets either. In this case, we print the ordinary thread stack.
442+
// With greenlets, we recover the thread stack from the active greenlet,
443+
// so if we don't skip here we would have a double print.
444+
if (current_greenlets.empty()) {
445+
// Print the PID and thread name
446+
Renderer::get().render_stack_begin(pid, iid, name);
447+
// Print the stack
448+
python_stack.render();
449+
450+
Renderer::get().render_stack_end(MetricType::Time, delta);
451+
}
452452
}
453453

454454
return Result<void>::ok();

0 commit comments

Comments
 (0)