summaryrefslogtreecommitdiffstats
path: root/third_party/rust/gpu-allocator/src/visualizer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/gpu-allocator/src/visualizer
parentInitial commit. (diff)
downloadfirefox-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')
-rw-r--r--third_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs138
-rw-r--r--third_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs134
-rw-r--r--third_party/rust/gpu-allocator/src/visualizer/mod.rs56
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,
+ ) {
+ }
+}