1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::cell::RefCell;
use std::sync::Mutex;

use anyhow::Context;
use serde::Serialize;

use crate::utility::counter::Counter;

/// Simulation statistics to be accessed by a single thread.
#[derive(Debug)]
pub struct LocalSimStats {
    pub alloc_counts: RefCell<Counter>,
    pub dealloc_counts: RefCell<Counter>,
    pub syscall_counts: RefCell<Counter>,
}

impl LocalSimStats {
    pub fn new() -> Self {
        Self {
            alloc_counts: RefCell::new(Counter::new()),
            dealloc_counts: RefCell::new(Counter::new()),
            syscall_counts: RefCell::new(Counter::new()),
        }
    }
}

impl Default for LocalSimStats {
    fn default() -> Self {
        Self::new()
    }
}

/// Simulation statistics to be accessed by multiple threads.
#[derive(Debug)]
pub struct SharedSimStats {
    pub alloc_counts: Mutex<Counter>,
    pub dealloc_counts: Mutex<Counter>,
    pub syscall_counts: Mutex<Counter>,
}

impl SharedSimStats {
    pub fn new() -> Self {
        Self {
            alloc_counts: Mutex::new(Counter::new()),
            dealloc_counts: Mutex::new(Counter::new()),
            syscall_counts: Mutex::new(Counter::new()),
        }
    }

    /// Add stats from a local object to a shared object. May reset fields of `local`.
    pub fn add_from_local_stats(&self, local: &LocalSimStats) {
        let mut shared_alloc_counts = self.alloc_counts.lock().unwrap();
        let mut shared_dealloc_counts = self.dealloc_counts.lock().unwrap();
        let mut shared_syscall_counts = self.syscall_counts.lock().unwrap();

        let mut local_alloc_counts = local.alloc_counts.borrow_mut();
        let mut local_dealloc_counts = local.dealloc_counts.borrow_mut();
        let mut local_syscall_counts = local.syscall_counts.borrow_mut();

        shared_alloc_counts.add_counter(&local_alloc_counts);
        shared_dealloc_counts.add_counter(&local_dealloc_counts);
        shared_syscall_counts.add_counter(&local_syscall_counts);

        *local_alloc_counts = Counter::new();
        *local_dealloc_counts = Counter::new();
        *local_syscall_counts = Counter::new();
    }
}

impl Default for SharedSimStats {
    fn default() -> Self {
        Self::new()
    }
}

/// Simulation statistics in the format to be output.
#[derive(Serialize, Clone, Debug)]
struct SimStatsForOutput {
    pub objects: ObjectStatsForOutput,
    pub syscalls: Counter,
}

#[derive(Serialize, Clone, Debug)]
struct ObjectStatsForOutput {
    pub alloc_counts: Counter,
    pub dealloc_counts: Counter,
}

impl SimStatsForOutput {
    /// Takes data from `stats` and puts it into a structure designed for output. May reset fields
    /// of `stats`.
    pub fn new(stats: &SharedSimStats) -> Self {
        Self {
            objects: ObjectStatsForOutput {
                alloc_counts: std::mem::replace(
                    &mut stats.alloc_counts.lock().unwrap(),
                    Counter::new(),
                ),
                dealloc_counts: std::mem::replace(
                    &mut stats.dealloc_counts.lock().unwrap(),
                    Counter::new(),
                ),
            },
            syscalls: std::mem::replace(&mut stats.syscall_counts.lock().unwrap(), Counter::new()),
        }
    }
}

/// May reset fields of `stats`.
pub fn write_stats_to_file(
    filename: &std::path::Path,
    stats: &SharedSimStats,
) -> anyhow::Result<()> {
    let stats = SimStatsForOutput::new(stats);

    let file = std::fs::File::create(filename)
        .with_context(|| format!("Failed to create file '{}'", filename.display()))?;

    serde_json::to_writer_pretty(file, &stats).with_context(|| {
        format!(
            "Failed to write stats json to file '{}'",
            filename.display()
        )
    })?;

    Ok(())
}