mmtk/util/analysis/
obj_size.rs

1use crate::util::analysis::RtAnalysis;
2use crate::util::statistics::counter::EventCounter;
3use crate::util::statistics::stats::Stats;
4use crate::vm::VMBinding;
5
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex};
8
9/**
10 * This file implements an analysis routine that counts the number of objects allocated
11 * in each size class. Here, a size class 'sizeX' is defined as 'X bytes or lower'. For
12 * example, size64 is the size class with objects <= 64 bytes but > 32 bytes which is
13 * the previous size class.
14 *
15 * We keep track of the size classes using a HashMap with the key being the name of the
16 * size class.
17 */
18pub struct PerSizeClassObjectCounter {
19    running: bool,
20    size_classes: Mutex<HashMap<String, Arc<Mutex<EventCounter>>>>,
21    stats: Arc<Stats>,
22}
23
24// Macro to simplify the creation of a new counter for a particular size class.
25// This is a macro as opposed to a function as otherwise we would have to unlock
26// and relock the size_classes map
27macro_rules! new_ctr {
28    ( $stats:expr, $map:expr, $size_class:expr ) => {{
29        let ctr = $stats.new_event_counter(&$size_class, true, true);
30        $map.insert($size_class.to_string(), ctr.clone());
31        ctr
32    }};
33}
34
35impl PerSizeClassObjectCounter {
36    pub fn new(running: bool, stats: Arc<Stats>) -> Self {
37        Self {
38            running,
39            size_classes: Mutex::new(HashMap::new()),
40            stats,
41        }
42    }
43
44    // Fastest way to compute the smallest power of 2 that is larger than n
45    // See: https://stackoverflow.com/questions/3272424/compute-fast-log-base-2-ceiling/51351885#51351885
46    fn size_class(&self, size: usize) -> usize {
47        2_usize.pow(63_u32 - (size - 1).leading_zeros() + 1)
48    }
49}
50
51impl<VM: VMBinding> RtAnalysis<VM> for PerSizeClassObjectCounter {
52    fn alloc_hook(&mut self, size: usize, _align: usize, _offset: usize) {
53        if !self.running {
54            return;
55        }
56
57        let size_class = format!("size{}", self.size_class(size));
58        let mut size_classes = self.size_classes.lock().unwrap();
59        let c = size_classes.get_mut(&size_class);
60        match c {
61            None => {
62                // Create (and increment) the counter associated with the size class if it doesn't exist
63                let ctr = new_ctr!(self.stats, size_classes, size_class);
64                ctr.lock().unwrap().inc();
65            }
66            Some(ctr) => {
67                // Increment counter associated with the size class
68                ctr.lock().unwrap().inc();
69            }
70        }
71    }
72
73    fn set_running(&mut self, running: bool) {
74        self.running = running;
75    }
76}