Skip to content

Commit 73a2d58

Browse files
committed
Significantly improve performance by using a buffered writer
Before ``` Benchmark 1: seq 10000000 | bat Time (mean ± σ): 6.235 s ± 0.052 s [User: 3.664 s, System: 2.714 s] Range (min … max): 6.172 s … 6.355 s 10 runs ``` After ``` Benchmark 1: seq 10000000 | ./target/release/bat Time (mean ± σ): 215.9 ms ± 5.1 ms [User: 275.4 ms, System: 38.8 ms] Range (min … max): 210.3 ms … 224.9 ms 10 runs ``` Using `less` for comparison ``` Benchmark 1: seq 10000000 | less Time (mean ± σ): 637.3 ms ± 43.3 ms [User: 642.1 ms, System: 95.6 ms] Range (min … max): 584.5 ms … 700.1 ms 10 runs ``` And raw ``` Benchmark 1: seq 10000000 Time (mean ± σ): 63.1 ms ± 1.3 ms [User: 57.1 ms, System: 5.9 ms] Range (min … max): 62.1 ms … 66.0 ms 10 runs ``` Signed-off-by: Mohammad AlSaleh <[email protected]>
1 parent eca6b8a commit 73a2d58

File tree

2 files changed

+47
-38
lines changed

2 files changed

+47
-38
lines changed

src/controller.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::io::{self, BufRead, Write};
1+
use std::io::{self, BufRead, BufWriter, Write};
22

33
use crate::assets::HighlightingAssets;
44
use crate::config::{Config, VisibleLines};
@@ -88,9 +88,10 @@ impl<'b> Controller<'b> {
8888
clircle::Identifier::stdout()
8989
};
9090

91+
const BUF_W_SZ: usize = 1 << 14;
9192
let mut writer = match output_buffer {
9293
Some(buf) => OutputHandle::FmtWrite(buf),
93-
None => OutputHandle::IoWrite(output_type.handle()?),
94+
None => OutputHandle::IoWrite(BufWriter::with_capacity(BUF_W_SZ, output_type.handle()?)),
9495
};
9596
let mut no_errors: bool = true;
9697
let stderr = io::stderr();
@@ -124,10 +125,10 @@ impl<'b> Controller<'b> {
124125
Ok(no_errors)
125126
}
126127

127-
fn print_input<R: BufRead>(
128+
fn print_input<R: BufRead, W: io::Write>(
128129
&self,
129130
input: Input,
130-
writer: &mut OutputHandle,
131+
writer: &mut OutputHandle<W>,
131132
stdin: R,
132133
stdout_identifier: Option<&Identifier>,
133134
is_first: bool,
@@ -174,7 +175,7 @@ impl<'b> Controller<'b> {
174175
None
175176
};
176177

177-
let mut printer: Box<dyn Printer> = if self.config.loop_through {
178+
let mut printer: Box<dyn Printer<_>> = if self.config.loop_through {
178179
Box::new(SimplePrinter::new(self.config))
179180
} else {
180181
Box::new(InteractivePrinter::new(
@@ -196,10 +197,10 @@ impl<'b> Controller<'b> {
196197
)
197198
}
198199

199-
fn print_file(
200+
fn print_file<W: io::Write>(
200201
&self,
201-
printer: &mut dyn Printer,
202-
writer: &mut OutputHandle,
202+
printer: &mut dyn Printer<W>,
203+
writer: &mut OutputHandle<W>,
203204
input: &mut OpenedInput,
204205
add_header_padding: bool,
205206
#[cfg(feature = "git")] line_changes: &Option<LineChanges>,
@@ -234,10 +235,10 @@ impl<'b> Controller<'b> {
234235
Ok(())
235236
}
236237

237-
fn print_file_ranges(
238+
fn print_file_ranges<W: io::Write>(
238239
&self,
239-
printer: &mut dyn Printer,
240-
writer: &mut OutputHandle,
240+
printer: &mut dyn Printer<W>,
241+
writer: &mut OutputHandle<W>,
241242
reader: &mut InputReader,
242243
line_ranges: &LineRanges,
243244
) -> Result<()> {
@@ -279,6 +280,7 @@ impl<'b> Controller<'b> {
279280
line_number += 1;
280281
line_buffer.clear();
281282
}
283+
writer.flush()?;
282284
Ok(())
283285
}
284286
}

src/printer.rs

+34-27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::fmt;
2-
use std::io;
2+
use std::io::{self, BufWriter, Write};
33
use std::vec::Vec;
44

55
use nu_ansi_term::Color::{Fixed, Green, Red, Yellow};
@@ -67,35 +67,42 @@ const EMPTY_SYNTECT_STYLE: syntect::highlighting::Style = syntect::highlighting:
6767
font_style: FontStyle::empty(),
6868
};
6969

70-
pub enum OutputHandle<'a> {
71-
IoWrite(&'a mut dyn io::Write),
70+
pub enum OutputHandle<'a, W: io::Write> {
71+
IoWrite(BufWriter<W>),
7272
FmtWrite(&'a mut dyn fmt::Write),
7373
}
7474

75-
impl<'a> OutputHandle<'a> {
75+
impl<'a, W: io::Write> OutputHandle<'a, W> {
7676
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
7777
match self {
7878
Self::IoWrite(handle) => handle.write_fmt(args).map_err(Into::into),
7979
Self::FmtWrite(handle) => handle.write_fmt(args).map_err(Into::into),
8080
}
8181
}
82+
83+
pub(crate) fn flush(&mut self) -> Result<()> {
84+
match self {
85+
Self::IoWrite(handle) => handle.flush().map_err(Into::into),
86+
Self::FmtWrite(_handle) => Ok(()),
87+
}
88+
}
8289
}
8390

84-
pub(crate) trait Printer {
91+
pub(crate) trait Printer<W: io::Write> {
8592
fn print_header(
8693
&mut self,
87-
handle: &mut OutputHandle,
94+
handle: &mut OutputHandle<W>,
8895
input: &OpenedInput,
8996
add_header_padding: bool,
9097
) -> Result<()>;
91-
fn print_footer(&mut self, handle: &mut OutputHandle, input: &OpenedInput) -> Result<()>;
98+
fn print_footer(&mut self, handle: &mut OutputHandle<W>, input: &OpenedInput) -> Result<()>;
9299

93-
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()>;
100+
fn print_snip(&mut self, handle: &mut OutputHandle<W>) -> Result<()>;
94101

95102
fn print_line(
96103
&mut self,
97104
out_of_range: bool,
98-
handle: &mut OutputHandle,
105+
handle: &mut OutputHandle<W>,
99106
line_number: usize,
100107
line_buffer: &[u8],
101108
) -> Result<()>;
@@ -115,28 +122,28 @@ impl<'a> SimplePrinter<'a> {
115122
}
116123
}
117124

118-
impl<'a> Printer for SimplePrinter<'a> {
125+
impl<'a, W: io::Write> Printer<W> for SimplePrinter<'a> {
119126
fn print_header(
120127
&mut self,
121-
_handle: &mut OutputHandle,
128+
_handle: &mut OutputHandle<W>,
122129
_input: &OpenedInput,
123130
_add_header_padding: bool,
124131
) -> Result<()> {
125132
Ok(())
126133
}
127134

128-
fn print_footer(&mut self, _handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
135+
fn print_footer(&mut self, _handle: &mut OutputHandle<W>, _input: &OpenedInput) -> Result<()> {
129136
Ok(())
130137
}
131138

132-
fn print_snip(&mut self, _handle: &mut OutputHandle) -> Result<()> {
139+
fn print_snip(&mut self, _handle: &mut OutputHandle<W>) -> Result<()> {
133140
Ok(())
134141
}
135142

136143
fn print_line(
137144
&mut self,
138145
out_of_range: bool,
139-
handle: &mut OutputHandle,
146+
handle: &mut OutputHandle<W>,
140147
_line_number: usize,
141148
line_buffer: &[u8],
142149
) -> Result<()> {
@@ -321,9 +328,9 @@ impl<'a> InteractivePrinter<'a> {
321328
})
322329
}
323330

324-
fn print_horizontal_line_term(
331+
fn print_horizontal_line_term<W: io::Write>(
325332
&mut self,
326-
handle: &mut OutputHandle,
333+
handle: &mut OutputHandle<W>,
327334
style: Style,
328335
) -> Result<()> {
329336
writeln!(
@@ -334,7 +341,7 @@ impl<'a> InteractivePrinter<'a> {
334341
Ok(())
335342
}
336343

337-
fn print_horizontal_line(&mut self, handle: &mut OutputHandle, grid_char: char) -> Result<()> {
344+
fn print_horizontal_line<W: io::Write>(&mut self, handle: &mut OutputHandle<W>, grid_char: char) -> Result<()> {
338345
if self.panel_width == 0 {
339346
self.print_horizontal_line_term(handle, self.colors.grid)?;
340347
} else {
@@ -372,7 +379,7 @@ impl<'a> InteractivePrinter<'a> {
372379
}
373380
}
374381

375-
fn print_header_component_indent(&mut self, handle: &mut OutputHandle) -> Result<()> {
382+
fn print_header_component_indent<W: io::Write>(&mut self, handle: &mut OutputHandle<W>) -> Result<()> {
376383
if self.config.style_components.grid() {
377384
write!(
378385
handle,
@@ -387,18 +394,18 @@ impl<'a> InteractivePrinter<'a> {
387394
}
388395
}
389396

390-
fn print_header_component_with_indent(
397+
fn print_header_component_with_indent<W: io::Write>(
391398
&mut self,
392-
handle: &mut OutputHandle,
399+
handle: &mut OutputHandle<W>,
393400
content: &str,
394401
) -> Result<()> {
395402
self.print_header_component_indent(handle)?;
396403
writeln!(handle, "{content}")
397404
}
398405

399-
fn print_header_multiline_component(
406+
fn print_header_multiline_component<W: io::Write>(
400407
&mut self,
401-
handle: &mut OutputHandle,
408+
handle: &mut OutputHandle<W>,
402409
content: &str,
403410
) -> Result<()> {
404411
let mut content = content;
@@ -446,10 +453,10 @@ impl<'a> InteractivePrinter<'a> {
446453
}
447454
}
448455

449-
impl<'a> Printer for InteractivePrinter<'a> {
456+
impl<'a, W: io::Write> Printer<W> for InteractivePrinter<'a> {
450457
fn print_header(
451458
&mut self,
452-
handle: &mut OutputHandle,
459+
handle: &mut OutputHandle<W>,
453460
input: &OpenedInput,
454461
add_header_padding: bool,
455462
) -> Result<()> {
@@ -549,7 +556,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
549556
Ok(())
550557
}
551558

552-
fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
559+
fn print_footer(&mut self, handle: &mut OutputHandle<W>, _input: &OpenedInput) -> Result<()> {
553560
if self.config.style_components.grid()
554561
&& (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable)
555562
{
@@ -559,7 +566,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
559566
}
560567
}
561568

562-
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()> {
569+
fn print_snip(&mut self, handle: &mut OutputHandle<W>) -> Result<()> {
563570
let panel = self.create_fake_panel(" ...");
564571
let panel_count = panel.chars().count();
565572

@@ -586,7 +593,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
586593
fn print_line(
587594
&mut self,
588595
out_of_range: bool,
589-
handle: &mut OutputHandle,
596+
handle: &mut OutputHandle<W>,
590597
line_number: usize,
591598
line_buffer: &[u8],
592599
) -> Result<()> {

0 commit comments

Comments
 (0)