Cache layout and performance fixes

pull/3/head
Florian Dehau 8 years ago
parent 07ff2b08eb
commit d7131ead11

@ -82,7 +82,7 @@ struct App {
progress: u16, progress: u16,
data: Vec<u64>, data: Vec<u64>,
data2: Vec<(f64, f64)>, data2: Vec<(f64, f64)>,
window: [f64; 2], data3: Vec<(f64, f64)>,
colors: [Color; 2], colors: [Color; 2],
color_index: usize, color_index: usize,
} }
@ -109,6 +109,7 @@ fn main() {
let mut rand_signal = RandomSignal::new(Range::new(0, 100)); let mut rand_signal = RandomSignal::new(Range::new(0, 100));
let mut sin_signal = SinSignal::new(4.0, 20.0); let mut sin_signal = SinSignal::new(4.0, 20.0);
let mut sin_signal2 = SinSignal::new(2.0, 10.0);
let mut app = App { let mut app = App {
name: String::from("Test app"), name: String::from("Test app"),
@ -119,7 +120,7 @@ fn main() {
progress: 0, progress: 0,
data: rand_signal.clone().take(100).collect(), data: rand_signal.clone().take(100).collect(),
data2: sin_signal.clone().take(100).collect(), data2: sin_signal.clone().take(100).collect(),
window: [0.0, 100.0], data3: sin_signal2.clone().take(100).collect(),
colors: [Color::Magenta, Color::Red], colors: [Color::Magenta, Color::Red],
color_index: 0, color_index: 0,
}; };
@ -141,7 +142,7 @@ fn main() {
let tx = tx.clone(); let tx = tx.clone();
loop { loop {
tx.send(Event::Tick).unwrap(); tx.send(Event::Tick).unwrap();
thread::sleep(time::Duration::from_millis(500)); thread::sleep(time::Duration::from_millis(1000));
} }
}); });
@ -184,8 +185,8 @@ fn main() {
app.data.pop(); app.data.pop();
app.data2.remove(0); app.data2.remove(0);
app.data2.push(sin_signal.next().unwrap()); app.data2.push(sin_signal.next().unwrap());
app.window[0] += 1.0; app.data3.remove(0);
app.window[1] += 1.0; app.data3.push(sin_signal2.next().unwrap());
app.selected += 1; app.selected += 1;
if app.selected >= app.items.len() { if app.selected >= app.items.len() {
app.selected = 0; app.selected = 0;
@ -206,14 +207,14 @@ fn draw(t: &mut Terminal, app: &App) {
.direction(Direction::Vertical) .direction(Direction::Vertical)
.alignment(Alignment::Left) .alignment(Alignment::Left)
.chunks(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)]) .chunks(&[Size::Fixed(7), Size::Min(5), Size::Fixed(3)])
.render(&Terminal::size().unwrap(), |chunks| { .render(t, &Terminal::size().unwrap(), |t, chunks| {
Block::default().borders(border::ALL).title("Graphs").render(&chunks[0], t); Block::default().borders(border::ALL).title("Graphs").render(&chunks[0], t);
Group::default() Group::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.alignment(Alignment::Left) .alignment(Alignment::Left)
.margin(1) .margin(1)
.chunks(&[Size::Fixed(2), Size::Fixed(3)]) .chunks(&[Size::Fixed(2), Size::Fixed(3)])
.render(&chunks[0], |chunks| { .render(t, &chunks[0], |t, chunks| {
Gauge::default() Gauge::default()
.block(Block::default().title("Gauge:")) .block(Block::default().title("Gauge:"))
.bg(Color::Yellow) .bg(Color::Yellow)
@ -234,7 +235,7 @@ fn draw(t: &mut Terminal, app: &App) {
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.alignment(Alignment::Left) .alignment(Alignment::Left)
.chunks(&sizes) .chunks(&sizes)
.render(&chunks[1], |chunks| { .render(t, &chunks[1], |t, chunks| {
List::default() List::default()
.block(Block::default().borders(border::ALL).title("List")) .block(Block::default().borders(border::ALL).title("List"))
.render(&chunks[0], t); .render(&chunks[0], t);
@ -243,9 +244,10 @@ fn draw(t: &mut Terminal, app: &App) {
.block(Block::default() .block(Block::default()
.borders(border::ALL) .borders(border::ALL)
.title("Chart")) .title("Chart"))
.x_axis(Axis::default().title("X").bounds(app.window)) .x_axis(Axis::default().title("X").bounds([0.0, 100.0]))
.y_axis(Axis::default().title("Y").bounds([0.0, 40.0])) .y_axis(Axis::default().title("Y").bounds([0.0, 40.0]))
.datasets(&[Dataset::default().color(Color::Cyan).data(&app.data2)]) .datasets(&[Dataset::default().color(Color::Cyan).data(&app.data2),
Dataset::default().color(Color::Yellow).data(&app.data3)])
.render(&chunks[1], t); .render(&chunks[1], t);
} }
}); });

@ -6,7 +6,10 @@ use cassowary::WeightedRelation::*;
use cassowary::strength::{WEAK, REQUIRED}; use cassowary::strength::{WEAK, REQUIRED};
use buffer::Buffer; use buffer::Buffer;
use terminal::Terminal;
use util::hash;
#[derive(Hash)]
pub enum Alignment { pub enum Alignment {
Top, Top,
Left, Left,
@ -15,12 +18,13 @@ pub enum Alignment {
Right, Right,
} }
#[derive(Hash)]
pub enum Direction { pub enum Direction {
Horizontal, Horizontal,
Vertical, Vertical,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct Rect { pub struct Rect {
pub x: u16, pub x: u16,
pub y: u16, pub y: u16,
@ -235,6 +239,7 @@ impl Element {
} }
} }
#[derive(Hash)]
pub struct Group { pub struct Group {
direction: Direction, direction: Direction,
alignment: Alignment, alignment: Alignment,
@ -273,14 +278,26 @@ impl Group {
self.chunks = Vec::from(chunks); self.chunks = Vec::from(chunks);
self self
} }
pub fn render<F>(&self, area: &Rect, mut f: F) pub fn render<F>(&self, t: &mut Terminal, area: &Rect, mut f: F)
where F: FnMut(&[Rect]) where F: FnMut(&mut Terminal, &[Rect])
{ {
let chunks = split(area, let hash = hash(self, area);
&self.direction, let (cache_update, chunks) = match t.get_layout(hash) {
&self.alignment, Some(chs) => (false, chs.to_vec()),
self.margin, None => {
&self.chunks); (true,
f(&chunks); split(area,
&self.direction,
&self.alignment,
self.margin,
&self.chunks))
}
};
f(t, &chunks);
if cache_update {
t.set_layout(hash, chunks);
}
} }
} }

@ -8,16 +8,19 @@ use termion::raw::{IntoRawMode, RawTerminal};
use buffer::Buffer; use buffer::Buffer;
use widgets::Widget; use widgets::Widget;
use layout::Rect; use layout::Rect;
use util::hash;
pub struct Terminal { pub struct Terminal {
stdout: RawTerminal<io::Stdout>, stdout: RawTerminal<io::Stdout>,
layout_cache: HashMap<u64, Vec<Rect>>,
} }
impl Terminal { impl Terminal {
pub fn new() -> Result<Terminal, io::Error> { pub fn new() -> Result<Terminal, io::Error> {
let stdout = try!(io::stdout().into_raw_mode()); let stdout = try!(io::stdout().into_raw_mode());
Ok(Terminal { stdout: stdout }) Ok(Terminal {
stdout: stdout,
layout_cache: HashMap::new(),
})
} }
pub fn size() -> Result<Rect, io::Error> { pub fn size() -> Result<Rect, io::Error> {
@ -30,20 +33,29 @@ impl Terminal {
}) })
} }
// FIXME: Clean cache to prevent memory leak
pub fn get_layout(&self, hash: u64) -> Option<&Vec<Rect>> {
self.layout_cache.get(&hash)
}
pub fn set_layout(&mut self, hash: u64, chunks: Vec<Rect>) {
self.layout_cache.insert(hash, chunks);
}
pub fn render_buffer(&mut self, buffer: Buffer) { pub fn render_buffer(&mut self, buffer: Buffer) {
let mut string = String::with_capacity(buffer.area().area() as usize);
for (i, cell) in buffer.content().iter().enumerate() { for (i, cell) in buffer.content().iter().enumerate() {
let (lx, ly) = buffer.pos_of(i).unwrap(); let (lx, ly) = buffer.pos_of(i).unwrap();
let (x, y) = (lx + buffer.area().x, ly + buffer.area().y); let (x, y) = (lx + buffer.area().x, ly + buffer.area().y);
if cell.symbol != "" { if cell.symbol != "" {
write!(self.stdout, string.push_str(&format!("{}{}{}{}",
"{}{}{}{}", termion::cursor::Goto(x + 1, y + 1),
termion::cursor::Goto(x + 1, y + 1), cell.fg.fg(),
cell.fg.fg(), cell.bg.bg(),
cell.bg.bg(), cell.symbol))
cell.symbol)
.unwrap();
} }
} }
write!(self.stdout, "{}", string);
self.stdout.flush().unwrap(); self.stdout.flush().unwrap();
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {

@ -3,9 +3,10 @@ use std::hash::{Hash, Hasher, BuildHasher};
use layout::Rect; use layout::Rect;
pub fn hash<T: Hash>(t: &T) -> u64 { pub fn hash<T: Hash>(t: &T, area: &Rect) -> u64 {
let state = RandomState::new(); let state = RandomState::new();
let mut hasher = state.build_hasher(); let mut hasher = state.build_hasher();
t.hash(&mut hasher); t.hash(&mut hasher);
area.hash(&mut hasher);
hasher.finish() hasher.finish()
} }

@ -138,7 +138,6 @@ impl<'a> Widget<'a> for Chart<'a> {
let margin_x = chart_area.x - area.x; let margin_x = chart_area.x - area.x;
let margin_y = chart_area.y - area.y; let margin_y = chart_area.y - area.y;
// info!("{:?}", self.datasets[0].data[0]);
for dataset in self.datasets { for dataset in self.datasets {
for &(x, y) in dataset.data.iter() { for &(x, y) in dataset.data.iter() {
@ -150,7 +149,6 @@ impl<'a> Widget<'a> for Chart<'a> {
(self.y_axis.bounds[1] - self.y_axis.bounds[0]); (self.y_axis.bounds[1] - self.y_axis.bounds[0]);
let dx = (self.x_axis.bounds[1] - x) * (chart_area.width - 1) as f64 / let dx = (self.x_axis.bounds[1] - x) * (chart_area.width - 1) as f64 /
(self.x_axis.bounds[1] - self.x_axis.bounds[0]); (self.x_axis.bounds[1] - self.x_axis.bounds[0]);
info!("{} {}", dx, dy);
buf.update_cell(dx as u16 + margin_x, dy as u16 + margin_y, |c| { buf.update_cell(dx as u16 + margin_x, dy as u16 + margin_y, |c| {
c.symbol = symbols::DOT; c.symbol = symbols::DOT;
c.fg = dataset.color; c.fg = dataset.color;

Loading…
Cancel
Save