Skip to content

perf(ui/interfaces): halve per-interface HashMap lookups and drop a String clone on every render #398

Description

@obchain

Problem

In src/ui/tabs/interfaces.rs, inside the per-interface loop that runs every TUI frame, there are three small but avoidable costs:

1. Duplicate rates.get() call (lines 76 + 82)

let rx_rate_str = if let Some(rate) = rates.get(&stat.interface_name) {
    format!("{}/s", format_bytes(rate.rx_bytes_per_sec))
} else {
    "---".to_string()
};

let tx_rate_str = if let Some(rate) = rates.get(&stat.interface_name) {
    format!("{}/s", format_bytes(rate.tx_bytes_per_sec))
} else {
    "---".to_string()
};

rates is a HashMap<String, InterfaceRates>. Both lookups hash and compare the same key (stat.interface_name). A single let rate = rates.get(&stat.interface_name); binding covers both.

2. stat.interface_name.clone() (line 93)

Cell::from(stat.interface_name.clone())

stat is already borrowed (&InterfaceStats). Cell::from accepts &str via Into<Cell<'_>>, so the clone is unnecessary — stat.interface_name.as_str() suffices.

3. s.to_string() in the header closure (line 123)

let right = |s: &str| Cell::from(Line::from(s.to_string()).right_aligned());

All arguments are &'static str literals. Line::from(s) with s: &str is valid — the codebase already uses Line::from("...") throughout. The to_string() allocates a String only to construct a Line that could be built directly from the &str.

Fix

  • Merge the two rates.get() calls into one binding.
  • Replace stat.interface_name.clone() with stat.interface_name.as_str().
  • Replace Line::from(s.to_string()) with Line::from(s) in the header closure.

All three are zero-behaviour-change refactors on the hot render path.

Impact

Per-frame, per-interface-entry: −1 HashMap hash+compare, −1 String clone. Per-frame in the header: −9 String allocations (one per column label).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions