Skip to content

Commit

Permalink
[profiling] Refactor: use the new FFI macros and types
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsn committed Dec 10, 2024
1 parent d111f32 commit 1374f98
Show file tree
Hide file tree
Showing 10 changed files with 459 additions and 559 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions ddcommon-ffi/src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub struct Handle<T> {
}

pub trait ToInner<T> {
/// # Safety
/// The Handle must hold a valid `inner` which has been allocated and not freed.
unsafe fn to_inner(&self) -> anyhow::Result<&T>;
/// # Safety
/// The Handle must hold a valid `inner` which has been allocated and not freed.
unsafe fn to_inner_mut(&mut self) -> anyhow::Result<&mut T>;
Expand All @@ -21,6 +24,10 @@ pub trait ToInner<T> {
}

impl<T> ToInner<T> for *mut Handle<T> {
unsafe fn to_inner(&self) -> anyhow::Result<&T> {
self.as_ref().context("Null pointer")?.to_inner()
}

unsafe fn to_inner_mut(&mut self) -> anyhow::Result<&mut T> {
self.as_mut().context("Null pointer")?.to_inner_mut()
}
Expand All @@ -31,6 +38,12 @@ impl<T> ToInner<T> for *mut Handle<T> {
}

impl<T> ToInner<T> for Handle<T> {
unsafe fn to_inner(&self) -> anyhow::Result<&T> {
self.inner
.as_ref()
.context("inner pointer was null, indicates use after free")
}

unsafe fn to_inner_mut(&mut self) -> anyhow::Result<&mut T> {
self.inner
.as_mut()
Expand Down
18 changes: 18 additions & 0 deletions ddcommon-ffi/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ impl From<anyhow::Result<()>> for VoidResult {
}
}

impl From<VoidResult> for anyhow::Result<()> {
fn from(value: VoidResult) -> Self {
match value {
VoidResult::Ok(_) => Self::Ok(()),
VoidResult::Err(err) => Self::Err(err.into()),
}
}
}

/// A generic result type for when an operation may fail,
/// or may return <T> in case of success.
#[repr(C)]
Expand All @@ -49,3 +58,12 @@ impl<T> From<anyhow::Result<T>> for Result<T> {
}
}
}

impl<T> From<Result<T>> for anyhow::Result<T> {
fn from(value: Result<T>) -> Self {
match value {
Result::Ok(v) => Self::Ok(v),
Result::Err(err) => Self::Err(err.into()),
}
}
}
93 changes: 55 additions & 38 deletions examples/ffi/exporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,50 @@
#include <thread>

static ddog_CharSlice to_slice_c_char(const char *s) { return {.ptr = s, .len = strlen(s)}; }

struct Deleter {
void operator()(ddog_prof_Profile *object) { ddog_prof_Profile_drop(object); }
};
static ddog_CharSlice to_slice_c_char(const char *s, std::size_t size) {
return {.ptr = s, .len = size};
}
static ddog_CharSlice to_slice_string(std::string const &s) {
return {.ptr = s.data(), .len = s.length()};
}

void print_error(const char *s, const ddog_Error &err) {
auto charslice = ddog_Error_message(&err);
printf("%s (%.*s)\n", s, static_cast<int>(charslice.len), charslice.ptr);
}

#define CHECK_RESULT(typ, ok_tag) \
void check_result(typ result, const char *msg) { \
if (result.tag != ok_tag) { \
print_error(msg, result.err); \
ddog_Error_drop(&result.err); \
exit(EXIT_FAILURE); \
} \
}

CHECK_RESULT(ddog_VoidResult, DDOG_VOID_RESULT_OK)

#define EXTRACT_RESULT(typ, ok_tag) \
struct typ##Deleter { \
void operator()(ddog_prof_Handle_##typ *object) { \
ddog_prof_##typ##_drop(object); \
delete object; \
} \
}; \
std::unique_ptr<ddog_prof_Handle_##typ, typ##Deleter> extract_result( \
ddog_prof_Result_Handle##typ result, const char *msg) { \
if (result.tag != ok_tag) { \
print_error(msg, result.err); \
ddog_Error_drop(&result.err); \
exit(EXIT_FAILURE); \
} \
std::unique_ptr<ddog_prof_Handle_##typ, typ##Deleter> rval{ \
new ddog_prof_Handle_##typ{result.ok}}; \
return rval; \
}

EXTRACT_RESULT(Profile, DDOG_PROF_RESULT_HANDLE_PROFILE_OK_HANDLE_PROFILE)

int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: exporter SERVICE_NAME\n");
Expand All @@ -38,14 +72,8 @@ int main(int argc, char *argv[]) {

const ddog_prof_Slice_ValueType sample_types = {&wall_time, 1};
const ddog_prof_Period period = {wall_time, 60};
ddog_prof_Profile_NewResult profile_new_result =
ddog_prof_Profile_new(sample_types, &period, nullptr);
if (profile_new_result.tag != DDOG_PROF_PROFILE_NEW_RESULT_OK) {
print_error("Failed to make new profile: ", profile_new_result.err);
ddog_Error_drop(&profile_new_result.err);
exit(EXIT_FAILURE);
}
std::unique_ptr<ddog_prof_Profile, Deleter> profile{&profile_new_result.ok};
auto profile =
extract_result(ddog_prof_Profile_new(sample_types, &period, nullptr), "Can't get profile");

ddog_prof_Location root_location = {
// yes, a zero-initialized mapping is valid
Expand All @@ -67,30 +95,18 @@ int main(int argc, char *argv[]) {
.values = {&value, 1},
.labels = {&label, 1},
};
auto add_result = ddog_prof_Profile_add(profile.get(), sample, 0);
if (add_result.tag != DDOG_PROF_PROFILE_RESULT_OK) {
print_error("Failed to add sample to profile: ", add_result.err);
ddog_Error_drop(&add_result.err);
return 1;
}
check_result(ddog_prof_Profile_add(profile.get(), sample, 0), "failed to add");

uintptr_t offset[1] = {0};
ddog_prof_Slice_Usize offsets_slice = {.ptr = offset, .len = 1};
ddog_CharSlice empty_charslice = DDOG_CHARSLICE_C_BARE("");

auto upscaling_addresult = ddog_prof_Profile_add_upscaling_rule_proportional(
profile.get(), offsets_slice, empty_charslice, empty_charslice, 1, 1);
check_result(ddog_prof_Profile_add_upscaling_rule_proportional(
profile.get(), offsets_slice, empty_charslice, empty_charslice, 1, 1),
"failed to add upscaling rule");

if (upscaling_addresult.tag == DDOG_PROF_PROFILE_RESULT_ERR) {
print_error("Failed to add an upscaling rule: ", upscaling_addresult.err);
ddog_Error_drop(&upscaling_addresult.err);
// in this specific case, we want to fail the execution. But in general, we should not
return 1;
}

ddog_prof_Profile_SerializeResult serialize_result =
ddog_prof_Profile_serialize(profile.get(), nullptr, nullptr, nullptr);
if (serialize_result.tag == DDOG_PROF_PROFILE_SERIALIZE_RESULT_ERR) {
auto serialize_result = ddog_prof_Profile_serialize(profile.get(), nullptr, nullptr, nullptr);
if (serialize_result.tag != DDOG_PROF_RESULT_ENCODED_PROFILE_OK_ENCODED_PROFILE) {
print_error("Failed to serialize profile: ", serialize_result.err);
ddog_Error_drop(&serialize_result.err);
return 1;
Expand All @@ -110,9 +126,9 @@ int main(int argc, char *argv[]) {
return 1;
}

ddog_prof_Exporter_NewResult exporter_new_result =
ddog_prof_Exporter_new(DDOG_CHARSLICE_C_BARE("exporter-example"), DDOG_CHARSLICE_C_BARE("1.2.3"),
DDOG_CHARSLICE_C_BARE("native"), &tags, endpoint);
ddog_prof_Exporter_NewResult exporter_new_result = ddog_prof_Exporter_new(
DDOG_CHARSLICE_C_BARE("exporter-example"), DDOG_CHARSLICE_C_BARE("1.2.3"),
DDOG_CHARSLICE_C_BARE("native"), &tags, endpoint);
ddog_Vec_Tag_drop(tags);

if (exporter_new_result.tag == DDOG_PROF_EXPORTER_NEW_RESULT_ERR) {
Expand All @@ -137,14 +153,15 @@ int main(int argc, char *argv[]) {
ddog_CharSlice internal_metadata_example = DDOG_CHARSLICE_C_BARE(
"{\"no_signals_workaround_enabled\": \"true\", \"execution_trace_enabled\": \"false\"}");

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

auto res = ddog_prof_Exporter_set_timeout(exporter, 30000);
if (res.tag == DDOG_PROF_OPTION_ERROR_SOME_ERROR) {
print_error("Failed to set the timeout", res.some);
ddog_Error_drop(&res.some);
return 1;
print_error("Failed to set the timeout", res.some);
ddog_Error_drop(&res.some);
return 1;
}

ddog_prof_Exporter_Request_BuildResult build_result = ddog_prof_Exporter_Request_build(
Expand Down
12 changes: 6 additions & 6 deletions examples/ffi/profiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ int main(void) {
const ddog_prof_Slice_ValueType sample_types = {&wall_time, 1};
const ddog_prof_Period period = {wall_time, 60};

ddog_prof_Profile_NewResult new_result = ddog_prof_Profile_new(sample_types, &period, NULL);
if (new_result.tag != DDOG_PROF_PROFILE_NEW_RESULT_OK) {
ddog_prof_Result_HandleProfile new_result = ddog_prof_Profile_new(sample_types, &period, NULL);
if (new_result.tag != DDOG_PROF_RESULT_HANDLE_PROFILE_OK_HANDLE_PROFILE) {
ddog_CharSlice message = ddog_Error_message(&new_result.err);
fprintf(stderr, "%.*s", (int)message.len, message.ptr);
ddog_Error_drop(&new_result.err);
Expand Down Expand Up @@ -47,8 +47,8 @@ int main(void) {
for (int i = 0; i < 10000000; i++) {
label.num = i;

ddog_prof_Profile_Result add_result = ddog_prof_Profile_add(profile, sample, 0);
if (add_result.tag != DDOG_PROF_PROFILE_RESULT_OK) {
ddog_VoidResult add_result = ddog_prof_Profile_add(profile, sample, 0);
if (add_result.tag == DDOG_VOID_RESULT_ERR) {
ddog_CharSlice message = ddog_Error_message(&add_result.err);
fprintf(stderr, "%.*s", (int)message.len, message.ptr);
ddog_Error_drop(&add_result.err);
Expand All @@ -58,8 +58,8 @@ int main(void) {
// printf("Press any key to reset and drop...");
// getchar();

ddog_prof_Profile_Result reset_result = ddog_prof_Profile_reset(profile, NULL);
if (reset_result.tag != DDOG_PROF_PROFILE_RESULT_OK) {
ddog_VoidResult reset_result = ddog_prof_Profile_reset(profile, NULL);
if (reset_result.tag == DDOG_VOID_RESULT_ERR) {
ddog_CharSlice message = ddog_Error_message(&reset_result.err);
fprintf(stderr, "%.*s", (int)message.len, message.ptr);
ddog_Error_drop(&reset_result.err);
Expand Down
1 change: 1 addition & 0 deletions profiling-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ symbolizer-ffi = { path = "../symbolizer-ffi", optional = true, default-features
symbolic-demangle = { version = "12.8.0", default-features = false, features = ["rust", "cpp", "msvc"] }
symbolic-common = "12.8.0"
data-pipeline-ffi = { path = "../data-pipeline-ffi", default-features = false, optional = true }
function_name = "0.3.0"
6 changes: 2 additions & 4 deletions profiling-ffi/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,15 @@ renaming_overrides_prefixing = true
"Timespec" = "ddog_Timespec"
"Vec_Tag" = "ddog_Vec_Tag"
"Vec_U8" = "ddog_Vec_U8"
"VoidResult" = "ddog_VoidResult"

"ProfilingEndpoint" = "ddog_prof_Endpoint"
"ExporterNewResult" = "ddog_prof_Exporter_NewResult"
"File" = "ddog_prof_Exporter_File"
"ProfileExporter" = "ddog_prof_Exporter"
"ProfileNewResult" = "ddog_prof_Profile_NewResult"
"ProfileResult" = "ddog_prof_Profile_Result"
"ProfilingEndpoint" = "ddog_prof_Endpoint"
"Request" = "ddog_prof_Exporter_Request"
"RequestBuildResult" = "ddog_prof_Exporter_Request_BuildResult"
"SendResult" = "ddog_prof_Exporter_SendResult"
"SerializeResult" = "ddog_prof_Profile_SerializeResult"
"Slice_File" = "ddog_prof_Exporter_Slice_File"

[export.mangle]
Expand Down
Loading

0 comments on commit 1374f98

Please sign in to comment.