aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2020-12-04 10:06:49 -0800
committerRob Landley <rob@landley.net>2020-12-05 04:24:36 -0600
commit72ec2b37468d7f1f0c15e6b201f914802d9d3b4f (patch)
tree41e6a7904e435bf0a060e035c6e70013b3b20063
parentec6639407b9eabf986ba81cfa6f2910feddf32dc (diff)
downloadtoybox-72ec2b37468d7f1f0c15e6b201f914802d9d3b4f.tar.gz
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
-rwxr-xr-xtests/tr.test11
-rw-r--r--toys/pending/tr.c27
2 files changed, 22 insertions, 16 deletions
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);
}
}