]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
factor: avoid interspersed lines for parallel runs
authorPádraig Brady <P@draigBrady.com>
Wed, 15 Oct 2014 01:18:35 +0000 (02:18 +0100)
committerPádraig Brady <P@draigBrady.com>
Wed, 24 Jun 2015 16:04:01 +0000 (17:04 +0100)
* 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.

NEWS
src/factor.c
tests/local.mk
tests/misc/factor-parallel.sh [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 99a930133ff276a811437c1855508e1a4b221a49..9aa35aded001ace5d6094ab68449ab45b8358a9a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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.
 
index f27bf22f250b9d87b9b1f40400b1caf0fd11311e..5b7ae22ab3c7b0b2a9cf86b46d401440454a663a 100644 (file)
@@ -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));
index d60f6cfecd08a0a6aaeacfdec4c0c2321e2ddc09..3cd8f92c672684cfa149f8228e52e5a1e7df68a4 100644 (file)
@@ -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 (executable)
index 0000000..8cec630
--- /dev/null
@@ -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