From 39c6b0ab06b86ba500ae84b0664845ae28b9cc69 Mon Sep 17 00:00:00 2001 From: obchain Date: Thu, 18 Jun 2026 16:39:22 +0530 Subject: [PATCH] perf(ui/state): borrow &str key in compute_grouped_rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit compute_grouped_rows is called every render frame when grouping is active. It grouped connections into a HashMap>, cloning conn.process_name once per connection to produce the owned key — N String allocs that existed only as map keys and were dropped immediately after building the stats. Since connections: &'a [Connection] is already live for the lifetime 'a, the process name can be borrowed directly: let key = conn.process_name.as_deref().unwrap_or(""); HashMap changes to HashMap<&'a str, Vec<&'a Connection>>. The downstream group_stats Vec changes from Vec<(String, …)> to Vec<(&'a str, …)>. GroupedRow still stores process_name: String, so the name.clone() calls at row-push sites become name.to_owned() — same allocation count there, but the N per-connection clones in the grouping loop are eliminated. Closes #409 --- src/ui/state.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/ui/state.rs b/src/ui/state.rs index b6ead8c..ffeb615 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -706,18 +706,16 @@ pub fn compute_grouped_rows<'a>( ) -> Vec> { use std::collections::HashMap; - // Group connections by process name - let mut groups: HashMap> = HashMap::new(); + // Group connections by process name, borrowing the name from each connection + // to avoid cloning N Strings just to use as HashMap keys. + let mut groups: HashMap<&'a str, Vec<&'a Connection>> = HashMap::new(); for conn in connections { - let key = conn - .process_name - .clone() - .unwrap_or_else(|| "".to_string()); + let key = conn.process_name.as_deref().unwrap_or(""); groups.entry(key).or_default().push(conn); } // Build stats for each group in a single pass over each group's connections - let mut group_stats: Vec<(String, ProcessGroupStats, Vec<&Connection>)> = groups + let mut group_stats: Vec<(&'a str, ProcessGroupStats, Vec<&'a Connection>)> = groups .into_iter() .map(|(name, conns)| { let mut connection_count = 0usize; @@ -761,9 +759,9 @@ pub fn compute_grouped_rows<'a>( // Build the flattened row list let mut rows = Vec::new(); for (name, stats, conns) in group_stats { - let expanded = expanded_groups.contains(&name); + let expanded = expanded_groups.contains(name); rows.push(GroupedRow::Group { - process_name: name.clone(), + process_name: name.to_owned(), stats, expanded, }); @@ -772,7 +770,7 @@ pub fn compute_grouped_rows<'a>( let conn_count = conns.len(); for (idx, conn) in conns.into_iter().enumerate() { rows.push(GroupedRow::Connection { - process_name: name.clone(), + process_name: name.to_owned(), connection: conn, is_last_in_group: idx == conn_count - 1, });