The AOSP build doesn't use tr (or anything that's still in pending), but
the kernel folks have been more aggressive. They found that tr's
pathological flushing was adding minutes to their build times.

Just removing the fflush() made tr significantly faster for my trivial
test, but still slow, with all the time going into stdio. Rewriting the
loop to modify toybuf in place and then do one write per read made most
of the difference, but special-casing the "neither -d nor -s" case made
a measurable difference too on a Xeon.

Bug: http://b/174773617
---
 tests/tr.test     | 11 +++++++++++
 toys/pending/tr.c | 27 +++++++++++----------------
 2 files changed, 22 insertions(+), 16 deletions(-)
 create mode 100755 tests/tr.test
From 3e7287649da5b4c0f0721186d9346f2184172438 Mon Sep 17 00:00:00 2001
From: Elliott Hughes <[email protected]>
Date: Fri, 4 Dec 2020 10:06:49 -0800
Subject: [PATCH] tr: fix pathological flushing.

The AOSP build doesn't use tr (or anything that's still in pending), but
the kernel folks have been more aggressive. They found that tr's
pathological flushing was adding minutes to their build times.

Just removing the fflush() made tr significantly faster for my trivial
test, but still slow, with all the time going into stdio. Rewriting the
loop to modify toybuf in place and then do one write per read made most
of the difference, but special-casing the "neither -d nor -s" case made
a measurable difference too on a Xeon.

Bug: http://b/174773617
---
 tests/tr.test     | 11 +++++++++++
 toys/pending/tr.c | 27 +++++++++++----------------
 2 files changed, 22 insertions(+), 16 deletions(-)
 create mode 100755 tests/tr.test

diff --git a/tests/tr.test b/tests/tr.test
new file mode 100755
index 00000000..bb00a3ff
--- /dev/null
+++ b/tests/tr.test
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "" "tr 1 2" "223223223" "" "123123123"
+testing "-d" "tr -d 1" "232323" "" "123123123"
+testing "-s" "tr -s 1" "12223331222333" "" "111222333111222333"
+
+testing "no pathological flushing" "seq 10000000 | tr 1 2 > /dev/null" "" "" ""
diff --git a/toys/pending/tr.c b/toys/pending/tr.c
index 9a823f67..e68ae464 100644
--- a/toys/pending/tr.c
+++ b/toys/pending/tr.c
@@ -210,26 +210,21 @@ save:
 
 static void print_map(char *set1, char *set2)
 {
-  int r = 0, i, prev_char = -1;
+  int n, src, dst, prev = -1;
 
-  while (1)
-  {
-    i = 0;
-    r = read(STDIN_FILENO, (toybuf), sizeof(toybuf));
-    if (!r) break;
-    for (;r > i;i++) {
+  while ((n = read(0, toybuf, sizeof(toybuf)))) {
+    if (!FLAG(d) && !FLAG(s)) {
+      for (dst = 0; dst < n; dst++) toybuf[dst] = TT.map[toybuf[dst]];
+    } else {
+      for (src = dst = 0; src < n; src++) {
+        int ch = TT.map[toybuf[src]];
 
-      if ((toys.optflags & FLAG_d) && (TT.map[(int)toybuf[i]] & 0x100)) continue;
-      if (toys.optflags & FLAG_s) {
-        if ((TT.map[(int)toybuf[i]] & 0x200) &&
-            (prev_char == TT.map[(int)toybuf[i]])) {
-          continue;
-        }
+        if (FLAG(d) && (ch & 0x100)) continue;
+        if (FLAG(s) && ((ch & 0x200) && prev == ch)) continue;
+        toybuf[dst++] = prev = ch;
       }
-      xputc(TT.map[(int)toybuf[i]] & 0xFF);
-      prev_char = TT.map[(int)toybuf[i]];
-      fflush(stdout);
     }
+    xwrite(1, toybuf, dst);
   }
 }
 
-- 
2.29.2.576.ga3fc446d84-goog

_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to