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;
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"));
Box::new(logs_view.with_name(VIEW_LOGS))
logs_view.with_name(VIEW_LOGS)
}
pub fn update(c: &mut Cursive, entry: LogEntry) {

View file

@ -29,7 +29,7 @@ use crate::tui::constants::{
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);
main_menu
.get_mut()
@ -83,5 +83,5 @@ pub fn create() -> Box<dyn View> {
.child(TextView::new("Enter : Select"))
.child(TextView::new("Esc : Back "))
.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
pub struct TUIMiningView;
impl TUIStatusListener for TUIMiningView {
impl TUIMiningView {
/// 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 _ = 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| {

View file

@ -121,8 +121,8 @@ impl TableViewItem<PeerColumn> for PeerStats {
pub struct TUIPeerView;
impl TUIStatusListener for TUIPeerView {
fn create() -> Box<dyn View> {
impl TUIPeerView {
pub fn create() -> impl View {
let table_view = TableView::<PeerStats, PeerColumn>::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

View file

@ -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)
}
SyncStatus::Shutdown => "Shutting down, closing connections".to_string(),
Cow::Owned(format!("Sync step 7/7: Downloading blocks: {}%", percent))
}
SyncStatus::Shutdown => Cow::Borrowed("Shutting down, closing connections"),
}
}
impl TUIStatusListener for TUIStatusView {
/// Create basic status view
fn create() -> Box<dyn View> {
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);

View file

@ -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<dyn View>;
/// Update according to status update contents
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::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() {
let menu: ViewRef<SelectView<&str>> = self.cursive.find_name(MAIN_MENU).unwrap();
if let Some(selection) = menu.selection() {
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);
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),
_ => {}
},
}
}
}

View file

@ -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<dyn View> {
pub fn create() -> Box<dyn View> {
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) {}
}