Skip to content

Commit 2fd2774

Browse files
committed
feat: optimize native tracer
1 parent 18c9c7c commit 2fd2774

File tree

2 files changed

+58
-26
lines changed

2 files changed

+58
-26
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Read the code of the native tracer implementation line by line and identify any inefficiency, improve performance while preserving correctness.

gems/codetracer-ruby-recorder/ext/native_tracer/src/lib.rs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,26 @@ struct Recorder {
6767
set_class: VALUE,
6868
open_struct_class: VALUE,
6969
struct_type_versions: HashMap<String, usize>,
70+
int_type_id: runtime_tracing::TypeId,
71+
float_type_id: runtime_tracing::TypeId,
72+
bool_type_id: runtime_tracing::TypeId,
73+
string_type_id: runtime_tracing::TypeId,
74+
symbol_type_id: runtime_tracing::TypeId,
75+
error_type_id: runtime_tracing::TypeId,
76+
}
77+
78+
fn should_ignore_path(path: &str) -> bool {
79+
const PATTERNS: [&str; 5] = [
80+
"codetracer_ruby_recorder.rb",
81+
"lib/ruby",
82+
"recorder.rb",
83+
"codetracer_pure_ruby_recorder.rb",
84+
"gems/",
85+
];
86+
if path.starts_with("<internal:") {
87+
return true;
88+
}
89+
PATTERNS.iter().any(|p| path.contains(p))
7090
}
7191

7292
fn value_type_id(val: &ValueRecord) -> runtime_tracing::TypeId {
@@ -165,11 +185,12 @@ unsafe fn get_recorder(obj: VALUE) -> *mut Recorder {
165185
unsafe extern "C" fn ruby_recorder_alloc(klass: VALUE) -> VALUE {
166186
let mut tracer = Tracer::new("ruby", &vec![]);
167187
// pre-register common types to match the pure Ruby tracer
168-
tracer.ensure_type_id(TypeKind::Int, "Integer");
169-
tracer.ensure_type_id(TypeKind::String, "String");
170-
tracer.ensure_type_id(TypeKind::Bool, "Bool");
171-
tracer.ensure_type_id(TypeKind::String, "Symbol");
172-
tracer.ensure_type_id(TypeKind::Error, "No type");
188+
let int_type_id = tracer.ensure_type_id(TypeKind::Int, "Integer");
189+
let string_type_id = tracer.ensure_type_id(TypeKind::String, "String");
190+
let bool_type_id = tracer.ensure_type_id(TypeKind::Bool, "Bool");
191+
let float_type_id = runtime_tracing::NONE_TYPE_ID;
192+
let symbol_type_id = tracer.ensure_type_id(TypeKind::String, "Symbol");
193+
let error_type_id = tracer.ensure_type_id(TypeKind::Error, "No type");
173194
let path = Path::new("");
174195
let func_id = tracer.ensure_function_id("<top-level>", path, Line(1));
175196
tracer.events.push(TraceLowLevelEvent::Call(CallRecord {
@@ -222,6 +243,12 @@ unsafe extern "C" fn ruby_recorder_alloc(klass: VALUE) -> VALUE {
222243
set_class: Qnil.into(),
223244
open_struct_class: Qnil.into(),
224245
struct_type_versions: HashMap::new(),
246+
int_type_id,
247+
float_type_id,
248+
bool_type_id,
249+
string_type_id,
250+
symbol_type_id,
251+
error_type_id,
225252
});
226253
let ty = std::ptr::addr_of!(RECORDER_TYPE) as *const rb_data_type_t;
227254
rb_data_typed_object_wrap(klass, Box::into_raw(recorder) as *mut c_void, ty)
@@ -319,47 +346,54 @@ unsafe fn value_to_string_safe(val: VALUE, to_s_id: ID) -> Option<String> {
319346

320347
unsafe fn to_value(recorder: &mut Recorder, val: VALUE, depth: usize, to_s_id: ID) -> ValueRecord {
321348
if depth == 0 {
322-
let type_id = recorder.tracer.ensure_type_id(TypeKind::Error, "No type");
323-
return ValueRecord::None { type_id };
349+
return ValueRecord::None {
350+
type_id: recorder.error_type_id,
351+
};
324352
}
325353
if NIL_P(val) {
326-
let type_id = recorder.tracer.ensure_type_id(TypeKind::Error, "No type");
327-
return ValueRecord::None { type_id };
354+
return ValueRecord::None {
355+
type_id: recorder.error_type_id,
356+
};
328357
}
329358
if val == (Qtrue as VALUE) || val == (Qfalse as VALUE) {
330-
let type_id = recorder.tracer.ensure_type_id(TypeKind::Bool, "Bool");
331359
return ValueRecord::Bool {
332360
b: val == (Qtrue as VALUE),
333-
type_id,
361+
type_id: recorder.bool_type_id,
334362
};
335363
}
336364
if RB_INTEGER_TYPE_P(val) {
337365
let i = rb_num2long(val) as i64;
338-
let type_id = recorder.tracer.ensure_type_id(TypeKind::Int, "Integer");
339-
return ValueRecord::Int { i, type_id };
366+
return ValueRecord::Int {
367+
i,
368+
type_id: recorder.int_type_id,
369+
};
340370
}
341371
if RB_FLOAT_TYPE_P(val) {
342372
let f = rb_num2dbl(val);
343-
let type_id = recorder.tracer.ensure_type_id(TypeKind::Float, "Float");
373+
let type_id = if recorder.float_type_id == runtime_tracing::NONE_TYPE_ID {
374+
let id = recorder.tracer.ensure_type_id(TypeKind::Float, "Float");
375+
recorder.float_type_id = id;
376+
id
377+
} else {
378+
recorder.float_type_id
379+
};
344380
return ValueRecord::Float { f, type_id };
345381
}
346382
if RB_SYMBOL_P(val) {
347383
let id = rb_sym2id(val);
348384
let name = CStr::from_ptr(rb_id2name(id)).to_str().unwrap_or("");
349-
let type_id = recorder.tracer.ensure_type_id(TypeKind::String, "Symbol");
350385
return ValueRecord::String {
351386
text: name.to_string(),
352-
type_id,
387+
type_id: recorder.symbol_type_id,
353388
};
354389
}
355390
if RB_TYPE_P(val, rb_sys::ruby_value_type::RUBY_T_STRING) {
356391
let ptr = RSTRING_PTR(val);
357392
let len = RSTRING_LEN(val) as usize;
358393
let slice = std::slice::from_raw_parts(ptr as *const u8, len);
359-
let type_id = recorder.tracer.ensure_type_id(TypeKind::String, "String");
360394
return ValueRecord::String {
361395
text: String::from_utf8_lossy(slice).to_string(),
362-
type_id,
396+
type_id: recorder.string_type_id,
363397
};
364398
}
365399
if RB_TYPE_P(val, rb_sys::ruby_value_type::RUBY_T_ARRAY) {
@@ -702,17 +736,14 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) {
702736
let path_bytes = if NIL_P(path_val) {
703737
&[] as &[u8]
704738
} else {
705-
std::slice::from_raw_parts(RSTRING_PTR(path_val) as *const u8, RSTRING_LEN(path_val) as usize)
739+
std::slice::from_raw_parts(
740+
RSTRING_PTR(path_val) as *const u8,
741+
RSTRING_LEN(path_val) as usize,
742+
)
706743
};
707744
let path = std::str::from_utf8(path_bytes).unwrap_or("");
708745
let line = rb_num2long(line_val) as i64;
709-
if path.contains("codetracer_ruby_recorder.rb")
710-
|| path.contains("lib/ruby")
711-
|| path.contains("recorder.rb")
712-
|| path.contains("codetracer_pure_ruby_recorder.rb")
713-
|| path.contains("gems/")
714-
|| path.starts_with("<internal:")
715-
{
746+
if should_ignore_path(path) {
716747
return;
717748
}
718749

0 commit comments

Comments
 (0)