diff options
author | Giuseppe Scrivano <gscrivano@gnu.org> | 2015-03-10 12:25:48 +0000 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2015-03-10 12:30:33 +0000 |
commit | e2e11119e0ac653bd0bdab91c189b7803f8df1f0 (patch) | |
tree | 47b82ed120099802b15c5422849c35bcd13402ff | |
parent | 35217221c211f3116f374f305654462195aa634a (diff) | |
download | coreutils-e2e11119e0ac653bd0bdab91c189b7803f8df1f0.tar.xz |
yes: improve efficiency when all args aren't buffered
* src/yes.c (main): Even when the internal buffer isn't large enough,
output what we've buffered already, and interate over the rest.
This improves the performance in the edge case where there are
many small arguments that overflow the buffer.
* tests/misc/yes.sh: Add a test case for the many small arguments case.
-rw-r--r-- | src/yes.c | 26 | ||||
-rwxr-xr-x | tests/misc/yes.sh | 12 |
2 files changed, 26 insertions, 12 deletions
@@ -82,7 +82,7 @@ main (int argc, char **argv) } /* Buffer data locally once, rather than having the - large overhead of stdio buffering each item. */ + large overhead of stdio buffering each item. */ for (i = optind; i < argc; i++) { size_t len = strlen (argv[i]); @@ -92,9 +92,7 @@ main (int argc, char **argv) pbuf += len; *pbuf++ = i == argc - 1 ? '\n' : ' '; } - if (i < argc) - pbuf = NULL; - else + if (i == argc) { size_t line_len = pbuf - buf; size_t lines = BUFSIZ / line_len; @@ -106,7 +104,7 @@ main (int argc, char **argv) } /* The normal case is to continuously output the local buffer. */ - while (pbuf) + while (i == argc) { if (write (STDOUT_FILENO, buf, pbuf - buf) == -1) { @@ -115,13 +113,19 @@ main (int argc, char **argv) } } - /* If the data doesn't fit in BUFSIZ then it's large - and not too inefficient to output through stdio. */ - while (! pbuf) + /* If the data doesn't fit in BUFSIZ then output + what we've buffered, and iterate over the remaining items. */ + while (i != argc) { - for (i = optind; i < argc; i++) - if (fputs (argv[i], stdout) == EOF - || putchar (i == argc - 1 ? '\n' : ' ') == EOF) + int j; + if ((pbuf - buf) && fwrite (buf, pbuf - buf, 1, stdout) != 1) + { + error (0, errno, _("standard output")); + return EXIT_FAILURE; + } + for (j = i; j < argc; j++) + if (fputs (argv[j], stdout) == EOF + || putchar (j == argc - 1 ? '\n' : ' ') == EOF) { error (0, errno, _("standard output")); return EXIT_FAILURE; diff --git a/tests/misc/yes.sh b/tests/misc/yes.sh index 4ed300a4f..79f8b87c0 100755 --- a/tests/misc/yes.sh +++ b/tests/misc/yes.sh @@ -19,7 +19,7 @@ . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src print_ver_ yes -# Check various buffer sizes, with the most important +# Check various single item sizes, with the most important # size being BUFSIZ used for the local buffer to yes(1). # Note a \n is added, so actual sizes required internally # are 1 more than the size used here. @@ -29,4 +29,14 @@ for size in 1 1999 4095 4096 8191 8192 16383 16384; do compare out.1 out.2 || fail=1 done +# Check the many small items case, +# both fitting and overflowing the internal buffer +if env true $(seq 4000); then + for i in 100 4000; do + seq $i | paste -s -d ' ' | sed p > out.1 + yes $(seq $i) | head -n2 > out.2 + compare out.1 out.2 || fail=1 + done +fi + Exit $fail |