forge/profile/analyze/
symbols.rs1#![expect(
2 clippy::cast_precision_loss,
3 reason = "profiler sample weights are intentionally converted to percentages"
4)]
5
6use wowlab_types::constants::HUNDRED;
7
8const MIN_MODULE_PARTS: usize = 2;
9const HASH_SUFFIX_LEN: usize = 17;
10const ROUND1_FACTOR: f64 = 10.0;
11
12pub(super) const fn pct(n: u64, total_weight: u64) -> f64 {
13 (n as f64 * HUNDRED) / total_weight as f64
14}
15
16pub(super) fn parse_module(name: &str) -> String {
17 let parts: Vec<&str> = name.split("::").collect();
18 let parts = if parts.len() >= MIN_MODULE_PARTS {
19 let last = parts.last().unwrap_or(&"");
21
22 if last.starts_with('h') && last.len() == HASH_SUFFIX_LEN {
23 &parts[..parts.len() - 1]
25 } else {
26 &*parts
28 }
29 } else {
30 &*parts
32 };
33
34 if parts.len() > 1 {
35 parts[..parts.len() - 1].join("::")
37 } else {
38 name.to_string()
39 }
40}
41
42pub(crate) fn clean_name(name: &str) -> String {
43 let parts: Vec<&str> = name.split("::").collect();
44
45 if parts.len() >= MIN_MODULE_PARTS {
46 let last = parts.last().unwrap_or(&"");
48
49 if last.starts_with('h') && last.len() == HASH_SUFFIX_LEN {
50 return parts[..parts.len() - 1].join("::");
52 }
53 }
54
55 name.to_string()
56}
57
58pub(super) fn symbol_to_source(name: &str) -> Option<String> {
59 if !name.contains("wowlab_engine::") {
60 return None;
61 }
62
63 let parts: Vec<&str> = name.split("::").collect();
64 let start = parts.iter().position(|&p| p == "wowlab_engine")? + 1;
65
66 let mut path_parts = Vec::with_capacity(parts.len().saturating_sub(start));
67 for &p in &parts[start..] {
70 if !p.is_empty() && p.chars().next().is_some_and(char::is_uppercase) {
71 break;
72 }
73
74 path_parts.push(p);
75 }
76
77 if path_parts.is_empty() {
78 return None;
79 }
80
81 if path_parts.len() > 1 {
82 Some(format!(
83 "src/{}/{}.rs",
84 path_parts[..path_parts.len() - 1].join("/"),
86 path_parts.last().unwrap_or(&"")
87 ))
88 } else {
89 Some(format!("src/{}.rs", path_parts[0]))
91 }
92}
93
94pub(super) fn round1(v: f64) -> f64 {
95 (v * ROUND1_FACTOR).round() / ROUND1_FACTOR
96}
97
98pub(super) fn round2(v: f64) -> f64 {
99 (v * HUNDRED).round() / HUNDRED
100}