diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/gpu-allocator/src/visualizer | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/gpu-allocator/src/visualizer')
3 files changed, 328 insertions, 0 deletions
diff --git a/third_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs b/third_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs new file mode 100644 index 0000000000..a57f212b8e --- /dev/null +++ b/third_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs @@ -0,0 +1,138 @@ +use std::backtrace::BacktraceStatus; + +use egui::{Label, Response, Sense, Ui, WidgetText}; +use egui_extras::{Column, TableBuilder}; + +use crate::allocator::{fmt_bytes, AllocationReport}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub(crate) enum AllocationReportVisualizeSorting { + #[default] + None, + Idx, + Name, + Size, +} + +#[derive(Debug, Default)] +pub(crate) struct AllocationReportVisualizeSettings { + pub filter: String, + pub sorting: AllocationReportVisualizeSorting, + pub ascending: bool, +} + +pub(crate) fn render_allocation_reports_ui( + ui: &mut Ui, + settings: &mut AllocationReportVisualizeSettings, + allocations: impl IntoIterator<Item = AllocationReport>, +) { + ui.horizontal(|ui| { + ui.label("Filter"); + ui.text_edit_singleline(&mut settings.filter); + }); + let breakdown_filter = settings.filter.to_lowercase(); + + let mut allocations = allocations + .into_iter() + .enumerate() + .filter(|(_, report)| report.name.to_lowercase().contains(&breakdown_filter)) + .collect::<Vec<_>>(); + + let row_height = ui.text_style_height(&egui::TextStyle::Body); + + let table = TableBuilder::new(ui) + .striped(true) + .resizable(true) + .column(Column::exact(30.0)) + .column(Column::initial(300.0).at_least(200.0).clip(true)) + .column(Column::exact(70.0)); + + fn header_button(ui: &mut Ui, label: &str) -> Response { + let label = WidgetText::from(label).strong(); + let label = Label::new(label.strong()).sense(Sense::click()); + ui.add(label) + } + + let table = table.header(row_height, |mut row| { + row.col(|ui| { + if header_button(ui, "Idx").clicked() { + if settings.sorting == AllocationReportVisualizeSorting::Idx { + settings.ascending = !settings.ascending; + } else { + settings.sorting = AllocationReportVisualizeSorting::Idx; + settings.ascending = false; + } + } + }); + row.col(|ui| { + if header_button(ui, "Name").clicked() { + if settings.sorting == AllocationReportVisualizeSorting::Name { + settings.ascending = !settings.ascending; + } else { + settings.sorting = AllocationReportVisualizeSorting::Name; + settings.ascending = false; + } + } + }); + row.col(|ui| { + if header_button(ui, "Size").clicked() { + if settings.sorting == AllocationReportVisualizeSorting::Size { + settings.ascending = !settings.ascending; + } else { + settings.sorting = AllocationReportVisualizeSorting::Size; + settings.ascending = false; + } + } + }); + }); + + match (settings.sorting, settings.ascending) { + (AllocationReportVisualizeSorting::None, _) => {} + (AllocationReportVisualizeSorting::Idx, true) => allocations.sort_by_key(|(idx, _)| *idx), + (AllocationReportVisualizeSorting::Idx, false) => { + allocations.sort_by_key(|(idx, _)| std::cmp::Reverse(*idx)) + } + (AllocationReportVisualizeSorting::Name, true) => { + allocations.sort_by(|(_, alloc1), (_, alloc2)| alloc1.name.cmp(&alloc2.name)) + } + (AllocationReportVisualizeSorting::Name, false) => { + allocations.sort_by(|(_, alloc1), (_, alloc2)| alloc1.name.cmp(&alloc2.name).reverse()) + } + (AllocationReportVisualizeSorting::Size, true) => { + allocations.sort_by_key(|(_, alloc)| alloc.size) + } + (AllocationReportVisualizeSorting::Size, false) => { + allocations.sort_by_key(|(_, alloc)| std::cmp::Reverse(alloc.size)) + } + } + + table.body(|mut body| { + for (idx, alloc) in allocations { + body.row(row_height, |mut row| { + let AllocationReport { + name, + size, + backtrace, + } = alloc; + + row.col(|ui| { + ui.label(idx.to_string()); + }); + + let resp = row.col(|ui| { + ui.label(name); + }); + + if backtrace.status() == BacktraceStatus::Captured { + resp.1.on_hover_ui(|ui| { + ui.label(backtrace.to_string()); + }); + } + + row.col(|ui| { + ui.label(fmt_bytes(size)); + }); + }); + } + }); +} diff --git a/third_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs b/third_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs new file mode 100644 index 0000000000..3ef3ff22a0 --- /dev/null +++ b/third_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs @@ -0,0 +1,134 @@ +use std::backtrace::BacktraceStatus; + +use egui::{Color32, DragValue, Rect, ScrollArea, Sense, Ui, Vec2}; + +use crate::allocator::free_list_allocator::MemoryChunk; + +use super::ColorScheme; + +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; + } + continue; + } + + 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; + } + }); + } + }); +} diff --git a/third_party/rust/gpu-allocator/src/visualizer/mod.rs b/third_party/rust/gpu-allocator/src/visualizer/mod.rs new file mode 100644 index 0000000000..113c8454c2 --- /dev/null +++ b/third_party/rust/gpu-allocator/src/visualizer/mod.rs @@ -0,0 +1,56 @@ +use egui::{Color32, Ui}; + +mod allocation_reports; +mod memory_chunks; + +pub(crate) use allocation_reports::*; +pub(crate) use memory_chunks::*; + +use crate::allocator::AllocationType; + +pub const DEFAULT_COLOR_ALLOCATION_TYPE_FREE: Color32 = Color32::from_rgb(159, 159, 159); // gray +pub const DEFAULT_COLOR_ALLOCATION_TYPE_LINEAR: Color32 = Color32::from_rgb(91, 206, 250); // blue +pub const DEFAULT_COLOR_ALLOCATION_TYPE_NON_LINEAR: Color32 = Color32::from_rgb(250, 169, 184); // pink + +#[derive(Clone)] +pub struct ColorScheme { + pub free_color: Color32, + pub linear_color: Color32, + pub non_linear_color: Color32, +} + +impl Default for ColorScheme { + fn default() -> Self { + Self { + free_color: DEFAULT_COLOR_ALLOCATION_TYPE_FREE, + linear_color: DEFAULT_COLOR_ALLOCATION_TYPE_LINEAR, + non_linear_color: DEFAULT_COLOR_ALLOCATION_TYPE_NON_LINEAR, + } + } +} + +impl ColorScheme { + pub(crate) fn get_allocation_type_color(&self, allocation_type: AllocationType) -> Color32 { + match allocation_type { + AllocationType::Free => self.free_color, + AllocationType::Linear => self.linear_color, + AllocationType::NonLinear => self.non_linear_color, + } + } +} + +pub(crate) trait SubAllocatorVisualizer { + fn supports_visualization(&self) -> bool { + false + } + fn draw_base_info(&self, ui: &mut Ui) { + ui.label("No sub allocator information available"); + } + fn draw_visualization( + &self, + _color_scheme: &ColorScheme, + _ui: &mut Ui, + _settings: &MemoryChunksVisualizationSettings, + ) { + } +} |