Skip to content

Commit

Permalink
other: optimize truncate_text
Browse files Browse the repository at this point in the history
Flamegraphs showed that this area seems to be a bit heavy at times with
some inefficient use of iterators and collection. This change should
hopefully optimize this a bit by reducing some collections or
reallocations.

There can also be some further optimizations with less allocations from
callers.
  • Loading branch information
ClementTsang committed Nov 28, 2022
1 parent c4c6a0a commit 66ab3b4
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ doctest = true
doc = true

[profile.release]
# debug = true
debug = 0
strip = "symbols"
lto = true
Expand Down
1 change: 1 addition & 0 deletions src/app/data_harvester/memory/general/heim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub async fn get_ram_data() -> crate::utils::error::Result<Option<MemHarvest>> {
let (mem_total_in_kib, mem_used_in_kib) = {
#[cfg(target_os = "linux")]
{
// TODO: [OPT] is this efficient?
use smol::fs::read_to_string;
let meminfo = read_to_string("/proc/meminfo").await?;

Expand Down
6 changes: 5 additions & 1 deletion src/components/data_table/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ where
.iter()
.zip(&self.state.calculated_widths)
.filter_map(|(column, &width)| {
data_row.to_cell(column.inner(), width)
if width > 0 {
data_row.to_cell(column.inner(), width)
} else {
None
}
}),
);

Expand Down
2 changes: 1 addition & 1 deletion src/components/time_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl<'a> TimeGraph<'a> {

// This is some ugly manual loop unswitching. Maybe unnecessary.
// TODO: Optimize this step. Cut out unneeded points.
let data = graph_data.iter().map(|data| create_dataset(data)).collect();
let data = graph_data.iter().map(create_dataset).collect();
let block = Block::default()
.title(self.generate_title(draw_loc))
.borders(Borders::ALL)
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ pub fn create_collection_thread(
}
}
}

// TODO: [OPT] this feels like it might not be totally optimal. Hm.
futures::executor::block_on(data_state.update_data());

// Yet another check to bail if needed...
Expand Down
45 changes: 36 additions & 9 deletions src/utils/gen_util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::cmp::Ordering;

use concat_string::concat_string;
use tui::text::Text;
use tui::text::{Span, Spans, Text};
use unicode_segmentation::UnicodeSegmentation;

pub const KILO_LIMIT: u64 = 1000;
Expand Down Expand Up @@ -99,14 +98,37 @@ pub fn get_decimal_prefix(quantity: u64, unit: &str) -> (f64, String) {
/// Truncates text if it is too long, and adds an ellipsis at the end if needed.
pub fn truncate_text<'a, U: Into<usize>>(content: &str, width: U) -> Text<'a> {
let width = width.into();
let graphemes: Vec<&str> = UnicodeSegmentation::graphemes(content, true).collect();

if graphemes.len() > width && width > 0 {
// Truncate with ellipsis
let first_n = graphemes[..(width - 1)].concat();
Text::raw(concat_string!(first_n, "…"))
let mut graphemes = UnicodeSegmentation::graphemes(content, true);
let grapheme_len = {
let (_, upper) = graphemes.size_hint();
match upper {
Some(upper) => upper,
None => graphemes.clone().count(), // Don't think this ever fires.
}
};

let text = if grapheme_len > width {
let mut text = String::with_capacity(width);
// Truncate with ellipsis.

// Use a hack to reduce the size to size `width`. Think of it like removing
// The last `grapheme_len - width` graphemes, which reduces the length to
// `width` long.
//
// This is a way to get around the currently experimental`advance_back_by`.
graphemes.nth_back(grapheme_len - width);

text.push_str(graphemes.as_str());
text.push('…');

text
} else {
Text::raw(content.to_string())
content.to_string()
};

// TODO: [OPT] maybe add interning here?
Text {
lines: vec![Spans(vec![Span::raw(text)])],
}
}

Expand Down Expand Up @@ -156,4 +178,9 @@ mod test {
y.sort_by(|a, b| sort_partial_fn(true)(a, b));
assert_eq!(y, vec![16.15, 15.0, 1.0, -1.0, -100.0, -100.0, -100.1]);
}

#[test]
fn test_truncation() {
// TODO: Add tests for `truncate_text`
}
}
1 change: 1 addition & 0 deletions src/widgets/process_table/proc_widget_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ impl ProcWidgetData {

impl DataToCell<ProcColumn> for ProcWidgetData {
fn to_cell<'a>(&'a self, column: &ProcColumn, calculated_width: u16) -> Option<Text<'a>> {
// TODO: Optimize the string allocations here...
Some(truncate_text(
&match column {
ProcColumn::CpuPercent => {
Expand Down

0 comments on commit 66ab3b4

Please sign in to comment.