Skip to content

Commit 5ac0f87

Browse files
committed
refactor(profiling): shrink max file and function name
The maximum length is now 16,383, aka (1 << 14) - 1, or one less than 16 KiB. This has nice properties: 1. It's a single byte "wasted" to use a 16 KiB buffer, which is a multiple of common page sizes. 2. It always encodes to 1 or 2 bytes in protobuf. It's also plenty long--the UI is not going to nicely show function or file names that are this long either. This doesn't check all strings, just the function and file names. I am thinking about enforcing it for all strings but this needs more discussion, such as for an exception message or a fatal error message.
1 parent 9cde556 commit 5ac0f87

1 file changed

Lines changed: 13 additions & 23 deletions

File tree

profiling/src/profiling/stack_walking.rs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ use crate::bindings::{
1616
const COW_PHP_OPEN_TAG: Cow<str> = Cow::Borrowed("<?php");
1717
const COW_TRUNCATED: Cow<str> = Cow::Borrowed("[truncated]");
1818

19-
/// The profiler is not meant to handle such large strings--if a file or
20-
/// function name exceeds this size, it will fail in some manner, or be
21-
/// replaced by a shorter string, etc.
22-
const STR_LEN_LIMIT: usize = u16::MAX as usize;
19+
/// The profiler is not meant to handle such large strings. If a file or
20+
/// function name exceeds this size, it will be represented by a short string,
21+
/// see [`COW_LARGE_STRING`].
22+
///
23+
/// This max is calculated such that when varint encoded for protobuf that it
24+
/// fits into 1 or 2 bytes, never 3 or more.
25+
const MAX_STR_LEN: usize = 0b00111111_11111111; // (1 << 14) - 1, or 16,383
2326
const COW_LARGE_STRING: Cow<str> = Cow::Borrowed("[suspiciously large string]");
2427

2528
#[derive(Default, Debug)]
@@ -78,7 +81,7 @@ pub fn extract_function_name(func: &zend_function) -> Option<Cow<'static, str>>
7881
let len = module_len + class_name_len + method_name.len();
7982

8083
// Rather than fail, we use a short string to represent a long string.
81-
if len >= STR_LEN_LIMIT {
84+
if len > MAX_STR_LEN {
8285
return Some(COW_LARGE_STRING);
8386
}
8487

@@ -151,7 +154,7 @@ unsafe fn extract_file_and_line(
151154
Some(func) if !func.is_internal() => {
152155
// Safety: zai_str_from_zstr will return a valid ZaiStr.
153156
let bytes = zai_str_from_zstr(func.op_array.filename.as_mut()).as_bytes();
154-
let file = if bytes.len() < STR_LEN_LIMIT {
157+
let file = if bytes.len() <= MAX_STR_LEN {
155158
Cow::Owned(String::from_utf8_lossy(bytes).into_owned())
156159
} else {
157160
COW_LARGE_STRING
@@ -589,36 +592,23 @@ mod tests {
589592
}
590593

591594
#[test]
592-
fn test_extract_function_name_at_limit_minus_one() {
595+
fn test_extract_function_name_at_limit() {
593596
unsafe {
594-
let func = ddog_php_test_create_fake_zend_function_with_name_len(STR_LEN_LIMIT - 1);
597+
let func = ddog_php_test_create_fake_zend_function_with_name_len(MAX_STR_LEN);
595598
assert!(!func.is_null());
596599

597600
let name = extract_function_name(&*func).expect("should extract name");
598-
assert_eq!(name.len(), STR_LEN_LIMIT - 1);
601+
assert_eq!(name.len(), MAX_STR_LEN);
599602
assert_ne!(name, COW_LARGE_STRING);
600603

601604
ddog_php_test_free_fake_zend_function(func);
602605
}
603606
}
604607

605-
#[test]
606-
fn test_extract_function_name_at_limit() {
607-
unsafe {
608-
let func = ddog_php_test_create_fake_zend_function_with_name_len(STR_LEN_LIMIT);
609-
assert!(!func.is_null());
610-
611-
let name = extract_function_name(&*func).expect("should return large string marker");
612-
assert_eq!(name, COW_LARGE_STRING);
613-
614-
ddog_php_test_free_fake_zend_function(func);
615-
}
616-
}
617-
618608
#[test]
619609
fn test_extract_function_name_over_limit() {
620610
unsafe {
621-
let func = ddog_php_test_create_fake_zend_function_with_name_len(STR_LEN_LIMIT + 1000);
611+
let func = ddog_php_test_create_fake_zend_function_with_name_len(MAX_STR_LEN + 1);
622612
assert!(!func.is_null());
623613

624614
let name = extract_function_name(&*func).expect("should return large string marker");

0 commit comments

Comments
 (0)