Skip to content

Commit ff3a20e

Browse files
try to intern strings/functions
1 parent 5f9fccd commit ff3a20e

File tree

8 files changed

+215
-46
lines changed

8 files changed

+215
-46
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ extern "C"
1111
#include "datadog/profiling.h"
1212
}
1313

14+
ddog_prof_ProfilesDictionaryHandle
15+
get_dictionary();
16+
1417
namespace Datadog {
1518

1619
// There's currently no need to offer custom tags, so there's no interface for

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: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <string>
88
#include <string_view>
9+
#include <unordered_map>
910
#include <vector>
1011

1112
extern "C"
@@ -15,6 +16,14 @@ extern "C"
1516

1617
namespace Datadog {
1718

19+
using string_id = ddog_prof_StringId2;
20+
using function_id = ddog_prof_FunctionId2;
21+
22+
string_id
23+
intern_string(std::string_view s);
24+
function_id
25+
intern_function(string_id name, string_id filename);
26+
1827
namespace internal {
1928

2029
// StringArena holds copies of strings we need while building samples.
@@ -70,12 +79,12 @@ class Sample
7079
static inline bool timeline_enabled = false;
7180

7281
// Keeps temporary buffer of frames in the stack
73-
std::vector<ddog_prof_Location> locations;
82+
std::vector<ddog_prof_Location2> locations;
7483
size_t dropped_frames = 0;
7584
uint64_t samples = 0;
7685

7786
// Storage for labels
78-
std::vector<ddog_prof_Label> labels{};
87+
std::vector<ddog_prof_Label2> labels{};
7988

8089
// Storage for values
8190
std::vector<int64_t> values = {};
@@ -91,6 +100,7 @@ class Sample
91100
bool push_label(ExportLabelKey key, std::string_view val);
92101
bool push_label(ExportLabelKey key, int64_t val);
93102
void push_frame_impl(std::string_view name, std::string_view filename, uint64_t address, int64_t line);
103+
void push_frame_impl(function_id function_id, uint64_t address, int64_t line);
94104
void clear_buffers();
95105

96106
// Add values
@@ -131,6 +141,12 @@ class Sample
131141
int64_t line // for ddog_prof_Location
132142
);
133143

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

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,27 @@
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+
ddog_prof_ProfilesDictionaryHandle
18+
get_dictionary()
19+
{
20+
static ddog_prof_ProfilesDictionaryHandle handle = nullptr;
21+
22+
if (!handle) {
23+
auto result = ddog_prof_ProfilesDictionary_new(&handle);
24+
if (result.flags) {
25+
std::cerr << "could not initialise profiles dictionary: " << result.err << std::endl;
26+
return nullptr;
27+
}
28+
}
29+
30+
return handle;
31+
}
32+
1633
// State
1734
bool is_ddup_initialized = false; // NOLINT (cppcoreguidelines-avoid-non-const-global-variables)
1835
std::once_flag ddup_init_flag; // NOLINT (cppcoreguidelines-avoid-non-const-global-variables)
@@ -144,6 +161,8 @@ ddup_start() // cppcheck-suppress unusedFunction
144161
// Right now, only do things in the child _after_ fork
145162
pthread_atfork(ddup_prefork, ddup_postfork_parent, ddup_postfork_child);
146163

164+
get_dictionary();
165+
147166
// Set the global initialization flag
148167
is_ddup_initialized = true;
149168
return true;
@@ -286,6 +305,28 @@ ddup_push_frame(Datadog::Sample* sample, // cppcheck-suppress unusedFunction
286305
sample->push_frame(_name, _filename, address, line);
287306
}
288307

308+
void
309+
ddup_push_frame_id(Datadog::Sample* sample,
310+
function_id_t function_id,
311+
uint64_t address,
312+
int64_t line) // cppcheck-suppress unusedFunction
313+
{
314+
315+
sample->push_frame(static_cast<Datadog::function_id>(function_id), address, line);
316+
}
317+
318+
string_id_t
319+
ddup_intern_string(std::string_view s) // cppcheck-suppress unusedFunction
320+
{
321+
return Datadog::intern_string(s);
322+
}
323+
324+
function_id_t
325+
ddup_intern_function(string_id_t name, string_id_t filename) // cppcheck-suppress unusedFunction
326+
{
327+
return Datadog::intern_function(static_cast<Datadog::string_id>(name), static_cast<Datadog::string_id>(filename));
328+
}
329+
289330
void
290331
ddup_push_absolute_ns(Datadog::Sample* sample, int64_t timestamp_ns) // cppcheck-suppress unusedFunction
291332
{

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

Lines changed: 11 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

@@ -196,11 +197,19 @@ Datadog::Profile::val()
196197
}
197198

198199
bool
199-
Datadog::Profile::collect(const ddog_prof_Sample& sample, int64_t endtime_ns)
200+
Datadog::Profile::collect(const ddog_prof_Sample2& sample, int64_t endtime_ns)
200201
{
202+
auto set_dictionary_res = ddog_prof_Profile_set_profiles_dictionary(&cur_profile, get_dictionary());
203+
if (set_dictionary_res.tag != DDOG_VOID_RESULT_OK) {
204+
auto err = set_dictionary_res.err;
205+
std::cerr << "Error setting profiles dictionary: " << err_to_msg(&err, "") << std::endl;
206+
ddog_Error_drop(&err);
207+
return false;
208+
}
209+
201210
static bool already_warned = false; // cppcheck-suppress threadsafety-threadsafety
202211
const std::lock_guard<std::mutex> lock(profile_mtx);
203-
auto res = ddog_prof_Profile_add(&cur_profile, sample, endtime_ns);
212+
auto res = ddog_prof_Profile_add2(&cur_profile, sample, endtime_ns);
204213
if (!res.ok) { // NOLINT (cppcoreguidelines-pro-type-union-access)
205214
auto err = res.err; // NOLINT (cppcoreguidelines-pro-type-union-access)
206215
if (!already_warned) {

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

Lines changed: 91 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,51 @@
11
#include "sample.hpp"
22

3-
#include "code_provenance.hpp"
3+
#include "libdatadog_helpers.hpp"
44

55
#include <algorithm>
66
#include <chrono>
7+
#include <datadog/common.h>
8+
#include <datadog/profiling.h>
79
#include <string_view>
8-
#include <thread>
10+
11+
Datadog::string_id
12+
Datadog::intern_string(std::string_view s)
13+
{
14+
auto dict = get_dictionary();
15+
16+
ddog_prof_StringId2 string_id;
17+
auto insert_str_res = ddog_prof_ProfilesDictionary_insert_str(
18+
&string_id, dict, to_slice(s), ddog_prof_Utf8Option::DDOG_PROF_UTF8_OPTION_CONVERT_LOSSY);
19+
20+
if (insert_str_res.flags) {
21+
std::cerr << "Error inserting string: " << insert_str_res.err << std::endl;
22+
return nullptr;
23+
}
24+
25+
return string_id;
26+
}
27+
28+
Datadog::function_id
29+
Datadog::intern_function(string_id name, string_id filename)
30+
{
31+
static auto empty_string_id = intern_string("");
32+
33+
auto dict = get_dictionary();
34+
ddog_prof_Function2 my_function = {
35+
.name = name,
36+
.system_name = empty_string_id, // No support for system_name in Python
37+
.file_name = filename,
38+
};
39+
40+
ddog_prof_FunctionId2 function_id;
41+
auto insert_function_res = ddog_prof_ProfilesDictionary_insert_function(&function_id, dict, &my_function);
42+
if (insert_function_res.flags) {
43+
std::cerr << "Error inserting function: " << insert_function_res.err << std::endl;
44+
return nullptr;
45+
}
46+
47+
return function_id;
48+
}
949

1050
Datadog::internal::StringArena::StringArena()
1151
{
@@ -55,25 +95,27 @@ Datadog::Sample::Sample(SampleType _type_mask, unsigned int _max_nframes)
5595
void
5696
Datadog::Sample::push_frame_impl(std::string_view name, std::string_view filename, uint64_t address, int64_t line)
5797
{
58-
static const ddog_prof_Mapping null_mapping = { 0, 0, 0, to_slice(""), { 0 }, to_slice(""), { 0 } };
59-
name = string_storage.insert(name);
60-
filename = string_storage.insert(filename);
61-
62-
const ddog_prof_Location loc = {
63-
.mapping = null_mapping, // No support for mappings in Python
64-
.function = {
65-
.name = to_slice(name),
66-
.name_id = { 0 },
67-
.system_name = {}, // No support for system_name in Python
68-
.system_name_id = { 0 },
69-
.filename = to_slice(filename),
70-
.filename_id = { 0 },
71-
},
72-
.address = address,
73-
.line = line,
74-
};
98+
// static const ddog_prof_Mapping null_mapping = { 0, 0, 0, to_slice(""), { 0 }, to_slice(""), { 0 } };
99+
// name = string_storage.insert(name);
100+
// filename = string_storage.insert(filename);
75101

76-
locations.emplace_back(loc);
102+
auto name_id = intern_string(name);
103+
auto filename_id = intern_string(filename);
104+
105+
auto function_id = intern_function(name_id, filename_id);
106+
107+
push_frame_impl(function_id, address, line);
108+
}
109+
110+
void
111+
Datadog::Sample::push_frame_impl(function_id function_id, uint64_t address, int64_t line)
112+
{
113+
locations.push_back({
114+
.mapping = nullptr, // No support for mappings in Python
115+
.function = function_id,
116+
.address = address,
117+
.line = line,
118+
});
77119
}
78120

79121
void
@@ -87,6 +129,16 @@ Datadog::Sample::push_frame(std::string_view name, std::string_view filename, ui
87129
}
88130
}
89131

132+
void
133+
Datadog::Sample::push_frame(function_id function_id, uint64_t address, int64_t line)
134+
{
135+
if (locations.size() <= max_nframes) {
136+
push_frame_impl(function_id, address, line);
137+
} else {
138+
++dropped_frames;
139+
}
140+
}
141+
90142
bool
91143
Datadog::Sample::push_label(const ExportLabelKey key, std::string_view val)
92144
{
@@ -100,11 +152,18 @@ Datadog::Sample::push_label(const ExportLabelKey key, std::string_view val)
100152
return true;
101153
}
102154

155+
std::string_view val_str = string_storage.insert(val);
156+
const static std::string unit_str = "";
157+
103158
// Otherwise, persist the val string and add the label
104-
val = string_storage.insert(val);
105-
auto& label = labels.emplace_back();
106-
label.key = to_slice(key_sv);
107-
label.str = to_slice(val);
159+
labels.push_back({
160+
.key = intern_string(key_sv),
161+
// do not intern this because it could be a memory leak if values are many-valued
162+
.str = to_slice(val_str),
163+
.num = 0,
164+
// do not intern this because it could be a memory leak if values are many-valued
165+
.num_unit = to_slice(unit_str.c_str()),
166+
});
108167
return true;
109168
}
110169

@@ -119,11 +178,13 @@ Datadog::Sample::push_label(const ExportLabelKey key, int64_t val)
119178
return true;
120179
}
121180

122-
auto& label = labels.emplace_back();
123-
label.key = to_slice(key_sv);
124-
label.str = to_slice("");
125-
label.num = val;
126-
label.num_unit = to_slice("");
181+
auto key_id = intern_string(key_sv);
182+
labels.push_back({
183+
.key = key_id,
184+
.str = to_slice(""),
185+
.num = val,
186+
.num_unit = to_slice(""),
187+
});
127188
return true;
128189
}
129190

@@ -150,7 +211,7 @@ Datadog::Sample::flush_sample(bool reverse_locations)
150211
std::reverse(locations.begin(), locations.end());
151212
}
152213

153-
const ddog_prof_Sample sample = {
214+
const ddog_prof_Sample2 sample = {
154215
.locations = { locations.data(), locations.size() },
155216
.values = { values.data(), values.size() },
156217
.labels = { labels.data(), labels.size() },

0 commit comments

Comments
 (0)