Skip to content

Commit 4c898d7

Browse files
chore(profiling): remove unused coremodule functionality
1 parent fdccddc commit 4c898d7

File tree

1 file changed

+0
-307
lines changed
  • ddtrace/internal/datadog/profiling/stack_v2/src/echion

1 file changed

+0
-307
lines changed

ddtrace/internal/datadog/profiling/stack_v2/src/echion/coremodule.cc

Lines changed: 0 additions & 307 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#endif
1111

1212
#include <mutex>
13-
#include <thread>
1413

1514
#include <fcntl.h>
1615
#include <sched.h>
@@ -31,153 +30,12 @@
3130
#include <echion/threads.h>
3231
#include <echion/timing.h>
3332

34-
// ----------------------------------------------------------------------------
35-
static inline void _start()
36-
{
37-
init_frame_cache(CACHE_MAX_ENTRIES);
38-
39-
auto open_success = Renderer::get().open();
40-
if (!open_success)
41-
{
42-
PyErr_SetString(PyExc_RuntimeError, "Failed to open renderer");
43-
return;
44-
}
45-
46-
#if defined PL_DARWIN
47-
// Get the wall time clock resource.
48-
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
49-
#endif
50-
51-
Renderer::get().header();
52-
53-
Renderer::get().metadata("mode", (cpu ? "cpu" : "wall"));
54-
Renderer::get().metadata("interval", std::to_string(interval));
55-
Renderer::get().metadata("sampler", "echion");
56-
57-
// DEV: Workaround for the austin-python library: we send an empty sample
58-
// to set the PID. We also map the key value 0 to the empty string, to
59-
// support task name frames.
60-
Renderer::get().render_stack_begin(pid, 0, "MainThread");
61-
Renderer::get().string(0, "");
62-
Renderer::get().string(1, "<invalid>");
63-
Renderer::get().string(2, "<unknown>");
64-
Renderer::get().render_stack_end(MetricType::Time, 0);
65-
}
66-
67-
// ----------------------------------------------------------------------------
68-
static inline void _stop()
69-
{
70-
// Clean up the thread info map. When not running async, we need to guard
71-
// the map lock because we are not in control of the sampling thread.
72-
{
73-
const std::lock_guard<std::mutex> guard(thread_info_map_lock);
74-
75-
thread_info_map.clear();
76-
string_table.clear();
77-
}
78-
79-
#if defined PL_DARWIN
80-
mach_port_deallocate(mach_task_self(), cclock);
81-
#endif
82-
83-
Renderer::get().close();
84-
85-
reset_frame_cache();
86-
}
87-
88-
// ----------------------------------------------------------------------------
89-
static inline void _sampler()
90-
{
91-
// This function can run without the GIL on the basis that these assumptions
92-
// hold:
93-
// 1. The interpreter state object lives as long as the process itself.
94-
95-
last_time = gettime();
96-
97-
while (running)
98-
{
99-
microsecond_t now = gettime();
100-
microsecond_t end_time = now + interval;
101-
microsecond_t wall_time = now - last_time;
102-
103-
for_each_interp([=](InterpreterInfo& interp) -> void {
104-
for_each_thread(interp, [=](PyThreadState* tstate, ThreadInfo& thread) {
105-
auto sample_success = thread.sample(interp.id, tstate, wall_time);
106-
if (!sample_success)
107-
{
108-
// Silently skip sampling this thread
109-
}
110-
});
111-
});
112-
113-
std::this_thread::sleep_for(std::chrono::microseconds(end_time - now));
114-
last_time = now;
115-
}
116-
}
117-
118-
static void sampler()
119-
{
120-
_start();
121-
_sampler();
122-
_stop();
123-
}
124-
12533
// ----------------------------------------------------------------------------
12634
static void _init()
12735
{
12836
pid = getpid();
12937
}
13038

131-
// ----------------------------------------------------------------------------
132-
static PyObject* start_async(PyObject* Py_UNUSED(m), PyObject* Py_UNUSED(args))
133-
{
134-
if (!running)
135-
{
136-
// TODO: Since we have a global state, we should not allow multiple ways
137-
// of starting the sampler.
138-
if (sampler_thread == nullptr)
139-
{
140-
running = 1;
141-
sampler_thread = new std::thread(sampler);
142-
}
143-
}
144-
145-
Py_RETURN_NONE;
146-
}
147-
148-
// ----------------------------------------------------------------------------
149-
static PyObject* start(PyObject* Py_UNUSED(m), PyObject* Py_UNUSED(args))
150-
{
151-
if (!running)
152-
{
153-
// TODO: Since we have a global state, we should not allow multiple ways
154-
// of starting the sampler.
155-
running = 1;
156-
157-
// Run the sampler without the GIL
158-
Py_BEGIN_ALLOW_THREADS;
159-
sampler();
160-
Py_END_ALLOW_THREADS;
161-
}
162-
163-
Py_RETURN_NONE;
164-
}
165-
166-
// ----------------------------------------------------------------------------
167-
static PyObject* stop(PyObject* Py_UNUSED(m), PyObject* Py_UNUSED(args))
168-
{
169-
running = 0;
170-
171-
// Stop the sampling thread
172-
if (sampler_thread != nullptr)
173-
{
174-
sampler_thread->join();
175-
sampler_thread = nullptr;
176-
}
177-
178-
Py_RETURN_NONE;
179-
}
180-
18139
// ----------------------------------------------------------------------------
18240
static PyObject* track_thread(PyObject* Py_UNUSED(m), PyObject* args)
18341
{
@@ -237,176 +95,11 @@ static PyObject* init(PyObject* Py_UNUSED(m), PyObject* Py_UNUSED(args))
23795
Py_RETURN_NONE;
23896
}
23997

240-
// ----------------------------------------------------------------------------
241-
static PyObject* track_asyncio_loop(PyObject* Py_UNUSED(m), PyObject* args)
242-
{
243-
uintptr_t thread_id; // map key
244-
PyObject* loop;
245-
246-
if (!PyArg_ParseTuple(args, "lO", &thread_id, &loop))
247-
return NULL;
248-
249-
{
250-
std::lock_guard<std::mutex> guard(thread_info_map_lock);
251-
252-
if (thread_info_map.find(thread_id) != thread_info_map.end())
253-
{
254-
thread_info_map.find(thread_id)->second->asyncio_loop =
255-
(loop != Py_None) ? reinterpret_cast<uintptr_t>(loop) : 0;
256-
}
257-
}
258-
259-
Py_RETURN_NONE;
260-
}
261-
262-
// ----------------------------------------------------------------------------
263-
static PyObject* init_asyncio(PyObject* Py_UNUSED(m), PyObject* args)
264-
{
265-
if (!PyArg_ParseTuple(args, "OOO", &asyncio_current_tasks, &asyncio_scheduled_tasks,
266-
&asyncio_eager_tasks))
267-
return NULL;
268-
269-
if (asyncio_eager_tasks == Py_None)
270-
asyncio_eager_tasks = NULL;
271-
272-
Py_RETURN_NONE;
273-
}
274-
275-
// ----------------------------------------------------------------------------
276-
static PyObject* track_greenlet(PyObject* Py_UNUSED(m), PyObject* args)
277-
{
278-
uintptr_t greenlet_id; // map key
279-
PyObject* name;
280-
PyObject* frame;
281-
282-
if (!PyArg_ParseTuple(args, "lOO", &greenlet_id, &name, &frame))
283-
return NULL;
284-
285-
StringTable::Key greenlet_name;
286-
287-
auto maybe_greenlet_name = string_table.key(name);
288-
if (!maybe_greenlet_name)
289-
{
290-
// We failed to get this task but we keep going
291-
PyErr_SetString(PyExc_RuntimeError, "Failed to get greenlet name from the string table");
292-
return NULL;
293-
}
294-
greenlet_name = *maybe_greenlet_name;
295-
296-
{
297-
const std::lock_guard<std::mutex> guard(greenlet_info_map_lock);
298-
299-
auto entry = greenlet_info_map.find(greenlet_id);
300-
if (entry != greenlet_info_map.end())
301-
// Greenlet is already tracked so we update its info. This should
302-
// never happen, as a greenlet should be tracked only once, so we
303-
// use this as a safety net.
304-
entry->second = std::make_unique<GreenletInfo>(greenlet_id, frame, greenlet_name);
305-
else
306-
greenlet_info_map.emplace(
307-
greenlet_id, std::make_unique<GreenletInfo>(greenlet_id, frame, greenlet_name));
308-
309-
// Update the thread map
310-
auto native_id = PyThread_get_thread_native_id();
311-
greenlet_thread_map[native_id] = greenlet_id;
312-
}
313-
314-
Py_RETURN_NONE;
315-
}
316-
317-
// ----------------------------------------------------------------------------
318-
static PyObject* untrack_greenlet(PyObject* Py_UNUSED(m), PyObject* args)
319-
{
320-
uintptr_t greenlet_id;
321-
if (!PyArg_ParseTuple(args, "l", &greenlet_id))
322-
return NULL;
323-
324-
{
325-
const std::lock_guard<std::mutex> guard(greenlet_info_map_lock);
326-
327-
greenlet_info_map.erase(greenlet_id);
328-
greenlet_parent_map.erase(greenlet_id);
329-
greenlet_thread_map.erase(greenlet_id);
330-
}
331-
Py_RETURN_NONE;
332-
}
333-
334-
// ----------------------------------------------------------------------------
335-
static PyObject* link_greenlets(PyObject* Py_UNUSED(m), PyObject* args)
336-
{
337-
uintptr_t parent, child;
338-
339-
if (!PyArg_ParseTuple(args, "ll", &child, &parent))
340-
return NULL;
341-
342-
{
343-
std::lock_guard<std::mutex> guard(greenlet_info_map_lock);
344-
345-
greenlet_parent_map[child] = parent;
346-
}
347-
348-
Py_RETURN_NONE;
349-
}
350-
351-
// ----------------------------------------------------------------------------
352-
static PyObject* update_greenlet_frame(PyObject* Py_UNUSED(m), PyObject* args)
353-
{
354-
uintptr_t greenlet_id;
355-
PyObject* frame;
356-
357-
if (!PyArg_ParseTuple(args, "lO", &greenlet_id, &frame))
358-
return NULL;
359-
360-
{
361-
std::lock_guard<std::mutex> guard(greenlet_info_map_lock);
362-
363-
auto entry = greenlet_info_map.find(greenlet_id);
364-
if (entry != greenlet_info_map.end())
365-
{
366-
// Update the frame of the greenlet
367-
entry->second->frame = frame;
368-
}
369-
}
370-
371-
Py_RETURN_NONE;
372-
}
373-
374-
// ----------------------------------------------------------------------------
375-
static PyObject* link_tasks(PyObject* Py_UNUSED(m), PyObject* args)
376-
{
377-
PyObject *parent, *child;
378-
379-
if (!PyArg_ParseTuple(args, "OO", &parent, &child))
380-
return NULL;
381-
382-
{
383-
std::lock_guard<std::mutex> guard(task_link_map_lock);
384-
385-
task_link_map[child] = parent;
386-
}
387-
388-
Py_RETURN_NONE;
389-
}
390-
39198
// ----------------------------------------------------------------------------
39299
static PyMethodDef echion_core_methods[] = {
393-
{"start", start, METH_NOARGS, "Start the stack sampler"},
394-
{"start_async", start_async, METH_NOARGS, "Start the stack sampler asynchronously"},
395-
{"stop", stop, METH_NOARGS, "Stop the stack sampler"},
396100
{"track_thread", track_thread, METH_VARARGS, "Map the name of a thread with its identifier"},
397101
{"untrack_thread", untrack_thread, METH_VARARGS, "Untrack a terminated thread"},
398102
{"init", init, METH_NOARGS, "Initialize the stack sampler (usually after a fork)"},
399-
// Task support
400-
{"track_asyncio_loop", track_asyncio_loop, METH_VARARGS,
401-
"Map the name of a task with its identifier"},
402-
{"init_asyncio", init_asyncio, METH_VARARGS, "Initialise asyncio tracking"},
403-
{"link_tasks", link_tasks, METH_VARARGS, "Link two tasks"},
404-
// Greenlet support
405-
{"track_greenlet", track_greenlet, METH_VARARGS, "Map a greenlet with its identifier"},
406-
{"untrack_greenlet", untrack_greenlet, METH_VARARGS, "Untrack a terminated greenlet"},
407-
{"link_greenlets", link_greenlets, METH_VARARGS, "Link two greenlets"},
408-
{"update_greenlet_frame", update_greenlet_frame, METH_VARARGS,
409-
"Update the frame of a greenlet"},
410103
// Configuration interface
411104
{"set_interval", set_interval, METH_VARARGS, "Set the sampling interval"},
412105
{"set_cpu", set_cpu, METH_VARARGS, "Set whether to use CPU time instead of wall time"},

0 commit comments

Comments
 (0)