Skip to main content

hara_native/jit/
hotness.rs

1use std::collections::HashMap;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4pub struct LoopKey {
5    pub function: u16,
6    pub header: u32,
7}
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct JitConfig {
11    pub hot_threshold: u32,
12    pub side_trace_threshold: u32,
13    pub max_traces_per_loop: usize,
14    pub max_branch_exits_before_bailout: u32,
15    pub min_iterations_per_branch_exit: u32,
16    pub max_trace_operations: usize,
17}
18
19impl Default for JitConfig {
20    fn default() -> Self {
21        Self {
22            hot_threshold: 16,
23            side_trace_threshold: 16,
24            max_traces_per_loop: 4,
25            max_branch_exits_before_bailout: 32,
26            min_iterations_per_branch_exit: 8,
27            max_trace_operations: 4096,
28        }
29    }
30}
31
32#[derive(Debug)]
33pub struct Hotness {
34    config: JitConfig,
35    counters: HashMap<LoopKey, u32>,
36}
37
38impl Hotness {
39    pub fn new(config: JitConfig) -> Self {
40        Self {
41            config,
42            counters: HashMap::new(),
43        }
44    }
45
46    pub fn backedge(&mut self, key: LoopKey) -> bool {
47        let counter = self.counters.entry(key).or_default();
48        *counter = counter.saturating_add(1);
49        *counter == self.config.hot_threshold
50    }
51
52    pub fn count(&self, key: LoopKey) -> u32 {
53        self.counters.get(&key).copied().unwrap_or(0)
54    }
55
56    pub fn config(&self) -> JitConfig {
57        self.config
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn counters_are_per_loop_and_saturating() {
67        let key = LoopKey {
68            function: 2,
69            header: 7,
70        };
71        let mut hotness = Hotness::new(JitConfig {
72            hot_threshold: 2,
73            side_trace_threshold: 2,
74            max_traces_per_loop: 4,
75            max_branch_exits_before_bailout: 32,
76            min_iterations_per_branch_exit: 8,
77            max_trace_operations: 10,
78        });
79        assert!(!hotness.backedge(key));
80        assert!(hotness.backedge(key));
81        assert!(!hotness.backedge(key));
82        assert_eq!(hotness.count(key), 3);
83    }
84}