From 8ffe445ad871439ad2d2a3077ee569f146047d7d Mon Sep 17 00:00:00 2001 From: zah Date: Tue, 20 May 2025 09:31:10 +0300 Subject: [PATCH] feat(native): cache rb_intern ids --- .../ext/native_tracer/src/lib.rs | 80 +++++++++++-------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/gems/native-tracer/ext/native_tracer/src/lib.rs b/gems/native-tracer/ext/native_tracer/src/lib.rs index cff3db4..19d9190 100644 --- a/gems/native-tracer/ext/native_tracer/src/lib.rs +++ b/gems/native-tracer/ext/native_tracer/src/lib.rs @@ -63,6 +63,12 @@ extern "C" { struct Recorder { tracer: Tracer, active: bool, + to_s_id: ID, + locals_id: ID, + local_get_id: ID, + inst_meth_id: ID, + parameters_id: ID, + class_id: ID, } unsafe extern "C" fn recorder_free(ptr: *mut c_void) { @@ -101,7 +107,22 @@ unsafe extern "C" fn ruby_recorder_alloc(klass: VALUE) -> VALUE { let path = Path::new(""); let func_id = tracer.ensure_function_id("", path, Line(1)); tracer.events.push(TraceLowLevelEvent::Call(CallRecord { function_id: func_id, args: vec![] })); - let recorder = Box::new(Recorder { tracer, active: false }); + let to_s_id = rb_intern(b"to_s\0".as_ptr() as *const c_char); + let locals_id = rb_intern(b"local_variables\0".as_ptr() as *const c_char); + let local_get_id = rb_intern(b"local_variable_get\0".as_ptr() as *const c_char); + let inst_meth_id = rb_intern(b"instance_method\0".as_ptr() as *const c_char); + let parameters_id = rb_intern(b"parameters\0".as_ptr() as *const c_char); + let class_id = rb_intern(b"class\0".as_ptr() as *const c_char); + let recorder = Box::new(Recorder { + tracer, + active: false, + to_s_id, + locals_id, + local_get_id, + inst_meth_id, + parameters_id, + class_id, + }); let ty = std::ptr::addr_of!(RECORDER_TYPE) as *const rb_data_type_t; rb_data_typed_object_wrap(klass, Box::into_raw(recorder) as *mut c_void, ty) } @@ -151,14 +172,13 @@ unsafe fn cstr_to_string(ptr: *const c_char) -> Option { CStr::from_ptr(ptr).to_str().ok().map(|s| s.to_string()) } -unsafe fn value_to_string(val: VALUE) -> Option { +unsafe fn value_to_string(val: VALUE, to_s_id: ID) -> Option { if RB_TYPE_P(val, rb_sys::ruby_value_type::RUBY_T_STRING) { let ptr = RSTRING_PTR(val); let len = RSTRING_LEN(val) as usize; let slice = std::slice::from_raw_parts(ptr as *const u8, len); return Some(String::from_utf8_lossy(slice).to_string()); } - let to_s_id = rb_intern(b"to_s\0".as_ptr() as *const c_char); let str_val = rb_funcall(val, to_s_id, 0); let ptr = RSTRING_PTR(str_val); let len = RSTRING_LEN(str_val) as usize; @@ -166,7 +186,7 @@ unsafe fn value_to_string(val: VALUE) -> Option { Some(String::from_utf8_lossy(slice).to_string()) } -unsafe fn to_value(tracer: &mut Tracer, val: VALUE, depth: usize) -> ValueRecord { +unsafe fn to_value(tracer: &mut Tracer, val: VALUE, depth: usize, to_s_id: ID) -> ValueRecord { if depth == 0 { let type_id = tracer.ensure_type_id(TypeKind::Error, "No type"); return ValueRecord::None { type_id }; @@ -203,45 +223,40 @@ unsafe fn to_value(tracer: &mut Tracer, val: VALUE, depth: usize) -> ValueRecord let ptr = RARRAY_CONST_PTR(val); for i in 0..len { let elem = *ptr.add(i); - elements.push(to_value(tracer, elem, depth - 1)); + elements.push(to_value(tracer, elem, depth - 1, to_s_id)); } let type_id = tracer.ensure_type_id(TypeKind::Seq, "Array"); return ValueRecord::Sequence { elements, is_slice: false, type_id }; } let class_name = cstr_to_string(rb_obj_classname(val)).unwrap_or_else(|| "Object".to_string()); - let text = value_to_string(val).unwrap_or_default(); + let text = value_to_string(val, to_s_id).unwrap_or_default(); let type_id = tracer.ensure_type_id(TypeKind::Raw, &class_name); ValueRecord::Raw { r: text, type_id } } -unsafe fn record_variables(tracer: &mut Tracer, binding: VALUE) -> Vec { +unsafe fn record_variables(recorder: &mut Recorder, binding: VALUE) -> Vec { let mut result = Vec::new(); - let locals_id = rb_intern(b"local_variables\0".as_ptr() as *const c_char); - let get_id = rb_intern(b"local_variable_get\0".as_ptr() as *const c_char); - let vars = rb_funcall(binding, locals_id, 0); + let vars = rb_funcall(binding, recorder.locals_id, 0); let len = RARRAY_LEN(vars) as usize; let ptr = RARRAY_CONST_PTR(vars); for i in 0..len { let sym = *ptr.add(i); let id = rb_sym2id(sym); let name = CStr::from_ptr(rb_id2name(id)).to_str().unwrap_or(""); - let value = rb_funcall(binding, get_id, 1, sym); - let val_rec = to_value(tracer, value, 10); - tracer.register_variable_with_full_value(name, val_rec.clone()); - let var_id = tracer.ensure_variable_id(name); + let value = rb_funcall(binding, recorder.local_get_id, 1, sym); + let val_rec = to_value(&mut recorder.tracer, value, 10, recorder.to_s_id); + recorder.tracer.register_variable_with_full_value(name, val_rec.clone()); + let var_id = recorder.tracer.ensure_variable_id(name); result.push(FullValueRecord { variable_id: var_id, value: val_rec }); } result } -unsafe fn record_parameters(tracer: &mut Tracer, binding: VALUE, defined_class: VALUE, mid: ID, register: bool) -> Vec { +unsafe fn record_parameters(recorder: &mut Recorder, binding: VALUE, defined_class: VALUE, mid: ID, register: bool) -> Vec { let mut result = Vec::new(); - let inst_meth_id = rb_intern(b"instance_method\0".as_ptr() as *const c_char); - let parameters_id = rb_intern(b"parameters\0".as_ptr() as *const c_char); - let local_get_id = rb_intern(b"local_variable_get\0".as_ptr() as *const c_char); let method_sym = rb_id2sym(mid); - let method_obj = rb_funcall(defined_class, inst_meth_id, 1, method_sym); - let params_ary = rb_funcall(method_obj, parameters_id, 0); + let method_obj = rb_funcall(defined_class, recorder.inst_meth_id, 1, method_sym); + let params_ary = rb_funcall(method_obj, recorder.parameters_id, 0); let params_len = RARRAY_LEN(params_ary) as usize; let params_ptr = RARRAY_CONST_PTR(params_ary); for i in 0..params_len { @@ -260,11 +275,11 @@ unsafe fn record_parameters(tracer: &mut Tracer, binding: VALUE, defined_class: continue; } let name = CStr::from_ptr(name_c).to_str().unwrap_or(""); - let value = rb_funcall(binding, local_get_id, 1, name_sym); - let val_rec = to_value(tracer, value, 10); + let value = rb_funcall(binding, recorder.local_get_id, 1, name_sym); + let val_rec = to_value(&mut recorder.tracer, value, 10, recorder.to_s_id); if register { - tracer.register_variable_with_full_value(name, val_rec.clone()); - let var_id = tracer.ensure_variable_id(name); + recorder.tracer.register_variable_with_full_value(name, val_rec.clone()); + let var_id = recorder.tracer.ensure_variable_id(name); result.push(FullValueRecord { variable_id: var_id, value: val_rec }); } } @@ -309,7 +324,7 @@ unsafe extern "C" fn record_event_api(self_val: VALUE, path: VALUE, line: VALUE, String::from_utf8_lossy(std::slice::from_raw_parts(ptr as *const u8, len)).to_string() }; let line_num = rb_num2long(line) as i64; - let content_str = value_to_string(content).unwrap_or_default(); + let content_str = value_to_string(content, recorder.to_s_id).unwrap_or_default(); record_event(&mut recorder.tracer, &path_str, line_num, &content_str); rb_sys::Qnil.into() } @@ -350,7 +365,7 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) { let binding = rb_tracearg_binding(arg); recorder.tracer.register_step(Path::new(&path), Line(line)); if !NIL_P(binding) { - record_variables(&mut recorder.tracer, binding); + record_variables(recorder, binding); } } else if (ev & RUBY_EVENT_CALL) != 0 { let binding = rb_tracearg_binding(arg); @@ -358,13 +373,12 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) { let self_val = rb_tracearg_self(arg); let mid_sym = rb_tracearg_callee_id(arg); let mid = rb_sym2id(mid_sym); - let class_id = rb_intern(b"class\0".as_ptr() as *const c_char); - let defined_class = rb_funcall(self_val, class_id, 0); + let defined_class = rb_funcall(self_val, recorder.class_id, 0); if !NIL_P(binding) { // register parameter types first - let _ = record_parameters(&mut recorder.tracer, binding, defined_class, mid, false); + let _ = record_parameters(recorder, binding, defined_class, mid, false); } - let self_rec = to_value(&mut recorder.tracer, self_val, 10); + let self_rec = to_value(&mut recorder.tracer, self_val, 10, recorder.to_s_id); recorder .tracer .register_variable_with_full_value("self", self_rec.clone()); @@ -372,7 +386,7 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) { let mut args = if NIL_P(binding) { vec![] } else { - record_parameters(&mut recorder.tracer, binding, defined_class, mid, true) + record_parameters(recorder, binding, defined_class, mid, true) }; args.insert(0, recorder.tracer.arg("self", self_rec)); recorder.tracer.register_step(Path::new(&path), Line(line)); @@ -391,12 +405,12 @@ unsafe extern "C" fn event_hook_raw(data: VALUE, arg: *mut rb_trace_arg_t) { } else if (ev & RUBY_EVENT_RETURN) != 0 { recorder.tracer.register_step(Path::new(&path), Line(line)); let ret = rb_tracearg_return_value(arg); - let val_rec = to_value(&mut recorder.tracer, ret, 10); + let val_rec = to_value(&mut recorder.tracer, ret, 10, recorder.to_s_id); recorder.tracer.register_variable_with_full_value("", val_rec.clone()); recorder.tracer.events.push(TraceLowLevelEvent::Return(ReturnRecord { return_value: val_rec })); } else if (ev & RUBY_EVENT_RAISE) != 0 { let exc = rb_tracearg_raised_exception(arg); - if let Some(msg) = value_to_string(exc) { + if let Some(msg) = value_to_string(exc, recorder.to_s_id) { recorder.tracer.events.push(TraceLowLevelEvent::Event(RecordEvent { kind: EventLogKind::Error, metadata: String::new(),