1use std::fs::OpenOptions;
2use std::io::Write;
3use std::path::PathBuf;
4use std::time::Instant;
5
6pub struct ProfileScope {
8 label: String,
9 start: Instant,
10}
11
12impl ProfileScope {
13 pub fn new(label: impl Into<String>) -> Self {
14 Self {
15 label: label.into(),
16 start: Instant::now(),
17 }
18 }
19}
20
21impl Drop for ProfileScope {
22 fn drop(&mut self) {
23 let elapsed = self.start.elapsed();
24
25 log::info!(
26 "[PROFILE] {} - {:.3}ms",
27 self.label,
28 elapsed.as_secs_f64() * 1000.0
29 );
30
31 if let Err(e) = write_profile_log(&self.label, elapsed.as_secs_f64() * 1000.0) {
33 log::warn!("Failed to write profile log: {}", e);
34 }
35 }
36}
37
38fn get_profile_log_path() -> PathBuf {
39 let app_dir = dirs::data_local_dir()
40 .unwrap_or_else(|| PathBuf::from("."))
41 .join("DDALAB");
42
43 std::fs::create_dir_all(&app_dir).ok();
44 app_dir.join("performance_profile.log")
45}
46
47fn write_profile_log(label: &str, duration_ms: f64) -> std::io::Result<()> {
48 let log_path = get_profile_log_path();
49 let mut file = OpenOptions::new()
50 .create(true)
51 .append(true)
52 .open(log_path)?;
53
54 let timestamp = chrono::Utc::now().to_rfc3339();
55 writeln!(file, "{} | {} | {:.3}ms", timestamp, label, duration_ms)?;
56
57 Ok(())
58}
59
60#[macro_export]
62macro_rules! profile_scope {
63 ($label:expr) => {
64 let _profile_scope = $crate::profiling::ProfileScope::new($label);
65 };
66}
67
68pub fn get_profile_log_location() -> String {
70 get_profile_log_path()
71 .to_str()
72 .unwrap_or("Unknown")
73 .to_string()
74}