luaur_repl_cli/functions/
profiler_dump.rs1use alloc::collections::BTreeMap;
4use core::ffi::{c_char, c_int, CStr};
5use core::sync::atomic::Ordering;
6use std::io::Write;
7
8use luaur_vm::functions::lua_c_statename::luaC_statename;
9
10use crate::functions::profiler_trigger::G_PROFILER;
11
12pub fn profiler_dump(path: *const c_char) {
13 unsafe {
14 if path.is_null() {
15 return;
16 }
17 let path_str = CStr::from_ptr(path).to_string_lossy().into_owned();
18 let profiler = core::ptr::addr_of_mut!(G_PROFILER).as_mut().unwrap();
19
20 let mut f = match std::fs::File::create(&path_str) {
21 Ok(f) => f,
22 Err(_) => {
23 eprintln!("Error opening profile {}", path_str);
24 return;
25 }
26 };
27
28 let mut total: u64 = 0;
29 let data = profiler.data.get_or_insert_with(BTreeMap::new);
30 for (stack, &ticks) in data.iter() {
31 let _ = writeln!(f, "{} {}", ticks, stack);
33 total += ticks;
34 }
35 drop(f);
36
37 let stacks = data.len();
38 let samples = profiler.samples.load(Ordering::Relaxed);
39 println!(
40 "Profiler dump written to {} (total runtime {:.3} seconds, {} samples, {} stacks)",
41 path_str,
42 total as f64 / 1e6,
43 samples,
44 stacks
45 );
46
47 let mut totalgc: u64 = 0;
48 for &p in profiler.gc.iter() {
49 totalgc += p;
50 }
51
52 if totalgc != 0 {
53 print!(
54 "GC: {:.3} seconds ({:.2}%)",
55 totalgc as f64 / 1e6,
56 totalgc as f64 / total as f64 * 100.0
57 );
58
59 for i in 0..profiler.gc.len() {
60 let p = profiler.gc[i];
61 if p != 0 {
62 let name_ptr = luaC_statename(i as c_int);
63 let name = if name_ptr.is_null() {
64 alloc::borrow::Cow::Borrowed("")
65 } else {
66 CStr::from_ptr(name_ptr).to_string_lossy()
67 };
68 print!(", {} {:.2}%", name, p as f64 / totalgc as f64 * 100.0);
69 }
70 }
71
72 println!();
73 }
74 }
75}