Skip to content

Commit 606d179

Browse files
committed
[profiling] Reduce copying and allocation in exporter
1 parent fc9530e commit 606d179

File tree

6 files changed

+114
-207
lines changed

6 files changed

+114
-207
lines changed

examples/ffi/exporter.cpp

+15-22
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ int main(int argc, char *argv[]) {
9696
return 1;
9797
}
9898

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

101-
ddog_prof_Endpoint endpoint =
101+
auto endpoint =
102102
ddog_prof_Endpoint_agentless(DDOG_CHARSLICE_C_BARE("datad0g.com"), to_slice_c_char(api_key));
103103

104104
ddog_Vec_Tag tags = ddog_Vec_Tag_new();
@@ -110,9 +110,9 @@ int main(int argc, char *argv[]) {
110110
return 1;
111111
}
112112

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);
113+
ddog_prof_Exporter_NewResult exporter_new_result = ddog_prof_Exporter_new(
114+
DDOG_CHARSLICE_C_BARE("exporter-example"), DDOG_CHARSLICE_C_BARE("1.2.3"),
115+
DDOG_CHARSLICE_C_BARE("native"), &tags, endpoint);
116116
ddog_Vec_Tag_drop(tags);
117117

118118
if (exporter_new_result.tag == DDOG_PROF_EXPORTER_NEW_RESULT_ERR) {
@@ -123,33 +123,26 @@ int main(int argc, char *argv[]) {
123123

124124
auto exporter = exporter_new_result.ok;
125125

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();
126+
auto files_to_compress_and_export = ddog_prof_Exporter_Slice_File_empty();
127+
auto files_to_export_unmodified = ddog_prof_Exporter_Slice_File_empty();
136128

137129
ddog_CharSlice internal_metadata_example = DDOG_CHARSLICE_C_BARE(
138130
"{\"no_signals_workaround_enabled\": \"true\", \"execution_trace_enabled\": \"false\"}");
139131

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\"}}");
132+
ddog_CharSlice info_example =
133+
DDOG_CHARSLICE_C_BARE("{\"application\": {\"start_time\": \"2024-01-24T11:17:22+0000\"}, "
134+
"\"platform\": {\"kernel\": \"Darwin Kernel 22.5.0\"}}");
142135

143136
auto res = ddog_prof_Exporter_set_timeout(exporter, 30000);
144137
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;
138+
print_error("Failed to set the timeout", res.some);
139+
ddog_Error_drop(&res.some);
140+
return 1;
148141
}
149142

150143
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);
144+
exporter, encoded_profile, files_to_compress_and_export, files_to_export_unmodified, nullptr,
145+
&internal_metadata_example, &info_example);
153146
ddog_prof_EncodedProfile_drop(encoded_profile);
154147

155148
if (build_result.tag == DDOG_PROF_EXPORTER_REQUEST_BUILD_RESULT_ERR) {

profiling-ffi/src/exporter.rs

+32-104
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
use datadog_profiling::exporter;
88
use datadog_profiling::exporter::{ProfileExporter, Request};
9-
use datadog_profiling::internal::ProfiledEndpointsStats;
9+
use datadog_profiling::internal::EncodedProfile;
1010
use ddcommon::tag::Tag;
1111
use ddcommon_ffi::slice::{AsBytes, ByteSlice, CharSlice, Slice};
12-
use ddcommon_ffi::{Error, MaybeError, Timespec};
12+
use ddcommon_ffi::{Error, Handle, MaybeError, ToInner};
1313
use std::borrow::Cow;
1414
use std::ptr::NonNull;
1515
use std::str::FromStr;
@@ -259,16 +259,15 @@ impl From<RequestBuildResult> for Result<Box<Request>, String> {
259259
/// valid objects created by this module.
260260
/// NULL is allowed for `optional_additional_tags`, `optional_endpoints_stats`,
261261
/// `optional_internal_metadata_json` and `optional_info_json`.
262+
/// Consumes the `SerializedProfile`
262263
#[no_mangle]
263264
#[must_use]
264265
pub unsafe extern "C" fn ddog_prof_Exporter_Request_build(
265266
exporter: Option<&mut ProfileExporter>,
266-
start: Timespec,
267-
end: Timespec,
267+
profile: *mut Handle<EncodedProfile>,
268268
files_to_compress_and_export: Slice<File>,
269269
files_to_export_unmodified: Slice<File>,
270270
optional_additional_tags: Option<&ddcommon_ffi::Vec<Tag>>,
271-
optional_endpoints_stats: Option<&ProfiledEndpointsStats>,
272271
optional_internal_metadata_json: Option<&CharSlice>,
273272
optional_info_json: Option<&CharSlice>,
274273
) -> RequestBuildResult {
@@ -290,13 +289,20 @@ pub unsafe extern "C" fn ddog_prof_Exporter_Request_build(
290289
Err(err) => return RequestBuildResult::Err(err.into()),
291290
};
292291

292+
if profile.is_null() {
293+
return RequestBuildResult::Err(anyhow::anyhow!("profile pointer was null").into());
294+
}
295+
296+
let profile = match (*profile).take() {
297+
Ok(p) => *p,
298+
Err(e) => return RequestBuildResult::Err(e.into()),
299+
};
300+
293301
match exporter.build(
294-
start.into(),
295-
end.into(),
302+
profile,
296303
files_to_compress_and_export.as_slice(),
297304
files_to_export_unmodified.as_slice(),
298305
tags.as_ref(),
299-
optional_endpoints_stats,
300306
internal_metadata,
301307
info,
302308
) {
@@ -575,19 +581,7 @@ mod tests {
575581
ExporterNewResult::Err(_) => panic!("Should not occur!"),
576582
};
577583

578-
let files_to_compress_and_export: &[File] = &[File {
579-
name: CharSlice::from("foo.pprof"),
580-
file: ByteSlice::from(b"dummy contents" as &[u8]),
581-
}];
582-
583-
let start = Timespec {
584-
seconds: 12,
585-
nanoseconds: 34,
586-
};
587-
let finish = Timespec {
588-
seconds: 56,
589-
nanoseconds: 78,
590-
};
584+
let profile = &mut EncodedProfile::test_instance().unwrap().into();
591585
let timeout_milliseconds = 90;
592586
unsafe {
593587
ddog_prof_Exporter_set_timeout(Some(exporter.as_mut()), timeout_milliseconds)
@@ -597,11 +591,9 @@ mod tests {
597591
let build_result = unsafe {
598592
ddog_prof_Exporter_Request_build(
599593
Some(exporter.as_mut()),
600-
start,
601-
finish,
602-
Slice::from(files_to_compress_and_export),
594+
profile,
595+
Slice::empty(),
603596
Slice::empty(),
604-
None,
605597
None,
606598
None,
607599
None,
@@ -610,7 +602,7 @@ mod tests {
610602

611603
let parsed_event_json = parsed_event_json(build_result);
612604

613-
assert_eq!(parsed_event_json["attachments"], json!(["foo.pprof"]));
605+
assert_eq!(parsed_event_json["attachments"], json!(["profile.pprof"]));
614606
assert_eq!(parsed_event_json["endpoint_counts"], json!(null));
615607
assert_eq!(
616608
parsed_event_json["start"],
@@ -649,19 +641,7 @@ mod tests {
649641
ExporterNewResult::Err(_) => panic!("Should not occur!"),
650642
};
651643

652-
let files: &[File] = &[File {
653-
name: CharSlice::from("foo.pprof"),
654-
file: ByteSlice::from(b"dummy contents" as &[u8]),
655-
}];
656-
657-
let start = Timespec {
658-
seconds: 12,
659-
nanoseconds: 34,
660-
};
661-
let finish = Timespec {
662-
seconds: 56,
663-
nanoseconds: 78,
664-
};
644+
let profile = &mut EncodedProfile::test_instance().unwrap().into();
665645
let timeout_milliseconds = 90;
666646
unsafe {
667647
ddog_prof_Exporter_set_timeout(Some(exporter.as_mut()), timeout_milliseconds)
@@ -681,11 +661,9 @@ mod tests {
681661
let build_result = unsafe {
682662
ddog_prof_Exporter_Request_build(
683663
Some(exporter.as_mut()),
684-
start,
685-
finish,
686-
Slice::from(files),
664+
profile,
665+
Slice::empty(),
687666
Slice::empty(),
688-
None,
689667
None,
690668
Some(&raw_internal_metadata),
691669
None,
@@ -724,19 +702,8 @@ mod tests {
724702
ExporterNewResult::Err(_) => panic!("Should not occur!"),
725703
};
726704

727-
let files: &[File] = &[File {
728-
name: CharSlice::from("foo.pprof"),
729-
file: ByteSlice::from(b"dummy contents" as &[u8]),
730-
}];
705+
let profile = &mut EncodedProfile::test_instance().unwrap().into();
731706

732-
let start = Timespec {
733-
seconds: 12,
734-
nanoseconds: 34,
735-
};
736-
let finish = Timespec {
737-
seconds: 56,
738-
nanoseconds: 78,
739-
};
740707
let timeout_milliseconds = 90;
741708
unsafe {
742709
ddog_prof_Exporter_set_timeout(Some(exporter.as_mut()), timeout_milliseconds)
@@ -748,11 +715,9 @@ mod tests {
748715
let build_result = unsafe {
749716
ddog_prof_Exporter_Request_build(
750717
Some(exporter.as_mut()),
751-
start,
752-
finish,
753-
Slice::from(files),
718+
profile,
719+
Slice::empty(),
754720
Slice::empty(),
755-
None,
756721
None,
757722
Some(&raw_internal_metadata),
758723
None,
@@ -787,19 +752,7 @@ mod tests {
787752
ExporterNewResult::Err(_) => panic!("Should not occur!"),
788753
};
789754

790-
let files: &[File] = &[File {
791-
name: CharSlice::from("foo.pprof"),
792-
file: ByteSlice::from(b"dummy contents" as &[u8]),
793-
}];
794-
795-
let start = Timespec {
796-
seconds: 12,
797-
nanoseconds: 34,
798-
};
799-
let finish = Timespec {
800-
seconds: 56,
801-
nanoseconds: 78,
802-
};
755+
let profile = &mut EncodedProfile::test_instance().unwrap().into();
803756
let timeout_milliseconds = 90;
804757
unsafe {
805758
ddog_prof_Exporter_set_timeout(Some(exporter.as_mut()), timeout_milliseconds)
@@ -840,11 +793,9 @@ mod tests {
840793
let build_result = unsafe {
841794
ddog_prof_Exporter_Request_build(
842795
Some(exporter.as_mut()),
843-
start,
844-
finish,
845-
Slice::from(files),
796+
profile,
797+
Slice::empty(),
846798
Slice::empty(),
847-
None,
848799
None,
849800
None,
850801
Some(&raw_info),
@@ -904,19 +855,7 @@ mod tests {
904855
ExporterNewResult::Err(_) => panic!("Should not occur!"),
905856
};
906857

907-
let files: &[File] = &[File {
908-
name: CharSlice::from("foo.pprof"),
909-
file: ByteSlice::from(b"dummy contents" as &[u8]),
910-
}];
911-
912-
let start = Timespec {
913-
seconds: 12,
914-
nanoseconds: 34,
915-
};
916-
let finish = Timespec {
917-
seconds: 56,
918-
nanoseconds: 78,
919-
};
858+
let profile = &mut EncodedProfile::test_instance().unwrap().into();
920859
let timeout_milliseconds = 90;
921860
unsafe {
922861
ddog_prof_Exporter_set_timeout(Some(exporter.as_mut()), timeout_milliseconds)
@@ -928,11 +867,9 @@ mod tests {
928867
let build_result = unsafe {
929868
ddog_prof_Exporter_Request_build(
930869
Some(exporter.as_mut()),
931-
start,
932-
finish,
933-
Slice::from(files),
870+
profile,
871+
Slice::empty(),
934872
Slice::empty(),
935-
None,
936873
None,
937874
None,
938875
Some(&raw_info),
@@ -949,26 +886,17 @@ mod tests {
949886

950887
#[test]
951888
fn test_build_failure() {
952-
let start = Timespec {
953-
seconds: 12,
954-
nanoseconds: 34,
955-
};
956-
let finish = Timespec {
957-
seconds: 56,
958-
nanoseconds: 78,
959-
};
889+
let profile = &mut EncodedProfile::test_instance().unwrap().into();
960890

961891
let build_result = unsafe {
962892
ddog_prof_Exporter_Request_build(
963893
None, // No exporter, will fail
964-
start,
965-
finish,
894+
profile,
966895
Slice::empty(),
967896
Slice::empty(),
968897
None,
969898
None,
970899
None,
971-
None,
972900
)
973901
};
974902

0 commit comments

Comments
 (0)