From 731528c61632a04ec4f3cba99885650e810dba4c Mon Sep 17 00:00:00 2001 From: hashmap Date: Fri, 29 May 2020 10:55:07 +0200 Subject: [PATCH] Some optimizsations in TUI (#3325) * Do not allocate String for static status, use Cow instead, eg we allocate "Running" string at every refresh * Use static dispatch for Views instead of Box * Update only the current view * Simplify Listener trait --- src/bin/tui/logs.rs | 4 ++-- src/bin/tui/menu.rs | 4 ++-- src/bin/tui/mining.rs | 8 +++++--- src/bin/tui/peers.rs | 8 +++++--- src/bin/tui/status.rs | 45 +++++++++++++++++++++--------------------- src/bin/tui/types.rs | 3 --- src/bin/tui/ui.rs | 26 +++++++++++++++--------- src/bin/tui/version.rs | 10 ++-------- 8 files changed, 56 insertions(+), 52 deletions(-) diff --git a/src/bin/tui/logs.rs b/src/bin/tui/logs.rs index 9ca49fd67..eeae77721 100644 --- a/src/bin/tui/logs.rs +++ b/src/bin/tui/logs.rs @@ -28,9 +28,9 @@ use std::collections::VecDeque; pub struct TUILogsView; impl TUILogsView { - pub fn create() -> Box { + pub fn create() -> impl View { let logs_view = ResizedView::with_full_screen(LogBufferView::new(200).with_name("logs")); - Box::new(logs_view.with_name(VIEW_LOGS)) + logs_view.with_name(VIEW_LOGS) } pub fn update(c: &mut Cursive, entry: LogEntry) { diff --git a/src/bin/tui/menu.rs b/src/bin/tui/menu.rs index 8df9c4e9a..3711ff4b1 100644 --- a/src/bin/tui/menu.rs +++ b/src/bin/tui/menu.rs @@ -29,7 +29,7 @@ use crate::tui::constants::{ VIEW_PEER_SYNC, VIEW_VERSION, }; -pub fn create() -> Box { +pub fn create() -> impl View { let mut main_menu = SelectView::new().h_align(HAlign::Left).with_name(MAIN_MENU); main_menu .get_mut() @@ -83,5 +83,5 @@ pub fn create() -> Box { .child(TextView::new("Enter : Select")) .child(TextView::new("Esc : Back ")) .child(TextView::new("Q : Quit ")); - Box::new(main_menu) + main_menu } diff --git a/src/bin/tui/mining.rs b/src/bin/tui/mining.rs index 9064e923b..969af833f 100644 --- a/src/bin/tui/mining.rs +++ b/src/bin/tui/mining.rs @@ -165,9 +165,9 @@ impl TableViewItem for DiffBlock { /// Mining status view pub struct TUIMiningView; -impl TUIStatusListener for TUIMiningView { +impl TUIMiningView { /// Create the mining view - fn create() -> Box { + pub fn create() -> impl View { let devices_button = Button::new_raw("Mining Server Status", |s| { let _ = s.call_on_name("mining_stack_view", |sv: &mut StackView| { let pos = sv.find_layer_from_name("mining_device_view").unwrap(); @@ -307,9 +307,11 @@ impl TUIStatusListener for TUIMiningView { let _ = c.focus_name(MAIN_MENU); }); - Box::new(mining_view.with_name(VIEW_MINING)) + mining_view.with_name(VIEW_MINING) } +} +impl TUIStatusListener for TUIMiningView { /// update fn update(c: &mut Cursive, stats: &ServerStats) { c.call_on_name("diff_cur_height", |t: &mut TextView| { diff --git a/src/bin/tui/peers.rs b/src/bin/tui/peers.rs index 167a84b2b..293b87112 100644 --- a/src/bin/tui/peers.rs +++ b/src/bin/tui/peers.rs @@ -121,8 +121,8 @@ impl TableViewItem for PeerStats { pub struct TUIPeerView; -impl TUIStatusListener for TUIPeerView { - fn create() -> Box { +impl TUIPeerView { + pub fn create() -> impl View { let table_view = TableView::::new() .column(PeerColumn::Address, "Address", |c| c.width_percent(16)) .column(PeerColumn::State, "State", |c| c.width_percent(8)) @@ -159,9 +159,11 @@ impl TUIStatusListener for TUIPeerView { let _ = c.focus_name(MAIN_MENU); }); - Box::new(peer_status_view) + peer_status_view } +} +impl TUIStatusListener for TUIPeerView { fn update(c: &mut Cursive, stats: &ServerStats) { let lp = stats .peer_stats diff --git a/src/bin/tui/status.rs b/src/bin/tui/status.rs index d3ad1ff4f..a82bb4ec0 100644 --- a/src/bin/tui/status.rs +++ b/src/bin/tui/status.rs @@ -20,6 +20,7 @@ use cursive::traits::Identifiable; use cursive::view::View; use cursive::views::{LinearLayout, ResizedView, TextView}; use cursive::Cursive; +use std::borrow::Cow; use crate::tui::constants::VIEW_BASIC_STATUS; use crate::tui::types::TUIStatusListener; @@ -32,11 +33,11 @@ const NANO_TO_MILLIS: f64 = 1.0 / 1_000_000.0; pub struct TUIStatusView; impl TUIStatusView { - fn update_sync_status(sync_status: SyncStatus) -> String { + pub fn update_sync_status(sync_status: SyncStatus) -> Cow<'static, str> { match sync_status { - SyncStatus::Initial => "Initializing".to_string(), - SyncStatus::NoSync => "Running".to_string(), - SyncStatus::AwaitingPeers(_) => "Waiting for peers".to_string(), + SyncStatus::Initial => Cow::Borrowed("Initializing"), + SyncStatus::NoSync => Cow::Borrowed("Running"), + SyncStatus::AwaitingPeers(_) => Cow::Borrowed("Waiting for peers"), SyncStatus::HeaderSync { current_height, highest_height, @@ -46,7 +47,7 @@ impl TUIStatusView { } else { current_height * 100 / highest_height }; - format!("Sync step 1/7: Downloading headers: {}%", percent) + Cow::Owned(format!("Sync step 1/7: Downloading headers: {}%", percent)) } SyncStatus::TxHashsetDownload(stat) => { if stat.total_size > 0 { @@ -55,23 +56,23 @@ impl TUIStatusView { let fin = Utc::now().timestamp_nanos(); let dur_ms = (fin - start) as f64 * NANO_TO_MILLIS; - format!("Sync step 2/7: Downloading {}(MB) chain state for state sync: {}% at {:.1?}(kB/s)", + Cow::Owned(format!("Sync step 2/7: Downloading {}(MB) chain state for state sync: {}% at {:.1?}(kB/s)", stat.total_size / 1_000_000, percent, if dur_ms > 1.0f64 { stat.downloaded_size.saturating_sub(stat.prev_downloaded_size) as f64 / dur_ms as f64 } else { 0f64 }, - ) + )) } else { let start = stat.start_time.timestamp_millis(); let fin = Utc::now().timestamp_millis(); let dur_secs = (fin - start) / 1000; - format!("Sync step 2/7: Downloading chain state for state sync. Waiting remote peer to start: {}s", + Cow::Owned(format!("Sync step 2/7: Downloading chain state for state sync. Waiting remote peer to start: {}s", dur_secs, - ) + )) } } SyncStatus::TxHashsetSetup => { - "Sync step 3/7: Preparing chain state for validation".to_string() + Cow::Borrowed("Sync step 3/7: Preparing chain state for validation") } SyncStatus::TxHashsetRangeProofsValidation { rproofs, @@ -82,10 +83,10 @@ impl TUIStatusView { } else { 0 }; - format!( + Cow::Owned(format!( "Sync step 4/7: Validating chain state - range proofs: {}%", r_percent - ) + )) } SyncStatus::TxHashsetKernelsValidation { kernels, @@ -96,16 +97,16 @@ impl TUIStatusView { } else { 0 }; - format!( + Cow::Owned(format!( "Sync step 5/7: Validating chain state - kernels: {}%", k_percent - ) + )) } SyncStatus::TxHashsetSave => { - "Sync step 6/7: Finalizing chain state for state sync".to_string() + Cow::Borrowed("Sync step 6/7: Finalizing chain state for state sync") } SyncStatus::TxHashsetDone => { - "Sync step 6/7: Finalized chain state for state sync".to_string() + Cow::Borrowed("Sync step 6/7: Finalized chain state for state sync") } SyncStatus::BodySync { current_height, @@ -116,16 +117,14 @@ impl TUIStatusView { } else { current_height * 100 / highest_height }; - format!("Sync step 7/7: Downloading blocks: {}%", percent) + Cow::Owned(format!("Sync step 7/7: Downloading blocks: {}%", percent)) } - SyncStatus::Shutdown => "Shutting down, closing connections".to_string(), + SyncStatus::Shutdown => Cow::Borrowed("Shutting down, closing connections"), } } -} -impl TUIStatusListener for TUIStatusView { /// Create basic status view - fn create() -> Box { + pub fn create() -> impl View { let basic_status_view = ResizedView::with_full_screen( LinearLayout::new(Orientation::Vertical) .child( @@ -232,9 +231,11 @@ impl TUIStatusListener for TUIStatusView { .child(TextView::new(" ").with_name("basic_network_info")), ), //.child(logo_view) ); - Box::new(basic_status_view.with_name(VIEW_BASIC_STATUS)) + basic_status_view.with_name(VIEW_BASIC_STATUS) } +} +impl TUIStatusListener for TUIStatusView { fn update(c: &mut Cursive, stats: &ServerStats) { let basic_status = TUIStatusView::update_sync_status(stats.sync_status); diff --git a/src/bin/tui/types.rs b/src/bin/tui/types.rs index 05a9b62b8..b476e6a96 100644 --- a/src/bin/tui/types.rs +++ b/src/bin/tui/types.rs @@ -15,7 +15,6 @@ //! Types specific to the UI module use crate::servers::ServerStats; -use cursive::view::View; use cursive::Cursive; /// Main message struct to communicate between the UI and @@ -28,8 +27,6 @@ pub enum UIMessage { /// and updates itself pub trait TUIStatusListener { - /// create the view, to return to the main UI controller - fn create() -> Box; /// Update according to status update contents fn update(c: &mut Cursive, stats: &ServerStats); } diff --git a/src/bin/tui/ui.rs b/src/bin/tui/ui.rs index 640af79b5..86f8af35b 100644 --- a/src/bin/tui/ui.rs +++ b/src/bin/tui/ui.rs @@ -26,14 +26,17 @@ use cursive::theme::{BaseColor, BorderStyle, Color, Theme}; use cursive::traits::Boxable; use cursive::traits::Identifiable; use cursive::utils::markup::StyledString; -use cursive::views::{BoxedView, CircularFocus, Dialog, LinearLayout, Panel, StackView, TextView}; +use cursive::views::{ + CircularFocus, Dialog, LinearLayout, Panel, SelectView, StackView, TextView, ViewRef, +}; use cursive::Cursive; use std::sync::mpsc; use std::{thread, time}; +use super::constants::MAIN_MENU; use crate::built_info; use crate::servers::Server; -use crate::tui::constants::ROOT_STACK; +use crate::tui::constants::{ROOT_STACK, VIEW_BASIC_STATUS, VIEW_MINING, VIEW_PEER_SYNC}; use crate::tui::types::{TUIStatusListener, UIMessage}; use crate::tui::{logs, menu, mining, peers, status, version}; use grin_util::logger::LogEntry; @@ -106,7 +109,7 @@ impl UI { .child(Panel::new(TextView::new(title_string).full_width())) .child( LinearLayout::new(Orientation::Horizontal) - .child(Panel::new(BoxedView::new(main_menu))) + .child(Panel::new(main_menu)) .child(Panel::new(root_stack)), ); @@ -144,12 +147,17 @@ impl UI { // Process any pending UI messages while let Some(message) = self.ui_rx.try_iter().next() { - match message { - UIMessage::UpdateStatus(update) => { - status::TUIStatusView::update(&mut self.cursive, &update); - mining::TUIMiningView::update(&mut self.cursive, &update); - peers::TUIPeerView::update(&mut self.cursive, &update); - version::TUIVersionView::update(&mut self.cursive, &update); + let menu: ViewRef> = self.cursive.find_name(MAIN_MENU).unwrap(); + if let Some(selection) = menu.selection() { + match message { + UIMessage::UpdateStatus(update) => match *selection { + VIEW_BASIC_STATUS => { + status::TUIStatusView::update(&mut self.cursive, &update) + } + VIEW_MINING => mining::TUIMiningView::update(&mut self.cursive, &update), + VIEW_PEER_SYNC => peers::TUIPeerView::update(&mut self.cursive, &update), + _ => {} + }, } } } diff --git a/src/bin/tui/version.rs b/src/bin/tui/version.rs index 4116f4539..c6b2025f7 100644 --- a/src/bin/tui/version.rs +++ b/src/bin/tui/version.rs @@ -18,19 +18,16 @@ use cursive::direction::Orientation; use cursive::traits::Identifiable; use cursive::view::View; use cursive::views::{LinearLayout, ResizedView, TextView}; -use cursive::Cursive; use crate::tui::constants::VIEW_VERSION; -use crate::tui::types::TUIStatusListener; use crate::info_strings; -use crate::servers::ServerStats; pub struct TUIVersionView; -impl TUIStatusListener for TUIVersionView { +impl TUIVersionView { /// Create basic status view - fn create() -> Box { + pub fn create() -> Box { let (basic_info, detailed_info) = info_strings(); let basic_status_view = ResizedView::with_full_screen( LinearLayout::new(Orientation::Vertical) @@ -40,7 +37,4 @@ impl TUIStatusListener for TUIVersionView { ); Box::new(basic_status_view.with_name(VIEW_VERSION)) } - - /// update - fn update(_c: &mut Cursive, _stats: &ServerStats) {} }