summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTom Scogland <scogland1@llnl.gov>2021-05-31 20:33:14 -0700
committerGitHub <noreply@github.com>2021-05-31 20:33:14 -0700
commit4a7b0afde2e04305697da2d441a560c2f976c3c4 (patch)
tree061d3312e044cdd85efbf64ab70cba7d35b9b62e /lib
parentea4a2c9120d86da2e647c348e00c7cc477e37bd1 (diff)
downloadspack-4a7b0afde2e04305697da2d441a560c2f976c3c4.tar.gz
spack-4a7b0afde2e04305697da2d441a560c2f976c3c4.tar.bz2
spack-4a7b0afde2e04305697da2d441a560c2f976c3c4.tar.xz
spack-4a7b0afde2e04305697da2d441a560c2f976c3c4.zip
Log performance improvement (#23925)
* util.tty.log: read up to 100 lines if ready Rework to read up to 100 lines from the captured stdin as long as data is ready to be read immediately. Adds a helper function to poll with `select` for ready data. This showed a roughly 5-10x perf improvement for high-rate writes through the logger with relatively short lines. * util.tty.log: Defer flushes to end of ready reads Rather than flush per line, flush per set of reads. Since this is a non-blocking loop, the total perceived wait is short. * util.tty.log: only scan each line once, usually Rather than always find all control characters then substitute them all, use `subn` to count the number of control characters replaced. Only if control characters exist find out what they are. This could be made truly single pass with sub with a function, but it's a more intrusive change and this got 99%ish of the performance improvement (roughly another 2x in some cases). * util.tty.log: remove check for `readable` Python < 3 does not support a readable check on streams, should not be necessary here since we control the only use and it's explicitly a stream to be read.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/tty/log.py59
1 files changed, 37 insertions, 22 deletions
diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py
index 337eb0ac68..28f4f06edf 100644
--- a/lib/spack/llnl/util/tty/log.py
+++ b/lib/spack/llnl/util/tty/log.py
@@ -771,28 +771,39 @@ def _writer_daemon(stdin_multiprocess_fd, read_multiprocess_fd, write_fd, echo,
raise
if in_pipe in rlist:
- # Handle output from the calling process.
- line = _retry(in_pipe.readline)()
- if not line:
- break
-
- # find control characters and strip them.
- controls = control.findall(line)
- line = control.sub('', line)
-
- # Echo to stdout if requested or forced.
- if echo or force_echo:
- sys.stdout.write(line)
- sys.stdout.flush()
-
- # Stripped output to log file.
- log_file.write(_strip(line))
- log_file.flush()
-
- if xon in controls:
- force_echo = True
- if xoff in controls:
- force_echo = False
+ line_count = 0
+ try:
+ while line_count < 100:
+ # Handle output from the calling process.
+ line = _retry(in_pipe.readline)()
+ if not line:
+ return
+ line_count += 1
+
+ # find control characters and strip them.
+ clean_line, num_controls = control.subn('', line)
+
+ # Echo to stdout if requested or forced.
+ if echo or force_echo:
+ sys.stdout.write(clean_line)
+
+ # Stripped output to log file.
+ log_file.write(_strip(clean_line))
+
+ if num_controls > 0:
+ controls = control.findall(line)
+ if xon in controls:
+ force_echo = True
+ if xoff in controls:
+ force_echo = False
+
+ if not _input_available(in_pipe):
+ break
+ finally:
+ if line_count > 0:
+ if echo or force_echo:
+ sys.stdout.flush()
+ log_file.flush()
except BaseException:
tty.error("Exception occurred in writer daemon!")
@@ -844,3 +855,7 @@ def _retry(function):
continue
raise
return wrapped
+
+
+def _input_available(f):
+ return f in select.select([f], [], [], 0)[0]