Git development
 help / color / mirror / Atom feed
From: Collin Funk <collin.funk1@gmail.com>
To: Kristofer Karlsson <krka@spotify.com>
Cc: Johannes Sixt <j6t@kdbg.org>,  Patrick Steinhardt <ps@pks.im>,
	git@vger.kernel.org,
	 Kristofer Karlsson via GitGitGadget <gitgitgadget@gmail.com>
Subject: Re: [PATCH 2/3] t: add "test-tool genbytes" to avoid slow tr(1) on macOS
Date: Mon, 09 Nov 2026 22:00:53 -0800	[thread overview]
Message-ID: <8733t9z0mi.fsf@gmail.com> (raw)
In-Reply-To: <CAL71e4NFyAShDZPW9JRB7Bpg3aLY5mY4wdn5m_ZYoLQjHZw_jA@mail.gmail.com>

Kristofer Karlsson <krka@spotify.com> writes:

> Nice trick, and it would work for t4205, which does not care about
> the byte value.  I tried it for the 2147483649 bytes there on Linux:
>
>   printf           time   peak memory
>   dash             6.5s   2.1GB
>   bash             6.0s   3MB
>   coreutils        3.7s   2.1GB
>
> It is definitely fast enough (on the variants I tested).
> The annoying thing (but not a real blocker) is the extra memory
> usage required and I am not sure I fully trust that all
> implementations will behave the same for absurdly large padding.
>
> (Particularly for paddings larger than 2^31, as you noted too.)
>
> It feels a bit like a hack, and tweaking the existing test-tool
> feels like a more sane option that is easier to reason about.
>
> A gotcha here is that the printf hack only works for producing
> "0", so for the cases we truly need NUL characters it does not
> help us, and I think that is also a point in favor of
> simply generalizing test-tool genzeros instead.

I've mentioned this idea on coreutils or gnulib's mailing lists before,
but I forget where and when. I've wanted to create a printf variant that
doesn't allocate much memory and will just use putc_unlocked for each
padding character, which would avoid the memory issue you bring up.

Most platforms will be limited to INT_MAX there, since that is what
POSIX specifies is supplied with '*' [1]:

    A field width, or precision, or both, may be indicated by an
    <asterisk> ('*'). In this case an argument of type int supplies the
    field width or precision.

E.g., in an invocation like this where the field width is supplied with
another argument:

    $ printf '%0*d\n' 5 1
    00001

I think my original reason for wanting a different printf variant was
escaping that limit.

For generating bytes where the values don't matter, in GNU coreutils we
frequently use 'yes' for that. As a result, the implementation is very
overengineered. E.g., it will use zero-copy since coreutils-9.11. Before
that, it would reuse ARGV if it was contiguous and the arguments used to
determine the printed string were long enough such that we weren't calling
read/write on a tiny string, or it would generate a large buffer before
using read and write. Here is the performance from before and after
zero-copy was introduced on a beefy Power10 machine, stolen from the
commit message [2]:

   IBM,9043-MRX $ taskset 1 yes | taskset 2 pv > /dev/null
   ... [11.6GiB/s]
   IBM,9043-MRX $ taskset 1 src/yes | taskset 2 pv > /dev/null
   ... [175GiB/s]

This was introduced around the time of the copy-fail vulnerability and
various zero-copy vulnerabilities, where there was serious consideration
given to nerfing splice and vmsplice. Luckily for us, that never
happened.

FreeBSD, and therefore, I assume, macOS use something similar to our
previous read/write method, which is fast enough. I think OpenBSD and
NetBSD use puts on ARGV or the "y" string, so it's relatively slow.

GNU 'tr' doesn't handle multi-byte characters, so you can adjust that
output if needed and remain relatively quick:

    $ timeout 10 yes 0 | LC_ALL=C tr -d '\n' | pv -r > /dev/null
    [ 616MiB/s]

I'm not sure if macOS 'tr' handles multibyte characters. But it might be
worth checking if they do, and if they keep a fast case for single-byte
locales. Doing that without duplicating code is quite tricky, which is
part of the reason why we haven't done it in GNU 'tr' yet (but recent
releases have improved multi-byte character support for other utilities,
so hopefully it is handled soon).

Probably more information than you need, but hopefully it helps you
generate slop sometimes needed for testing. :)

Collin

[1] https://pubs.opengroup.org/onlinepubs/9799919799/functions/printf.html
[2] https://github.com/coreutils/coreutils/commit/2b1c059e6a06eebbb721d010b1221ec54200cc33

  parent reply	other threads:[~2026-11-10  6:08 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-07 14:59 [PATCH 0/3] t: add "test-tool genbytes" to avoid slow tr(1) on macOS Kristofer Karlsson via GitGitGadget
2026-11-07 14:59 ` [PATCH 1/3] t/helper: rename test-genzeros.c to test-genbytes.c Kristofer Karlsson via GitGitGadget
2026-11-07 23:15   ` Junio C Hamano
2026-11-08  4:44     ` Junio C Hamano
2026-11-08  9:10       ` Kristofer Karlsson
2026-11-08 18:35         ` Junio C Hamano
2026-11-08 19:10           ` Kristofer Karlsson
2026-11-07 14:59 ` [PATCH 2/3] t: add "test-tool genbytes" to avoid slow tr(1) on macOS Kristofer Karlsson via GitGitGadget
2026-11-08  8:54   ` Johannes Sixt
2026-11-08  9:18     ` Kristofer Karlsson
2026-11-08  9:35       ` Johannes Sixt
2026-11-08 12:24         ` Kristofer Karlsson
2026-11-08 16:34           ` Johannes Sixt
2026-11-09  9:33             ` Johannes Sixt
2026-11-09 13:05               ` Kristofer Karlsson
2026-11-09 15:38                 ` Johannes Sixt
2026-11-10  6:00       ` Collin Funk [this message]
2026-11-10  8:09         ` Kristofer Karlsson
2026-11-08 18:37     ` Junio C Hamano
2026-11-07 14:59 ` [PATCH 3/3] t: replace "test-tool genzeros" with "genbytes NUL" Kristofer Karlsson via GitGitGadget
2026-11-07 23:04 ` [PATCH 0/3] t: add "test-tool genbytes" to avoid slow tr(1) on macOS Junio C Hamano
2026-11-08  9:11   ` Kristofer Karlsson
2026-11-07 23:23 ` Junio C Hamano
2026-11-08  9:13   ` Kristofer Karlsson
2026-11-08 19:15 ` [PATCH v2 0/2] " Kristofer Karlsson via GitGitGadget
2026-11-08 19:15   ` [PATCH v2 1/2] " Kristofer Karlsson via GitGitGadget
2026-11-09  1:39     ` Junio C Hamano
2026-11-09  7:10       ` Kristofer Karlsson
2026-11-09 15:41         ` Junio C Hamano
2026-11-09  6:59     ` Patrick Steinhardt
2026-11-09  7:43       ` Kristofer Karlsson
2026-11-08 19:15   ` [PATCH v2 2/2] t: replace "test-tool genzeros" with "genbytes 00" Kristofer Karlsson via GitGitGadget
2026-11-10 18:26 ` [PATCH v3] t: add "test-tool genbytes" to avoid slow tr(1) on macOS Kristofer Karlsson via GitGitGadget
2026-11-10 19:31   ` Junio C Hamano
2026-11-11 10:54   ` Patrick Steinhardt
2026-11-11 15:38   ` Junio C Hamano
2026-11-11 15:47     ` Kristofer Karlsson
2026-11-11 17:57       ` Junio C Hamano
2026-11-11 15:59 ` [PATCH v4] " Kristofer Karlsson via GitGitGadget

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8733t9z0mi.fsf@gmail.com \
    --to=collin.funk1@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=j6t@kdbg.org \
    --cc=krka@spotify.com \
    --cc=ps@pks.im \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox