-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathmemory_chunks.rs
132 lines (114 loc) · 4.87 KB
/
memory_chunks.rs
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
128
129
130
131
132
use std::backtrace::BacktraceStatus;
use egui::{Color32, DragValue, Rect, ScrollArea, Sense, Ui, Vec2};
use super::ColorScheme;
use crate::allocator::free_list_allocator::MemoryChunk;
pub(crate) struct MemoryChunksVisualizationSettings {
pub width_in_bytes: u64,
pub show_backtraces: bool,
}
impl Default for MemoryChunksVisualizationSettings {
fn default() -> Self {
Self {
width_in_bytes: 1024,
show_backtraces: false,
}
}
}
impl MemoryChunksVisualizationSettings {
pub fn ui(&mut self, ui: &mut Ui, store_stack_traces: bool) {
if store_stack_traces {
ui.checkbox(&mut self.show_backtraces, "Show backtraces");
}
// Slider for changing the 'zoom' level of the visualizer.
const BYTES_PER_UNIT_MIN: i32 = 1;
const BYTES_PER_UNIT_MAX: i32 = 1024 * 1024;
ui.horizontal(|ui| {
ui.add(
DragValue::new(&mut self.width_in_bytes)
.clamp_range(BYTES_PER_UNIT_MIN..=BYTES_PER_UNIT_MAX)
.speed(10.0),
);
ui.label("Bytes per line");
});
}
}
pub(crate) fn render_memory_chunks_ui<'a>(
ui: &mut Ui,
color_scheme: &ColorScheme,
settings: &MemoryChunksVisualizationSettings,
total_size_in_bytes: u64,
data: impl IntoIterator<Item = &'a MemoryChunk>,
) {
let line_height = ui.text_style_height(&egui::TextStyle::Body);
let number_of_rows =
(total_size_in_bytes as f32 / settings.width_in_bytes as f32).ceil() as usize;
ScrollArea::new([false, true]).show_rows(ui, line_height, number_of_rows, |ui, range| {
// Let range be in bytes
let start_in_bytes = range.start as u64 * settings.width_in_bytes;
let end_in_bytes = range.end as u64 * settings.width_in_bytes;
let mut data = data
.into_iter()
.filter(|chunk| {
(chunk.offset + chunk.size) > start_in_bytes && chunk.offset < end_in_bytes
})
.collect::<Vec<_>>();
data.sort_by_key(|chunk| chunk.offset);
let screen_width = ui.available_width();
let mut cursor_idx = 0;
let mut bytes_required = data[cursor_idx].offset + data[cursor_idx].size - start_in_bytes;
for _ in range {
ui.horizontal(|ui| {
let mut bytes_left = settings.width_in_bytes;
let mut cursor = ui.cursor().min;
while cursor_idx < data.len() && bytes_left > 0 {
// Block is depleted, so reset for more chunks
while bytes_required == 0 {
cursor_idx += 1;
if cursor_idx < data.len() {
bytes_required = data[cursor_idx].size;
}
}
let bytes_used = bytes_required.min(bytes_left);
let width_used =
bytes_used as f32 * screen_width / settings.width_in_bytes as f32;
// Draw the rectangle
let resp = ui.allocate_rect(
Rect::from_min_size(cursor, Vec2::new(width_used, line_height)),
Sense::click(),
);
if ui.is_rect_visible(resp.rect) {
ui.painter().rect(
resp.rect,
egui::Rounding::ZERO,
color_scheme
.get_allocation_type_color(data[cursor_idx].allocation_type),
egui::Stroke::new(1.0, Color32::BLACK),
);
resp.on_hover_ui_at_pointer(|ui| {
let chunk = &data[cursor_idx];
ui.label(format!("id: {}", chunk.chunk_id));
ui.label(format!("offset: 0x{:x}", chunk.offset));
ui.label(format!("size: 0x{:x}", chunk.size));
ui.label(format!(
"allocation_type: {}",
chunk.allocation_type.as_str()
));
if let Some(name) = &chunk.name {
ui.label(format!("name: {}", name));
}
if settings.show_backtraces
&& chunk.backtrace.status() == BacktraceStatus::Captured
{
ui.label(chunk.backtrace.to_string());
}
});
}
// Update our cursors
cursor.x += width_used;
bytes_left -= bytes_used;
bytes_required -= bytes_used;
}
});
}
});
}