diff options
author | Pádraig Brady <P@draigBrady.com> | 2014-10-15 02:18:35 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2015-06-24 17:04:01 +0100 |
commit | 4d2d6c5b7c455392617609ae21b6b21879e12975 (patch) | |
tree | 61a3dc20fc98a7387703622e2ab986c946f7f079 | |
parent | 32c97093db85c827ccbbf4cd4255190718863232 (diff) | |
download | coreutils-4d2d6c5b7c455392617609ae21b6b21879e12975.tar.xz |
factor: avoid interspersed lines for parallel runs
* src/factor.c (n_out): A new global variable to track
how much data has been written to stdout.
(print_factors_single): Use n_out to determine whether
to flush the current (and previous) lines.
* tests/misc/factor-parallel.sh: Add a new test.
* tests/local.mk: Reference the new test.
* NEWS: Mention the bug fix.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/factor.c | 24 | ||||
-rw-r--r-- | tests/local.mk | 1 | ||||
-rwxr-xr-x | tests/misc/factor-parallel.sh | 34 |
4 files changed, 59 insertions, 3 deletions
@@ -24,6 +24,9 @@ GNU coreutils NEWS -*- outline -*- file types, a warning is issued for source directories with duplicate names, or with -H the directory is copied again using the symlink name. + factor avoids writing partial lines, thus supporting parallel operation. + [the bug dates back to the initial implementation] + head, od, split, tac, tail, and wc no longer mishandle input from files in /proc and /sys file systems that report somewhat-incorrect file sizes. diff --git a/src/factor.c b/src/factor.c index f27bf22f2..5b7ae22ab 100644 --- a/src/factor.c +++ b/src/factor.c @@ -2323,13 +2323,15 @@ strto2uintmax (uintmax_t *hip, uintmax_t *lop, const char *s) return err; } +static size_t n_out; /* How much data we've written to stdout. */ + static void print_uintmaxes (uintmax_t t1, uintmax_t t0) { uintmax_t q, r; if (t1 == 0) - printf ("%"PRIuMAX, t0); + n_out += printf ("%"PRIuMAX, t0); else { /* Use very plain code here since it seems hard to write fast code @@ -2338,7 +2340,7 @@ print_uintmaxes (uintmax_t t1, uintmax_t t0) r = t1 % 1000000000; udiv_qrnnd (t0, r, r, t0, 1000000000); print_uintmaxes (q, t0); - printf ("%09u", (unsigned int) r); + n_out += printf ("%09u", (unsigned int) r); } } @@ -2350,6 +2352,7 @@ print_factors_single (uintmax_t t1, uintmax_t t0) print_uintmaxes (t1, t0); putchar (':'); + n_out++; factor (t1, t0, &factors); @@ -2358,15 +2361,29 @@ print_factors_single (uintmax_t t1, uintmax_t t0) { char buf[INT_BUFSIZE_BOUND (uintmax_t)]; putchar (' '); - fputs (umaxtostr (factors.p[j], buf), stdout); + char *umaxstr = umaxtostr (factors.p[j], buf); + fputs (umaxstr, stdout); + n_out += strlen (umaxstr) + 1; } if (factors.plarge[1]) { putchar (' '); + n_out++; print_uintmaxes (factors.plarge[1], factors.plarge[0]); } putchar ('\n'); + n_out++; + + /* Assume the stdout buffer is > this value. + Flush here to avoid partial lines being output. + Flushing every line has too much overhead. + TODO: Buffer internally and avoid stdio. */ + if (n_out >= 512) + { + fflush (stdout); + n_out = 0; + } } /* Emit the factors of the indicated number. If we have the option of using @@ -2422,6 +2439,7 @@ print_factors (const char *input) mp_factor_clear (&factors); mpz_clear (t); putchar ('\n'); + fflush (stdout); return true; #else error (0, 0, _("%s is too large"), quote (input)); diff --git a/tests/local.mk b/tests/local.mk index d60f6cfec..3cd8f92c6 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -282,6 +282,7 @@ all_tests = \ tests/misc/expand.pl \ tests/misc/expr.pl \ tests/misc/factor.pl \ + tests/misc/factor-parallel.sh \ tests/misc/false-status.sh \ tests/misc/fold.pl \ tests/misc/groups-dash.sh \ diff --git a/tests/misc/factor-parallel.sh b/tests/misc/factor-parallel.sh new file mode 100755 index 000000000..8cec630ea --- /dev/null +++ b/tests/misc/factor-parallel.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Test for complete lines on output + +# Copyright (C) 2015 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ factor + + +odd() { LC_ALL=C sed '/[24680]$/d'; } +primes() { LC_ALL=C sed 's/.*: //; / /d'; } + +# Before v8.24 the number reported here would vary +# Note -u not supplied to split, increased batching of quickly processed items. +# As processing cost increases it becomes advantageous to use -u to keep +# the factor processes supplied with data. +nprimes=$(seq 1e6 | odd | split -nr/4 --filter='factor' | primes | wc -l) + +test "$nprimes" = '78498' || fail=1 + +Exit $fail |