1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

Merge pull request #7485 from drinkcat/seq-buffered

seq: Buffer writes to stdout
This commit is contained in:
Sylvestre Ledru 2025-03-19 11:18:07 +01:00 committed by GitHub
commit 09f4e60e93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 4 deletions

View file

@ -19,7 +19,38 @@ Finally, you can compare the performance of the two versions of `seq`
by running, for example, by running, for example,
```shell ```shell
hyperfine "seq 1000000" "target/release/seq 1000000" hyperfine -L seq seq,target/release/seq "{seq} 1000000"
``` ```
## Interesting test cases
Performance characteristics may vary a lot depending on the parameters,
and if custom formatting is required. In particular, it does appear
that the GNU implementation is heavily optimized for positive integer
outputs (which is probably the most common use case for `seq`).
Specifying a format or fixed width will slow down the
execution a lot (~15-20 times on GNU `seq`):
```shell
hyperfine -L seq seq,target/release/seq "{seq} -f%g 1000000"
hyperfine -L seq seq,target/release/seq "{seq} -w 1000000"
```
Floating point increments, or any negative bound, also degrades the
performance (~10-15 times on GNU `seq`):
```shell
hyperfine -L seq seq,./target/release/seq "{seq} 0 0.000001 1"
hyperfine -L seq seq,./target/release/seq "{seq} -100 1 1000000"
```
## Optimizations
### Buffering stdout
The original `uutils` implementation of `seq` did unbuffered writes
to stdout, causing a large number of system calls (and therefore a large amount
of system time). Simply wrapping `stdout` in a `BufWriter` increased performance
by about 2 times for a floating point increment test case, leading to similar
performance compared with GNU `seq`.
[0]: https://github.com/sharkdp/hyperfine [0]: https://github.com/sharkdp/hyperfine

View file

@ -4,7 +4,7 @@
// file that was distributed with this source code. // file that was distributed with this source code.
// spell-checker:ignore (ToDO) bigdecimal extendedbigdecimal numberparse hexadecimalfloat // spell-checker:ignore (ToDO) bigdecimal extendedbigdecimal numberparse hexadecimalfloat
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{stdout, ErrorKind, Write}; use std::io::{stdout, BufWriter, ErrorKind, Write};
use clap::{Arg, ArgAction, Command}; use clap::{Arg, ArgAction, Command};
use num_traits::{ToPrimitive, Zero}; use num_traits::{ToPrimitive, Zero};
@ -262,8 +262,8 @@ fn print_seq(
padding: usize, padding: usize,
format: Option<&Format<num_format::Float>>, format: Option<&Format<num_format::Float>>,
) -> std::io::Result<()> { ) -> std::io::Result<()> {
let stdout = stdout(); let stdout = stdout().lock();
let mut stdout = stdout.lock(); let mut stdout = BufWriter::new(stdout);
let (first, increment, last) = range; let (first, increment, last) = range;
let mut value = first; let mut value = first;
let padding = if pad { let padding = if pad {