Skip to content

Commit 2864f97

Browse files
perf(profiling): intern strings/functions into libdatadog
1 parent b2b336f commit 2864f97

File tree

9 files changed

+316
-48
lines changed

9 files changed

+316
-48
lines changed

ddtrace/internal/datadog/profiling/dd_wrapper/include/ddup_interface.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ class Sample;
1414
extern "C"
1515
{
1616
#endif
17+
18+
using string_id_t = std::add_pointer<void>::type;
19+
using function_id_t = std::add_pointer<void>::type;
20+
21+
string_id_t ddup_intern_string(std::string_view s);
22+
function_id_t ddup_intern_function(string_id_t name, string_id_t filename);
23+
1724
void ddup_config_env(std::string_view dd_env);
1825
void ddup_config_service(std::string_view service);
1926
void ddup_config_version(std::string_view version);
@@ -65,6 +72,7 @@ extern "C"
6572
std::string_view _filename,
6673
uint64_t address,
6774
int64_t line);
75+
void ddup_push_frame_id(Datadog::Sample* sample, function_id_t function_id, uint64_t address, int64_t line);
6876
void ddup_push_absolute_ns(Datadog::Sample* sample, int64_t timestamp_ns);
6977
void ddup_push_monotonic_ns(Datadog::Sample* sample, int64_t monotonic_ns);
7078
void ddup_flush_sample(Datadog::Sample* sample);

ddtrace/internal/datadog/profiling/dd_wrapper/include/libdatadog_helpers.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <iostream>
55
#include <string>
66
#include <string_view>
7-
#include <variant>
87

98
extern "C"
109
{
@@ -139,6 +138,13 @@ add_tag(ddog_Vec_Tag& tags, const ExportTagKey key, std::string_view val, std::s
139138
return add_tag(tags, key_sv, val, errmsg);
140139
}
141140

141+
namespace internal {
142+
143+
ddog_prof_ProfilesDictionaryHandle
144+
get_profiles_dictionary();
145+
146+
} // namespace internal
147+
142148
// Keep macros from propagating
143149
#undef X_STR
144150
#undef X_ENUM

ddtrace/internal/datadog/profiling/dd_wrapper/include/profile.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ class Profile
6060
const ValueIndex& val();
6161

6262
// collect
63-
bool collect(const ddog_prof_Sample& sample, int64_t endtime_ns);
63+
bool collect(const ddog_prof_Sample2& sample, int64_t endtime_ns);
6464
};
6565
} // namespace Datadog

ddtrace/internal/datadog/profiling/dd_wrapper/include/sample.hpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ struct StringArena
5353

5454
} // namespace internal
5555

56+
using string_id = ddog_prof_StringId2;
57+
using function_id = ddog_prof_FunctionId2;
58+
59+
string_id
60+
intern_string(std::string_view s);
61+
function_id
62+
intern_function(string_id name, string_id filename);
63+
5664
class SampleManager; // friend
5765

5866
class Sample
@@ -70,12 +78,12 @@ class Sample
7078
static inline bool timeline_enabled = false;
7179

7280
// Keeps temporary buffer of frames in the stack
73-
std::vector<ddog_prof_Location> locations;
81+
std::vector<ddog_prof_Location2> locations;
7482
size_t dropped_frames = 0;
7583
uint64_t samples = 0;
7684

7785
// Storage for labels
78-
std::vector<ddog_prof_Label> labels{};
86+
std::vector<ddog_prof_Label2> labels{};
7987

8088
// Storage for values
8189
std::vector<int64_t> values = {};
@@ -91,6 +99,7 @@ class Sample
9199
bool push_label(ExportLabelKey key, std::string_view val);
92100
bool push_label(ExportLabelKey key, int64_t val);
93101
void push_frame_impl(std::string_view name, std::string_view filename, uint64_t address, int64_t line);
102+
void push_frame_impl(function_id function_id, uint64_t address, int64_t line);
94103
void clear_buffers();
95104

96105
// Add values
@@ -131,6 +140,12 @@ class Sample
131140
int64_t line // for ddog_prof_Location
132141
);
133142

143+
// Assumes frames are pushed in leaf-order
144+
void push_frame(function_id function_id, // for ddog_prof_Location
145+
uint64_t address, // for ddog_prof_Location
146+
int64_t line // for ddog_prof_Location
147+
);
148+
134149
// Flushes the current buffer, clearing it
135150
bool flush_sample(bool reverse_locations = false);
136151

ddtrace/internal/datadog/profiling/dd_wrapper/src/ddup_interface.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,38 @@
99
#include "uploader_builder.hpp"
1010

1111
#include <cstdlib>
12+
#include <datadog/profiling.h>
1213
#include <iostream>
1314
#include <unistd.h>
1415
#include <unordered_map>
1516

17+
// Dictionary state - needs to be at file scope so postfork can reset it
18+
namespace {
19+
20+
std::once_flag dict_init_flag;
21+
ddog_prof_ProfilesDictionaryHandle dict_handle = nullptr;
22+
23+
} // namespace
24+
25+
namespace Datadog::internal {
26+
27+
ddog_prof_ProfilesDictionaryHandle
28+
get_profiles_dictionary()
29+
{
30+
std::call_once(dict_init_flag, []() {
31+
auto result = ddog_prof_ProfilesDictionary_new(&dict_handle);
32+
if (result.flags) {
33+
std::cerr << "could not initialise profiles dictionary: " << result.err << std::endl;
34+
}
35+
36+
// TODO: how should we handle this case? Return a nullptr? If it happens, we're stuck.
37+
});
38+
39+
return dict_handle;
40+
}
41+
42+
} // namespace Datadog::internal
43+
1644
// State
1745
bool is_ddup_initialized = false; // NOLINT (cppcoreguidelines-avoid-non-const-global-variables)
1846
std::once_flag ddup_init_flag; // NOLINT (cppcoreguidelines-avoid-non-const-global-variables)
@@ -22,6 +50,16 @@ std::once_flag ddup_init_flag; // NOLINT (cppcoreguidelines-avoid-non-const-g
2250
void
2351
ddup_postfork_child()
2452
{
53+
// Drop the dictionary handle from the parent before resetting
54+
// The ProfilesDictionary is reference-counted, so we must drop our reference
55+
if (dict_handle != nullptr) {
56+
ddog_prof_ProfilesDictionary_drop(&dict_handle);
57+
}
58+
59+
// We need to re-initialize std::once_flag to allow re-creation
60+
new (&dict_init_flag) std::once_flag();
61+
dict_handle = nullptr;
62+
2563
Datadog::Uploader::postfork_child();
2664
Datadog::SampleManager::postfork_child();
2765
}
@@ -32,6 +70,16 @@ ddup_postfork_parent()
3270
Datadog::Uploader::postfork_parent();
3371
}
3472

73+
// Cleanup function to free the profiles dictionary on exit
74+
void
75+
ddup_cleanup()
76+
{
77+
if (dict_handle != nullptr) {
78+
ddog_prof_ProfilesDictionary_drop(&dict_handle);
79+
dict_handle = nullptr;
80+
}
81+
}
82+
3583
// Since we don't control the internal state of libdatadog's exporter and we want to prevent state-tearing
3684
// after a `fork()`, we just outright prevent uploads from happening during a `fork()` operation. Since a
3785
// new upload may be scheduled _just_ as `fork()` is entered, we also need to prevent new uploads from happening.
@@ -144,6 +192,11 @@ ddup_start() // cppcheck-suppress unusedFunction
144192
// Right now, only do things in the child _after_ fork
145193
pthread_atfork(ddup_prefork, ddup_postfork_parent, ddup_postfork_child);
146194

195+
Datadog::internal::get_profiles_dictionary();
196+
197+
// Register cleanup function to free resources on exit
198+
std::atexit(ddup_cleanup);
199+
147200
// Set the global initialization flag
148201
is_ddup_initialized = true;
149202
return true;
@@ -286,6 +339,28 @@ ddup_push_frame(Datadog::Sample* sample, // cppcheck-suppress unusedFunction
286339
sample->push_frame(_name, _filename, address, line);
287340
}
288341

342+
void
343+
ddup_push_frame_id(Datadog::Sample* sample,
344+
function_id_t function_id,
345+
uint64_t address,
346+
int64_t line) // cppcheck-suppress unusedFunction
347+
{
348+
349+
sample->push_frame(static_cast<Datadog::function_id>(function_id), address, line);
350+
}
351+
352+
string_id_t
353+
ddup_intern_string(std::string_view s) // cppcheck-suppress unusedFunction
354+
{
355+
return Datadog::intern_string(s);
356+
}
357+
358+
function_id_t
359+
ddup_intern_function(string_id_t name, string_id_t filename) // cppcheck-suppress unusedFunction
360+
{
361+
return Datadog::intern_function(static_cast<Datadog::string_id>(name), static_cast<Datadog::string_id>(filename));
362+
}
363+
289364
void
290365
ddup_push_absolute_ns(Datadog::Sample* sample, int64_t timestamp_ns) // cppcheck-suppress unusedFunction
291366
{

ddtrace/internal/datadog/profiling/dd_wrapper/src/profile.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "libdatadog_helpers.hpp"
44

5+
#include <datadog/profiling.h>
56
#include <functional>
67
#include <iostream>
78

@@ -55,6 +56,20 @@ Datadog::Profile::reset_profile()
5556
ddog_Error_drop(&err);
5657
return false;
5758
}
59+
60+
auto set_dictionary_res =
61+
ddog_prof_Profile_set_profiles_dictionary(&cur_profile, Datadog::internal::get_profiles_dictionary());
62+
if (set_dictionary_res.tag != DDOG_VOID_RESULT_OK) {
63+
auto err = set_dictionary_res.err;
64+
if (!already_warned) {
65+
already_warned = true;
66+
const std::string errmsg = err_to_msg(&err, "Error setting profiles dictionary");
67+
std::cerr << errmsg << std::endl;
68+
}
69+
ddog_Error_drop(&err);
70+
return false;
71+
}
72+
5873
return true;
5974
}
6075

@@ -185,6 +200,19 @@ Datadog::Profile::one_time_init(SampleType type, unsigned int _max_nframes)
185200
return;
186201
}
187202

203+
auto set_dictionary_res =
204+
ddog_prof_Profile_set_profiles_dictionary(&cur_profile, Datadog::internal::get_profiles_dictionary());
205+
if (set_dictionary_res.tag != DDOG_VOID_RESULT_OK) {
206+
auto err = set_dictionary_res.err;
207+
if (!already_warned) {
208+
already_warned = true;
209+
const std::string errmsg = err_to_msg(&err, "Error setting profiles dictionary");
210+
std::cerr << errmsg << std::endl;
211+
}
212+
ddog_Error_drop(&err);
213+
return;
214+
}
215+
188216
// We're done. Don't do this again.
189217
first_time.store(false);
190218
}
@@ -196,11 +224,12 @@ Datadog::Profile::val()
196224
}
197225

198226
bool
199-
Datadog::Profile::collect(const ddog_prof_Sample& sample, int64_t endtime_ns)
227+
Datadog::Profile::collect(const ddog_prof_Sample2& sample, int64_t endtime_ns)
200228
{
201229
static bool already_warned = false; // cppcheck-suppress threadsafety-threadsafety
202230
const std::lock_guard<std::mutex> lock(profile_mtx);
203-
auto res = ddog_prof_Profile_add(&cur_profile, sample, endtime_ns);
231+
232+
auto res = ddog_prof_Profile_add2(&cur_profile, sample, endtime_ns);
204233
if (!res.ok) { // NOLINT (cppcoreguidelines-pro-type-union-access)
205234
auto err = res.err; // NOLINT (cppcoreguidelines-pro-type-union-access)
206235
if (!already_warned) {

0 commit comments

Comments
 (0)