Skip to content

Commit 828a5df

Browse files
add allocation and exception count to event.json (#2392)
1 parent fecdcfc commit 828a5df

File tree

5 files changed

+52
-3
lines changed

5 files changed

+52
-3
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.

profiling/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ libc = "0.2"
2828
log = { version = "0.4", features = ["max_level_trace", "release_max_level_trace"]}
2929
once_cell = { version = "1.12" }
3030
ouroboros = { version = "0.17.0" }
31+
serde_json = {version = "1.0"}
3132
rand = { version = "0.8.5" }
3233
rand_distr = { version = "0.4.3" }
3334
uuid = { version = "1.0", features = ["v4"] }

profiling/src/allocation.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use log::{debug, error, trace, warn};
88
use rand::rngs::ThreadRng;
99
use std::cell::RefCell;
1010
use std::ffi::CStr;
11+
use std::sync::atomic::AtomicU64;
12+
use std::sync::atomic::Ordering::SeqCst;
1113

1214
use rand_distr::{Distribution, Poisson};
1315

@@ -36,6 +38,15 @@ pub fn allocation_profiling_minit() {
3638
/// take a sample every 4096 KiB
3739
pub const ALLOCATION_PROFILING_INTERVAL: f64 = 1024.0 * 4096.0;
3840

41+
/// this will store the count of allocations (including reallocations) during a profiling period.
42+
/// This will overflow when doing more then u64::MAX allocations, which seems big enough to ignore.
43+
pub static ALLOCATION_PROFILING_COUNT: AtomicU64 = AtomicU64::new(0);
44+
45+
/// this will store the accumulated size of all allocations in bytes during the profiling period.
46+
/// This will overflow when allocating more then 18 exabyte of memory (u64::MAX) which might not
47+
/// happen, so we can ignore this
48+
pub static ALLOCATION_PROFILING_SIZE: AtomicU64 = AtomicU64::new(0);
49+
3950
pub struct AllocationProfilingStats {
4051
/// number of bytes until next sample collection
4152
next_sample: i64,
@@ -326,6 +337,9 @@ unsafe extern "C" fn alloc_profiling_gc_mem_caches(
326337
}
327338

328339
unsafe extern "C" fn alloc_profiling_malloc(len: size_t) -> *mut c_void {
340+
ALLOCATION_PROFILING_COUNT.fetch_add(1, SeqCst);
341+
ALLOCATION_PROFILING_SIZE.fetch_add(len as u64, SeqCst);
342+
329343
let ptr: *mut c_void = ALLOCATION_PROFILING_ALLOC(len);
330344

331345
// during startup, minit, rinit, ... current_execute_data is null
@@ -379,6 +393,9 @@ unsafe fn allocation_profiling_orig_free(ptr: *mut c_void) {
379393
}
380394

381395
unsafe extern "C" fn alloc_profiling_realloc(prev_ptr: *mut c_void, len: size_t) -> *mut c_void {
396+
ALLOCATION_PROFILING_COUNT.fetch_add(1, SeqCst);
397+
ALLOCATION_PROFILING_SIZE.fetch_add(len as u64, SeqCst);
398+
382399
let ptr: *mut c_void = ALLOCATION_PROFILING_REALLOC(prev_ptr, len);
383400

384401
// during startup, minit, rinit, ... current_execute_data is null

profiling/src/exception.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ use rand_distr::{Distribution, Poisson};
1212
/// The engine's previous throw exception hook
1313
static mut PREV_ZEND_THROW_EXCEPTION_HOOK: Option<zend::VmZendThrowExceptionHook> = None;
1414

15-
/// take a sample every 100 exceptions
15+
/// Take a sample every 100 exceptions
1616
pub static EXCEPTION_PROFILING_INTERVAL: AtomicU32 = AtomicU32::new(100);
1717

18+
/// This will store the number of exceptions thrown during a profiling period. It will overflow
19+
/// when throwing more then 4_294_967_295 exceptions during this period which we currently
20+
/// believe will bring down your application anyway, so accurate numbers are not a problem.
21+
pub static EXCEPTION_PROFILING_EXCEPTION_COUNT: AtomicU32 = AtomicU32::new(0);
22+
1823
pub struct ExceptionProfilingStats {
1924
/// number of exceptions until next sample collection
2025
next_sample: u32,
@@ -109,6 +114,8 @@ unsafe extern "C" fn exception_profiling_throw_exception_hook(
109114
#[cfg(php7)] exception: *mut zend::zval,
110115
#[cfg(php8)] exception: *mut zend::zend_object,
111116
) {
117+
EXCEPTION_PROFILING_EXCEPTION_COUNT.fetch_add(1, Ordering::SeqCst);
118+
112119
let exception_profiling = REQUEST_LOCALS.with(|cell| {
113120
cell.try_borrow()
114121
.map(|locals| locals.profiling_experimental_exception_enabled)

profiling/src/profiling/uploader.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use crate::allocation::{ALLOCATION_PROFILING_COUNT, ALLOCATION_PROFILING_SIZE};
2+
use crate::exception::EXCEPTION_PROFILING_EXCEPTION_COUNT;
13
use crate::profiling::{UploadMessage, UploadRequest};
24
use crate::{PROFILER_NAME_STR, PROFILER_VERSION_STR};
35
use crossbeam_channel::{select, Receiver};
46
use datadog_profiling::exporter::{Endpoint, File};
57
use log::{debug, info, warn};
8+
use serde_json::json;
69
use std::borrow::Cow;
710
use std::str;
11+
use std::sync::atomic::Ordering;
812
use std::sync::{Arc, Barrier};
913
use std::time::Duration;
1014

@@ -27,6 +31,17 @@ impl Uploader {
2731
}
2832
}
2933

34+
/// This function will not only create the internal metadata JSON representation, but is also
35+
/// in charge to reset all those counters back to 0.
36+
fn create_internal_metadata() -> Option<serde_json::Value> {
37+
let metadata = json!({
38+
"exceptions_count": EXCEPTION_PROFILING_EXCEPTION_COUNT.swap(0, Ordering::SeqCst),
39+
"allocations_count": ALLOCATION_PROFILING_COUNT.swap(0, Ordering::SeqCst),
40+
"allocations_size": ALLOCATION_PROFILING_SIZE.swap(0, Ordering::SeqCst),
41+
});
42+
Some(metadata)
43+
}
44+
3045
fn upload(message: UploadRequest) -> anyhow::Result<u16> {
3146
let index = message.index;
3247
let profile = message.profile;
@@ -55,8 +70,16 @@ impl Uploader {
5570
bytes: serialized.buffer.as_slice(),
5671
}];
5772
let timeout = Duration::from_secs(10);
58-
let request =
59-
exporter.build(start, end, &[], files, None, endpoint_counts, None, timeout)?;
73+
let request = exporter.build(
74+
start,
75+
end,
76+
&[],
77+
files,
78+
None,
79+
endpoint_counts,
80+
Self::create_internal_metadata(),
81+
timeout,
82+
)?;
6083
debug!("Sending profile to: {}", index.endpoint);
6184
let result = exporter.send(request, None)?;
6285
Ok(result.status().as_u16())

0 commit comments

Comments
 (0)