mirror of
https://github.com/sharkdp/bat.git
synced 2025-02-16 09:50:06 +01:00
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 <CE.Mohammad.AlSaleh@gmail.com>
This commit is contained in:
parent
eca6b8a376
commit
69a4bedb55
@ -44,6 +44,7 @@
|
||||
- Use bat's ANSI iterator during tab expansion, see #2998 (@eth-p)
|
||||
- Support 'statically linked binary' for aarch64 in 'Release' page, see #2992 (@tzq0301)
|
||||
- Update options in shell completions and the man page of `bat`, see #2995 (@akinomyoga)
|
||||
- Significantly improve performance by using a buffered writer, see #3101 (@MoSal)
|
||||
|
||||
## Syntaxes
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::io::{self, BufRead, Write};
|
||||
use std::io::{self, BufRead, BufWriter, Write};
|
||||
|
||||
use crate::assets::HighlightingAssets;
|
||||
use crate::config::{Config, VisibleLines};
|
||||
@ -88,9 +88,12 @@ impl<'b> Controller<'b> {
|
||||
clircle::Identifier::stdout()
|
||||
};
|
||||
|
||||
const BUF_W_SZ: usize = 1 << 14;
|
||||
let mut writer = match output_buffer {
|
||||
Some(buf) => OutputHandle::FmtWrite(buf),
|
||||
None => OutputHandle::IoWrite(output_type.handle()?),
|
||||
None => {
|
||||
OutputHandle::IoWrite(BufWriter::with_capacity(BUF_W_SZ, output_type.handle()?))
|
||||
}
|
||||
};
|
||||
let mut no_errors: bool = true;
|
||||
let stderr = io::stderr();
|
||||
@ -124,10 +127,10 @@ impl<'b> Controller<'b> {
|
||||
Ok(no_errors)
|
||||
}
|
||||
|
||||
fn print_input<R: BufRead>(
|
||||
fn print_input<R: BufRead, W: io::Write>(
|
||||
&self,
|
||||
input: Input,
|
||||
writer: &mut OutputHandle,
|
||||
writer: &mut OutputHandle<W>,
|
||||
stdin: R,
|
||||
stdout_identifier: Option<&Identifier>,
|
||||
is_first: bool,
|
||||
@ -174,7 +177,7 @@ impl<'b> Controller<'b> {
|
||||
None
|
||||
};
|
||||
|
||||
let mut printer: Box<dyn Printer> = if self.config.loop_through {
|
||||
let mut printer: Box<dyn Printer<_>> = if self.config.loop_through {
|
||||
Box::new(SimplePrinter::new(self.config))
|
||||
} else {
|
||||
Box::new(InteractivePrinter::new(
|
||||
@ -196,10 +199,10 @@ impl<'b> Controller<'b> {
|
||||
)
|
||||
}
|
||||
|
||||
fn print_file(
|
||||
fn print_file<W: io::Write>(
|
||||
&self,
|
||||
printer: &mut dyn Printer,
|
||||
writer: &mut OutputHandle,
|
||||
printer: &mut dyn Printer<W>,
|
||||
writer: &mut OutputHandle<W>,
|
||||
input: &mut OpenedInput,
|
||||
add_header_padding: bool,
|
||||
#[cfg(feature = "git")] line_changes: &Option<LineChanges>,
|
||||
@ -234,10 +237,10 @@ impl<'b> Controller<'b> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_file_ranges(
|
||||
fn print_file_ranges<W: io::Write>(
|
||||
&self,
|
||||
printer: &mut dyn Printer,
|
||||
writer: &mut OutputHandle,
|
||||
printer: &mut dyn Printer<W>,
|
||||
writer: &mut OutputHandle<W>,
|
||||
reader: &mut InputReader,
|
||||
line_ranges: &LineRanges,
|
||||
) -> Result<()> {
|
||||
@ -279,6 +282,7 @@ impl<'b> Controller<'b> {
|
||||
line_number += 1;
|
||||
line_buffer.clear();
|
||||
}
|
||||
writer.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::{self, BufWriter, Write};
|
||||
use std::vec::Vec;
|
||||
|
||||
use nu_ansi_term::Color::{Fixed, Green, Red, Yellow};
|
||||
@ -67,35 +67,42 @@ const EMPTY_SYNTECT_STYLE: syntect::highlighting::Style = syntect::highlighting:
|
||||
font_style: FontStyle::empty(),
|
||||
};
|
||||
|
||||
pub enum OutputHandle<'a> {
|
||||
IoWrite(&'a mut dyn io::Write),
|
||||
pub enum OutputHandle<'a, W: io::Write> {
|
||||
IoWrite(BufWriter<W>),
|
||||
FmtWrite(&'a mut dyn fmt::Write),
|
||||
}
|
||||
|
||||
impl<'a> OutputHandle<'a> {
|
||||
impl<'a, W: io::Write> OutputHandle<'a, W> {
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
|
||||
match self {
|
||||
Self::IoWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
Self::FmtWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn flush(&mut self) -> Result<()> {
|
||||
match self {
|
||||
Self::IoWrite(handle) => handle.flush().map_err(Into::into),
|
||||
Self::FmtWrite(_handle) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Printer {
|
||||
pub(crate) trait Printer<W: io::Write> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
input: &OpenedInput,
|
||||
add_header_padding: bool,
|
||||
) -> Result<()>;
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle, input: &OpenedInput) -> Result<()>;
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle<W>, input: &OpenedInput) -> Result<()>;
|
||||
|
||||
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()>;
|
||||
fn print_snip(&mut self, handle: &mut OutputHandle<W>) -> Result<()>;
|
||||
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()>;
|
||||
@ -115,28 +122,28 @@ impl<'a> SimplePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Printer for SimplePrinter<'a> {
|
||||
impl<'a, W: io::Write> Printer<W> for SimplePrinter<'a> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
_handle: &mut OutputHandle,
|
||||
_handle: &mut OutputHandle<W>,
|
||||
_input: &OpenedInput,
|
||||
_add_header_padding: bool,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_footer(&mut self, _handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
|
||||
fn print_footer(&mut self, _handle: &mut OutputHandle<W>, _input: &OpenedInput) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_snip(&mut self, _handle: &mut OutputHandle) -> Result<()> {
|
||||
fn print_snip(&mut self, _handle: &mut OutputHandle<W>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
_line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()> {
|
||||
@ -321,9 +328,9 @@ impl<'a> InteractivePrinter<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn print_horizontal_line_term(
|
||||
fn print_horizontal_line_term<W: io::Write>(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
style: Style,
|
||||
) -> Result<()> {
|
||||
writeln!(
|
||||
@ -334,7 +341,11 @@ impl<'a> InteractivePrinter<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_horizontal_line(&mut self, handle: &mut OutputHandle, grid_char: char) -> Result<()> {
|
||||
fn print_horizontal_line<W: io::Write>(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle<W>,
|
||||
grid_char: char,
|
||||
) -> Result<()> {
|
||||
if self.panel_width == 0 {
|
||||
self.print_horizontal_line_term(handle, self.colors.grid)?;
|
||||
} else {
|
||||
@ -372,7 +383,10 @@ impl<'a> InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_header_component_indent(&mut self, handle: &mut OutputHandle) -> Result<()> {
|
||||
fn print_header_component_indent<W: io::Write>(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle<W>,
|
||||
) -> Result<()> {
|
||||
if self.config.style_components.grid() {
|
||||
write!(
|
||||
handle,
|
||||
@ -387,18 +401,18 @@ impl<'a> InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_header_component_with_indent(
|
||||
fn print_header_component_with_indent<W: io::Write>(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
content: &str,
|
||||
) -> Result<()> {
|
||||
self.print_header_component_indent(handle)?;
|
||||
writeln!(handle, "{content}")
|
||||
}
|
||||
|
||||
fn print_header_multiline_component(
|
||||
fn print_header_multiline_component<W: io::Write>(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
content: &str,
|
||||
) -> Result<()> {
|
||||
let mut content = content;
|
||||
@ -446,10 +460,10 @@ impl<'a> InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Printer for InteractivePrinter<'a> {
|
||||
impl<'a, W: io::Write> Printer<W> for InteractivePrinter<'a> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
input: &OpenedInput,
|
||||
add_header_padding: bool,
|
||||
) -> Result<()> {
|
||||
@ -549,7 +563,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle<W>, _input: &OpenedInput) -> Result<()> {
|
||||
if self.config.style_components.grid()
|
||||
&& (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable)
|
||||
{
|
||||
@ -559,7 +573,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()> {
|
||||
fn print_snip(&mut self, handle: &mut OutputHandle<W>) -> Result<()> {
|
||||
let panel = self.create_fake_panel(" ...");
|
||||
let panel_count = panel.chars().count();
|
||||
|
||||
@ -586,7 +600,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut OutputHandle,
|
||||
handle: &mut OutputHandle<W>,
|
||||
line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()> {
|
||||
|
Loading…
Reference in New Issue
Block a user