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
//! Heap layout management.

pub mod layout;
pub mod trace;

use self::trace::{Packet, Parser};
use anyhow::{bail, Result};
use std::{collections::BTreeMap, fs::File};

/// Processed trace map.
pub type TraceMap = BTreeMap<u32, TraceEntry>;

/// Processed trace entry.
#[derive(Default)]
pub struct TraceEntry {
    /// Currently allocated bytes.
    pub cur: u32,
    /// Maximum allocated bytes.
    pub max: u32,
    /// Total allocated bytes.
    pub total: u32,
}

/// Reads the trace file.
pub fn read_trace(trace: &mut TraceMap, trace_file: File, max_size: u32) -> Result<()> {
    let parser = Parser::new(trace_file)?;
    for packet in parser {
        let packet = packet?;
        match packet {
            Packet::Alloc { size } => {
                alloc(trace, size, max_size)?;
            }
            Packet::Dealloc { size } => {
                dealloc(trace, size)?;
            }
            Packet::Grow { old_size, new_size } | Packet::Shrink { old_size, new_size } => {
                dealloc(trace, old_size)?;
                alloc(trace, new_size, max_size)?;
            }
        }
    }
    Ok(())
}

fn alloc(trace: &mut TraceMap, size: u32, max_size: u32) -> Result<()> {
    if size > max_size {
        bail!("Trace file is corrupted");
    }
    let entry = trace.entry(size).or_default();
    entry.cur += 1;
    entry.total += 1;
    if entry.max < entry.cur {
        entry.max = entry.cur;
    }
    Ok(())
}

fn dealloc(trace: &mut TraceMap, size: u32) -> Result<()> {
    let entry = trace.entry(size).or_default();
    if entry.cur == 0 {
        bail!("Trace file is corrupted");
    }
    entry.cur -= 1;
    Ok(())
}