Skip to content

Commit 51d4c2b

Browse files
authored
[profiling] Reduce copying and allocation in exporter (#926)
1 parent 9f66ffa commit 51d4c2b

File tree

15 files changed

+426
-585
lines changed

15 files changed

+426
-585
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ddcommon-ffi/src/handle.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright 2024-Present Datadog, Inc. https://www.datadoghq.com/
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use std::ptr::null_mut;
5+
46
use anyhow::Context;
57

68
/// Represents an object that should only be referred to by its handle.
@@ -11,6 +13,12 @@ pub struct Handle<T> {
1113
inner: *mut T,
1214
}
1315

16+
impl<T> Handle<T> {
17+
pub fn empty() -> Self {
18+
Self { inner: null_mut() }
19+
}
20+
}
21+
1422
pub trait ToInner<T> {
1523
/// # Safety
1624
/// The Handle must hold a valid `inner` which has been allocated and not freed.

ddcommon-ffi/src/result.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ pub enum VoidResult {
1515
Err(Error),
1616
}
1717

18+
impl VoidResult {
19+
pub fn unwrap(self) {
20+
assert!(matches!(self, Self::Ok(_)));
21+
}
22+
23+
pub fn unwrap_err(self) -> Error {
24+
match self {
25+
#[allow(clippy::panic)]
26+
Self::Ok(_) => panic!("Expected error, got value"),
27+
Self::Err(err) => err,
28+
}
29+
}
30+
}
31+
1832
impl From<anyhow::Result<()>> for VoidResult {
1933
fn from(value: anyhow::Result<()>) -> Self {
2034
match value {
@@ -40,6 +54,14 @@ impl<T> Result<T> {
4054
Self::Err(err) => panic!("{err}"),
4155
}
4256
}
57+
58+
pub fn unwrap_err(self) -> Error {
59+
match self {
60+
#[allow(clippy::panic)]
61+
Self::Ok(_) => panic!("Expected error, got value"),
62+
Self::Err(err) => err,
63+
}
64+
}
4365
}
4466

4567
impl<T> From<anyhow::Result<T>> for Result<T> {

examples/ffi/exporter.cpp

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ int main(int argc, char *argv[]) {
3838

3939
const ddog_prof_Slice_ValueType sample_types = {&wall_time, 1};
4040
const ddog_prof_Period period = {wall_time, 60};
41-
ddog_prof_Profile_NewResult profile_new_result =
42-
ddog_prof_Profile_new(sample_types, &period, nullptr);
41+
ddog_prof_Profile_NewResult profile_new_result = ddog_prof_Profile_new(sample_types, &period);
4342
if (profile_new_result.tag != DDOG_PROF_PROFILE_NEW_RESULT_OK) {
4443
print_error("Failed to make new profile: ", profile_new_result.err);
4544
ddog_Error_drop(&profile_new_result.err);
@@ -96,9 +95,9 @@ int main(int argc, char *argv[]) {
9695
return 1;
9796
}
9897

99-
ddog_prof_EncodedProfile *encoded_profile = &serialize_result.ok;
98+
auto *encoded_profile = &serialize_result.ok;
10099

101-
ddog_prof_Endpoint endpoint =
100+
auto endpoint =
102101
ddog_prof_Endpoint_agentless(DDOG_CHARSLICE_C_BARE("datad0g.com"), to_slice_c_char(api_key));
103102

104103
ddog_Vec_Tag tags = ddog_Vec_Tag_new();
@@ -110,90 +109,82 @@ int main(int argc, char *argv[]) {
110109
return 1;
111110
}
112111

113-
ddog_prof_Exporter_NewResult exporter_new_result =
114-
ddog_prof_Exporter_new(DDOG_CHARSLICE_C_BARE("exporter-example"), DDOG_CHARSLICE_C_BARE("1.2.3"),
115-
DDOG_CHARSLICE_C_BARE("native"), &tags, endpoint);
112+
auto exporter_new_result = ddog_prof_Exporter_new(
113+
DDOG_CHARSLICE_C_BARE("exporter-example"), DDOG_CHARSLICE_C_BARE("1.2.3"),
114+
DDOG_CHARSLICE_C_BARE("native"), &tags, endpoint);
116115
ddog_Vec_Tag_drop(tags);
117116

118-
if (exporter_new_result.tag == DDOG_PROF_EXPORTER_NEW_RESULT_ERR) {
117+
if (exporter_new_result.tag == DDOG_PROF_PROFILE_EXPORTER_RESULT_ERR_HANDLE_PROFILE_EXPORTER) {
119118
print_error("Failed to create exporter: ", exporter_new_result.err);
120119
ddog_Error_drop(&exporter_new_result.err);
121120
return 1;
122121
}
123122

124-
auto exporter = exporter_new_result.ok;
123+
auto exporter = &exporter_new_result.ok;
125124

126-
ddog_prof_Exporter_File files_to_compress_and_export_[] = {{
127-
.name = DDOG_CHARSLICE_C_BARE("auto.pprof"),
128-
.file = ddog_Vec_U8_as_slice(&encoded_profile->buffer),
129-
}};
130-
ddog_prof_Exporter_Slice_File files_to_compress_and_export = {
131-
.ptr = files_to_compress_and_export_,
132-
.len = sizeof files_to_compress_and_export_ / sizeof *files_to_compress_and_export_,
133-
};
134-
135-
ddog_prof_Exporter_Slice_File files_to_export_unmodified = ddog_prof_Exporter_Slice_File_empty();
125+
auto files_to_compress_and_export = ddog_prof_Exporter_Slice_File_empty();
126+
auto files_to_export_unmodified = ddog_prof_Exporter_Slice_File_empty();
136127

137128
ddog_CharSlice internal_metadata_example = DDOG_CHARSLICE_C_BARE(
138129
"{\"no_signals_workaround_enabled\": \"true\", \"execution_trace_enabled\": \"false\"}");
139130

140-
ddog_CharSlice info_example = DDOG_CHARSLICE_C_BARE(
141-
"{\"application\": {\"start_time\": \"2024-01-24T11:17:22+0000\"}, \"platform\": {\"kernel\": \"Darwin Kernel 22.5.0\"}}");
131+
ddog_CharSlice info_example =
132+
DDOG_CHARSLICE_C_BARE("{\"application\": {\"start_time\": \"2024-01-24T11:17:22+0000\"}, "
133+
"\"platform\": {\"kernel\": \"Darwin Kernel 22.5.0\"}}");
142134

143135
auto res = ddog_prof_Exporter_set_timeout(exporter, 30000);
144-
if (res.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
145-
print_error("Failed to set the timeout", res.some);
146-
ddog_Error_drop(&res.some);
147-
return 1;
136+
if (res.tag == DDOG_PROF_VOID_RESULT_ERR) {
137+
print_error("Failed to set the timeout", res.err);
138+
ddog_Error_drop(&res.err);
139+
return 1;
148140
}
149141

150-
ddog_prof_Exporter_Request_BuildResult build_result = ddog_prof_Exporter_Request_build(
151-
exporter, encoded_profile->start, encoded_profile->end, files_to_compress_and_export,
152-
files_to_export_unmodified, nullptr, nullptr, &internal_metadata_example, &info_example);
142+
auto build_result = ddog_prof_Exporter_Request_build(
143+
exporter, encoded_profile, files_to_compress_and_export, files_to_export_unmodified, nullptr,
144+
&internal_metadata_example, &info_example);
153145
ddog_prof_EncodedProfile_drop(encoded_profile);
154146

155-
if (build_result.tag == DDOG_PROF_EXPORTER_REQUEST_BUILD_RESULT_ERR) {
147+
if (build_result.tag == DDOG_PROF_REQUEST_RESULT_ERR_HANDLE_REQUEST) {
156148
print_error("Failed to build request: ", build_result.err);
157149
ddog_Error_drop(&build_result.err);
158150
return 1;
159151
}
160152

161-
auto &request = build_result.ok;
153+
auto request = &build_result.ok;
162154

163-
ddog_CancellationToken *cancel = ddog_CancellationToken_new();
164-
ddog_CancellationToken *cancel_for_background_thread = ddog_CancellationToken_clone(cancel);
155+
auto cancel = ddog_CancellationToken_new();
156+
auto cancel_for_background_thread = ddog_CancellationToken_clone(&cancel);
165157

166158
// As an example of CancellationToken usage, here we create a background
167159
// thread that sleeps for some time and then cancels a request early (e.g.
168160
// before the timeout in ddog_ProfileExporter_send is hit).
169161
//
170162
// If the request is faster than the sleep time, no cancellation takes place.
171163
std::thread trigger_cancel_if_request_takes_too_long_thread(
172-
[](ddog_CancellationToken *cancel_for_background_thread) {
164+
[](ddog_prof_CancellationToken cancel_for_background_thread) {
173165
int timeout_ms = 5000;
174166
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms));
175167
printf("Request took longer than %d ms, triggering asynchronous "
176168
"cancellation\n",
177169
timeout_ms);
178-
ddog_CancellationToken_cancel(cancel_for_background_thread);
179-
ddog_CancellationToken_drop(cancel_for_background_thread);
170+
ddog_CancellationToken_cancel(&cancel_for_background_thread);
171+
ddog_CancellationToken_drop(&cancel_for_background_thread);
180172
},
181173
cancel_for_background_thread);
182174
trigger_cancel_if_request_takes_too_long_thread.detach();
183175

184176
int exit_code = 0;
185-
ddog_prof_Exporter_SendResult send_result = ddog_prof_Exporter_send(exporter, &request, cancel);
186-
if (send_result.tag == DDOG_PROF_EXPORTER_SEND_RESULT_ERR) {
177+
auto send_result = ddog_prof_Exporter_send(exporter, request, &cancel);
178+
if (send_result.tag == DDOG_PROF_RESULT_HTTP_STATUS_ERR_HTTP_STATUS) {
187179
print_error("Failed to send profile: ", send_result.err);
188180
exit_code = 1;
189181
ddog_Error_drop(&send_result.err);
190182
} else {
191-
printf("Response code: %d\n", send_result.http_response.code);
183+
printf("Response code: %d\n", send_result.ok.code);
192184
}
193185

194-
ddog_prof_Exporter_Request_drop(&request);
195-
186+
ddog_prof_Exporter_Request_drop(request);
196187
ddog_prof_Exporter_drop(exporter);
197-
ddog_CancellationToken_drop(cancel);
188+
ddog_CancellationToken_drop(&cancel);
198189
return exit_code;
199190
}

examples/ffi/profiles.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ int main(void) {
1414
const ddog_prof_Slice_ValueType sample_types = {&wall_time, 1};
1515
const ddog_prof_Period period = {wall_time, 60};
1616

17-
ddog_prof_Profile_NewResult new_result = ddog_prof_Profile_new(sample_types, &period, NULL);
17+
ddog_prof_Profile_NewResult new_result = ddog_prof_Profile_new(sample_types, &period);
1818
if (new_result.tag != DDOG_PROF_PROFILE_NEW_RESULT_OK) {
1919
ddog_CharSlice message = ddog_Error_message(&new_result.err);
2020
fprintf(stderr, "%.*s", (int)message.len, message.ptr);
@@ -58,7 +58,7 @@ int main(void) {
5858
// printf("Press any key to reset and drop...");
5959
// getchar();
6060

61-
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(profile, NULL);
61+
ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(profile);
6262
if (reset_result.tag != DDOG_PROF_PROFILE_RESULT_OK) {
6363
ddog_CharSlice message = ddog_Error_message(&reset_result.err);
6464
fprintf(stderr, "%.*s", (int)message.len, message.ptr);

profiling-ffi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ symbolic-demangle = { version = "12.8.0", default-features = false, features = [
4848
symbolic-common = "12.8.0"
4949
data-pipeline-ffi = { path = "../data-pipeline-ffi", default-features = false, optional = true }
5050
datadog-library-config-ffi = { path = "../library-config-ffi", default-features = false, optional = true }
51+
function_name = "0.3.0"

profiling-ffi/cbindgen.toml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ no_includes = true
1515
sys_includes = ["stdbool.h", "stddef.h", "stdint.h"]
1616
includes = ["common.h"]
1717

18+
after_includes = """
19+
struct TokioCancellationToken;
20+
"""
21+
1822
[export]
1923
prefix = "ddog_prof_"
2024
renaming_overrides_prefixing = true
2125

2226
[export.rename]
2327
"ByteSlice" = "ddog_ByteSlice"
24-
"CancellationToken" = "ddog_CancellationToken"
2528
"CharSlice" = "ddog_CharSlice"
2629
"Endpoint" = "ddog_Endpoint"
2730
"Error" = "ddog_Error"
@@ -50,6 +53,21 @@ renaming_overrides_prefixing = true
5053
"StringWrapper" = "ddog_StringWrapper"
5154
"StringWrapperResult" = "ddog_StringWrapperResult"
5255

56+
"HandleProfileExporter" = "ddog_prof_ProfileExporter"
57+
"Handle_ProfileExporter" = "ddog_prof_ProfileExporter"
58+
"Result_HandleProfileExporter" = "ddog_prof_ProfileExporter_Result"
59+
60+
"HandleRequest" = "ddog_prof_Request"
61+
"Handle_Request" = "ddog_prof_Request"
62+
"Result_HandleRequest" = "ddog_prof_Request_Result"
63+
64+
"HandleEncodedProfile" = "ddog_prof_EncodedProfile"
65+
"Handle_EncodedProfile" = "ddog_prof_EncodedProfile"
66+
"Result_HandleEncodedProfile" = "ddog_prof_EncodedProfile_Result"
67+
68+
"CancellationToken" = "struct ddog_prof_OpaqueCancellationToken"
69+
"Handle_TokioCancellationToken" = "ddog_prof_CancellationToken"
70+
5371
[export.mangle]
5472
rename_types = "PascalCase"
5573

0 commit comments

Comments
 (0)