How is GNU `yes` so fast? (2017)
old.reddit.com
old.reddit.com
Someone else managed to double yes performance [2] via vmsplice.
[1] https://www.reddit.com/r/unix/comments/6gxduc/how_is_gnu_yes...
[2] https://www.reddit.com/r/unix/comments/6gxduc/how_is_gnu_yes...
Source for yes which does all the buffer malarkey: https://github.com/coreutils/coreutils/blob/master/src/yes.c
Source for the actual output: https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_pla...
https://web.archive.org/web/20200122231049/https://old.reddi...
https://www.gnu.org/prep/standards/html_node/Reading-Non_002...
This appears to be a case where they went for speed rather than simplicity.
In a million years it’d have spared… about a 386 worth of compute ;-)
I could use "cp /dev/urandom file" but then it's hard to tell if the filesystem or kernel optimize a copy different from generating your own writes.
Probably the more useful metric is total efficiency. How many interactions need to occur before the setup cost is made back up. And how many lines are read on average from yes?
I tested this by taking the freebsd (buffered) implementation, stripping all the iterations, and comparing it against a version which also strips all the buffering (so the latter would just `write(STDOUT_FILENO, "y\n", 2)`, and the former would first fill an 8k buffer then write that).
The unbuffered implementation has an edge of about 1%, for a variance of above 10%. The "shorter latency" is essentially nonexistent.
I always feel like it is the wrong way of doing it, but at the same time I just love the idea of a core utility that does nothing but spam yes.
On my computer reading from /dev/zero (16.5GiB/s) is still significantly faster than piping yes (7.11GiB/s), so I'd be interested in an exploration of why that is. BPF would probably be useful here. Maybe when I find a moment, I'll write a follow-up, doing just that... unless someone else does it faster. ;)
"How is GNU `yes` so fast?" https://news.ycombinator.com/item?id=14542938 (872 points | 5 years ago | 334 comments)
A lot of tools have their own command line flag to do this, e.g. apt-get has -y or --assume-yes
expect is basically the next step up from yes for this use.
I wouldn't be surprised if the BSD coreutils were more performant on older machines with small memory, buffers and prefetch queues (sometimes just a few bytes) than their GNU counterpart.
As to why they don't use similar techniques, probably because they historically didn't really care enough about the performances of yes(1) to bother with it.
FreeBSD has since added output buffering to yes(1), you can see the difference between openbsd yes(1)[0] which remains utterly naïve and freebsd yes(1)[1] which uses an 8k internal buffer.
[0]: https://github.com/openbsd/src/blob/master/usr.bin/yes/yes.c
[1]: https://svnweb.freebsd.org/base/head/usr.bin/yes/yes.c?view=...
But generally GNU tends to focus on performance and features while BSD focuses on simplicity. GNU having ridiculously complex code to do trivial things is kind of a meme.
And also, most people don't need a ridiculously fast "yes". Usually, when you want a fast stream of bytes, for example to fill up some space, /dev/zero is a better option.
One of the reasons is that GNU had to reimlmement UNIX tools as GPL code. How do you reimplement something trivial without it looking as the original to avoid copyright claims? One of the solutions is to implement it as complicated as possible.
Meanwhile, its BSD version essentially sums up to "return 1".
Same for much of the GNU code:
- separate the people from the problem
- focus on interests, not positions
- invent options for mutual gain
- insist on using objective criteria
I'd hire that engineer!But then again, maybe the purpose is to swamp the input, maybe for testing, so the more the better, so, you never know and it's wrong to decide what all users don't need.