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<dyn View>
* Update only the current view
* Simplify Listener trait
This commit is contained in:
hashmap 2020-05-29 10:55:07 +02:00 committed by GitHub
parent a8b8dc3a7f
commit 731528c616
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 52 deletions

View file

@ -28,9 +28,9 @@ use std::collections::VecDeque;
pub struct TUILogsView; pub struct TUILogsView;
impl TUILogsView { impl TUILogsView {
pub fn create() -> Box<dyn View> { pub fn create() -> impl View {
let logs_view = ResizedView::with_full_screen(LogBufferView::new(200).with_name("logs")); 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) { pub fn update(c: &mut Cursive, entry: LogEntry) {

View file

@ -29,7 +29,7 @@ use crate::tui::constants::{
VIEW_PEER_SYNC, VIEW_VERSION, VIEW_PEER_SYNC, VIEW_VERSION,
}; };
pub fn create() -> Box<dyn View> { pub fn create() -> impl View {
let mut main_menu = SelectView::new().h_align(HAlign::Left).with_name(MAIN_MENU); let mut main_menu = SelectView::new().h_align(HAlign::Left).with_name(MAIN_MENU);
main_menu main_menu
.get_mut() .get_mut()
@ -83,5 +83,5 @@ pub fn create() -> Box<dyn View> {
.child(TextView::new("Enter : Select")) .child(TextView::new("Enter : Select"))
.child(TextView::new("Esc : Back ")) .child(TextView::new("Esc : Back "))
.child(TextView::new("Q : Quit ")); .child(TextView::new("Q : Quit "));
Box::new(main_menu) main_menu
} }

View file

@ -165,9 +165,9 @@ impl TableViewItem<DiffColumn> for DiffBlock {
/// Mining status view /// Mining status view
pub struct TUIMiningView; pub struct TUIMiningView;
impl TUIStatusListener for TUIMiningView { impl TUIMiningView {
/// Create the mining view /// Create the mining view
fn create() -> Box<dyn View> { pub fn create() -> impl View {
let devices_button = Button::new_raw("Mining Server Status", |s| { let devices_button = Button::new_raw("Mining Server Status", |s| {
let _ = s.call_on_name("mining_stack_view", |sv: &mut StackView| { let _ = s.call_on_name("mining_stack_view", |sv: &mut StackView| {
let pos = sv.find_layer_from_name("mining_device_view").unwrap(); 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); 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 /// update
fn update(c: &mut Cursive, stats: &ServerStats) { fn update(c: &mut Cursive, stats: &ServerStats) {
c.call_on_name("diff_cur_height", |t: &mut TextView| { c.call_on_name("diff_cur_height", |t: &mut TextView| {

View file

@ -121,8 +121,8 @@ impl TableViewItem<PeerColumn> for PeerStats {
pub struct TUIPeerView; pub struct TUIPeerView;
impl TUIStatusListener for TUIPeerView { impl TUIPeerView {
fn create() -> Box<dyn View> { pub fn create() -> impl View {
let table_view = TableView::<PeerStats, PeerColumn>::new() let table_view = TableView::<PeerStats, PeerColumn>::new()
.column(PeerColumn::Address, "Address", |c| c.width_percent(16)) .column(PeerColumn::Address, "Address", |c| c.width_percent(16))
.column(PeerColumn::State, "State", |c| c.width_percent(8)) .column(PeerColumn::State, "State", |c| c.width_percent(8))
@ -159,9 +159,11 @@ impl TUIStatusListener for TUIPeerView {
let _ = c.focus_name(MAIN_MENU); 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) { fn update(c: &mut Cursive, stats: &ServerStats) {
let lp = stats let lp = stats
.peer_stats .peer_stats

View file

@ -20,6 +20,7 @@ use cursive::traits::Identifiable;
use cursive::view::View; use cursive::view::View;
use cursive::views::{LinearLayout, ResizedView, TextView}; use cursive::views::{LinearLayout, ResizedView, TextView};
use cursive::Cursive; use cursive::Cursive;
use std::borrow::Cow;
use crate::tui::constants::VIEW_BASIC_STATUS; use crate::tui::constants::VIEW_BASIC_STATUS;
use crate::tui::types::TUIStatusListener; use crate::tui::types::TUIStatusListener;
@ -32,11 +33,11 @@ const NANO_TO_MILLIS: f64 = 1.0 / 1_000_000.0;
pub struct TUIStatusView; pub struct TUIStatusView;
impl 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 { match sync_status {
SyncStatus::Initial => "Initializing".to_string(), SyncStatus::Initial => Cow::Borrowed("Initializing"),
SyncStatus::NoSync => "Running".to_string(), SyncStatus::NoSync => Cow::Borrowed("Running"),
SyncStatus::AwaitingPeers(_) => "Waiting for peers".to_string(), SyncStatus::AwaitingPeers(_) => Cow::Borrowed("Waiting for peers"),
SyncStatus::HeaderSync { SyncStatus::HeaderSync {
current_height, current_height,
highest_height, highest_height,
@ -46,7 +47,7 @@ impl TUIStatusView {
} else { } else {
current_height * 100 / highest_height 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) => { SyncStatus::TxHashsetDownload(stat) => {
if stat.total_size > 0 { if stat.total_size > 0 {
@ -55,23 +56,23 @@ impl TUIStatusView {
let fin = Utc::now().timestamp_nanos(); let fin = Utc::now().timestamp_nanos();
let dur_ms = (fin - start) as f64 * NANO_TO_MILLIS; 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, stat.total_size / 1_000_000,
percent, percent,
if dur_ms > 1.0f64 { stat.downloaded_size.saturating_sub(stat.prev_downloaded_size) as f64 / dur_ms as f64 } else { 0f64 }, if dur_ms > 1.0f64 { stat.downloaded_size.saturating_sub(stat.prev_downloaded_size) as f64 / dur_ms as f64 } else { 0f64 },
) ))
} else { } else {
let start = stat.start_time.timestamp_millis(); let start = stat.start_time.timestamp_millis();
let fin = Utc::now().timestamp_millis(); let fin = Utc::now().timestamp_millis();
let dur_secs = (fin - start) / 1000; 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, dur_secs,
) ))
} }
} }
SyncStatus::TxHashsetSetup => { 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 { SyncStatus::TxHashsetRangeProofsValidation {
rproofs, rproofs,
@ -82,10 +83,10 @@ impl TUIStatusView {
} else { } else {
0 0
}; };
format!( Cow::Owned(format!(
"Sync step 4/7: Validating chain state - range proofs: {}%", "Sync step 4/7: Validating chain state - range proofs: {}%",
r_percent r_percent
) ))
} }
SyncStatus::TxHashsetKernelsValidation { SyncStatus::TxHashsetKernelsValidation {
kernels, kernels,
@ -96,16 +97,16 @@ impl TUIStatusView {
} else { } else {
0 0
}; };
format!( Cow::Owned(format!(
"Sync step 5/7: Validating chain state - kernels: {}%", "Sync step 5/7: Validating chain state - kernels: {}%",
k_percent k_percent
) ))
} }
SyncStatus::TxHashsetSave => { 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 => { 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 { SyncStatus::BodySync {
current_height, current_height,
@ -116,16 +117,14 @@ impl TUIStatusView {
} else { } else {
current_height * 100 / highest_height 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 /// Create basic status view
fn create() -> Box<dyn View> { pub fn create() -> impl View {
let basic_status_view = ResizedView::with_full_screen( let basic_status_view = ResizedView::with_full_screen(
LinearLayout::new(Orientation::Vertical) LinearLayout::new(Orientation::Vertical)
.child( .child(
@ -232,9 +231,11 @@ impl TUIStatusListener for TUIStatusView {
.child(TextView::new(" ").with_name("basic_network_info")), .child(TextView::new(" ").with_name("basic_network_info")),
), //.child(logo_view) ), //.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) { fn update(c: &mut Cursive, stats: &ServerStats) {
let basic_status = TUIStatusView::update_sync_status(stats.sync_status); let basic_status = TUIStatusView::update_sync_status(stats.sync_status);

View file

@ -15,7 +15,6 @@
//! Types specific to the UI module //! Types specific to the UI module
use crate::servers::ServerStats; use crate::servers::ServerStats;
use cursive::view::View;
use cursive::Cursive; use cursive::Cursive;
/// Main message struct to communicate between the UI and /// Main message struct to communicate between the UI and
@ -28,8 +27,6 @@ pub enum UIMessage {
/// and updates itself /// and updates itself
pub trait TUIStatusListener { pub trait TUIStatusListener {
/// create the view, to return to the main UI controller
fn create() -> Box<dyn View>;
/// Update according to status update contents /// Update according to status update contents
fn update(c: &mut Cursive, stats: &ServerStats); fn update(c: &mut Cursive, stats: &ServerStats);
} }

View file

@ -26,14 +26,17 @@ use cursive::theme::{BaseColor, BorderStyle, Color, Theme};
use cursive::traits::Boxable; use cursive::traits::Boxable;
use cursive::traits::Identifiable; use cursive::traits::Identifiable;
use cursive::utils::markup::StyledString; 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 cursive::Cursive;
use std::sync::mpsc; use std::sync::mpsc;
use std::{thread, time}; use std::{thread, time};
use super::constants::MAIN_MENU;
use crate::built_info; use crate::built_info;
use crate::servers::Server; 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::types::{TUIStatusListener, UIMessage};
use crate::tui::{logs, menu, mining, peers, status, version}; use crate::tui::{logs, menu, mining, peers, status, version};
use grin_util::logger::LogEntry; use grin_util::logger::LogEntry;
@ -106,7 +109,7 @@ impl UI {
.child(Panel::new(TextView::new(title_string).full_width())) .child(Panel::new(TextView::new(title_string).full_width()))
.child( .child(
LinearLayout::new(Orientation::Horizontal) LinearLayout::new(Orientation::Horizontal)
.child(Panel::new(BoxedView::new(main_menu))) .child(Panel::new(main_menu))
.child(Panel::new(root_stack)), .child(Panel::new(root_stack)),
); );
@ -144,12 +147,17 @@ impl UI {
// Process any pending UI messages // Process any pending UI messages
while let Some(message) = self.ui_rx.try_iter().next() { while let Some(message) = self.ui_rx.try_iter().next() {
let menu: ViewRef<SelectView<&str>> = self.cursive.find_name(MAIN_MENU).unwrap();
if let Some(selection) = menu.selection() {
match message { match message {
UIMessage::UpdateStatus(update) => { UIMessage::UpdateStatus(update) => match *selection {
status::TUIStatusView::update(&mut self.cursive, &update); VIEW_BASIC_STATUS => {
mining::TUIMiningView::update(&mut self.cursive, &update); status::TUIStatusView::update(&mut self.cursive, &update)
peers::TUIPeerView::update(&mut self.cursive, &update); }
version::TUIVersionView::update(&mut self.cursive, &update); VIEW_MINING => mining::TUIMiningView::update(&mut self.cursive, &update),
VIEW_PEER_SYNC => peers::TUIPeerView::update(&mut self.cursive, &update),
_ => {}
},
} }
} }
} }

View file

@ -18,19 +18,16 @@ use cursive::direction::Orientation;
use cursive::traits::Identifiable; use cursive::traits::Identifiable;
use cursive::view::View; use cursive::view::View;
use cursive::views::{LinearLayout, ResizedView, TextView}; use cursive::views::{LinearLayout, ResizedView, TextView};
use cursive::Cursive;
use crate::tui::constants::VIEW_VERSION; use crate::tui::constants::VIEW_VERSION;
use crate::tui::types::TUIStatusListener;
use crate::info_strings; use crate::info_strings;
use crate::servers::ServerStats;
pub struct TUIVersionView; pub struct TUIVersionView;
impl TUIStatusListener for TUIVersionView { impl TUIVersionView {
/// Create basic status view /// Create basic status view
fn create() -> Box<dyn View> { pub fn create() -> Box<dyn View> {
let (basic_info, detailed_info) = info_strings(); let (basic_info, detailed_info) = info_strings();
let basic_status_view = ResizedView::with_full_screen( let basic_status_view = ResizedView::with_full_screen(
LinearLayout::new(Orientation::Vertical) LinearLayout::new(Orientation::Vertical)
@ -40,7 +37,4 @@ impl TUIStatusListener for TUIVersionView {
); );
Box::new(basic_status_view.with_name(VIEW_VERSION)) Box::new(basic_status_view.with_name(VIEW_VERSION))
} }
/// update
fn update(_c: &mut Cursive, _stats: &ServerStats) {}
} }