hara-native 0.1.14

HAL-free native host runtime and package launcher for Hara
Documentation
use std::collections::HashMap;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LoopKey {
    pub function: u16,
    pub header: u32,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct JitConfig {
    pub hot_threshold: u32,
    pub side_trace_threshold: u32,
    pub max_traces_per_loop: usize,
    pub max_branch_exits_before_bailout: u32,
    pub min_iterations_per_branch_exit: u32,
    pub max_trace_operations: usize,
}

impl Default for JitConfig {
    fn default() -> Self {
        Self {
            hot_threshold: 16,
            side_trace_threshold: 16,
            max_traces_per_loop: 4,
            max_branch_exits_before_bailout: 32,
            min_iterations_per_branch_exit: 8,
            max_trace_operations: 4096,
        }
    }
}

#[derive(Debug)]
pub struct Hotness {
    config: JitConfig,
    counters: HashMap<LoopKey, u32>,
}

impl Hotness {
    pub fn new(config: JitConfig) -> Self {
        Self {
            config,
            counters: HashMap::new(),
        }
    }

    pub fn backedge(&mut self, key: LoopKey) -> bool {
        let counter = self.counters.entry(key).or_default();
        *counter = counter.saturating_add(1);
        *counter == self.config.hot_threshold
    }

    pub fn count(&self, key: LoopKey) -> u32 {
        self.counters.get(&key).copied().unwrap_or(0)
    }

    pub fn config(&self) -> JitConfig {
        self.config
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn counters_are_per_loop_and_saturating() {
        let key = LoopKey {
            function: 2,
            header: 7,
        };
        let mut hotness = Hotness::new(JitConfig {
            hot_threshold: 2,
            side_trace_threshold: 2,
            max_traces_per_loop: 4,
            max_branch_exits_before_bailout: 32,
            min_iterations_per_branch_exit: 8,
            max_trace_operations: 10,
        });
        assert!(!hotness.backedge(key));
        assert!(hotness.backedge(key));
        assert!(!hotness.backedge(key));
        assert_eq!(hotness.count(key), 3);
    }
}