Beating gnu yes in throughput


Date: 20.04.2021

I just stumbled upon this article:

How is GNU `yes` so fast?

And it tells me that doing less syscalls improves throughput and the naive implementation is just not good.

As i was wondering how well Zig compares to the GNU yes, i just hacked something together:
const std = @import("std");

pub fn main() anyerror!void {
    const pattern = "y\n" ** 8192;
    var out = std.io.getStdOut();
    while (true) {
        out.writeAll(pattern) catch |err| switch (err) {
            error.NoSpaceLeft => break,
            else => |e| return e,
        };
    }
}

Building that with ReleaseFast gave me this small (and pretty senseless) benchmark:
[felix@denkplatte-v2 quickyes]$ ./zig-yes | pv > /dev/null 
24,6GiB 0:00:10 [2,41GiB/s]

[felix@denkplatte-v2 quickyes]$ yes | pv > /dev/null
22,7GiB 0:00:10 [2,26GiB/s]

When increasing the buffer size, the transfer speed goes up as well, but there's a sweet-spot for normal write() syscalls. Using writev, aio or io_uring should yield even better transfer rates.

So the sentence
> We didn't beat GNU's yes, and there probably is no way.
can be proven wrong by telling them: Use a pretty naive zig implementation!

But to be fair: These aren't relevant numbers, nobody needs to type `y` that quickly, so don't take this blog post too serious, yeah?