From 14e1d55b0da331e7c7c0634f6c6c626229d4fd0e Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 11 Jul 2017 16:05:50 +0000 Subject: [PATCH] [lit] Implement non-pipelined echo commands internally Summary: This speeds up the LLD test suite on Windows by 3x. Most of the time is spent on lld/test/ELF/linkerscript/diagnostics.s, which repeatedly constructs linker scripts with appending echo commands. Reviewers: dlj, zturner, modocache Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35093 llvm-svn: 307668 --- llvm/utils/lit/lit/TestRunner.py | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py index e49aec9..f803604 100644 --- a/llvm/utils/lit/lit/TestRunner.py +++ b/llvm/utils/lit/lit/TestRunner.py @@ -5,6 +5,11 @@ import platform import tempfile import threading +try: + import cStringIO as StringIO +except ImportError: + import StringIO + from lit.ShCommands import GlobItem import lit.ShUtil as ShUtil import lit.Test as Test @@ -221,6 +226,64 @@ def updateEnv(env, cmd): env.env[key] = val cmd.args = cmd.args[arg_idx+1:] +def executeBuiltinEcho(cmd, shenv): + """Interpret a redirected echo command""" + opened_files = [] + stdin, stdout, stderr = processRedirects(cmd, subprocess.PIPE, shenv, + opened_files) + if stdin != subprocess.PIPE or stderr != subprocess.PIPE: + raise InternalShellError( + cmd, "stdin and stderr redirects not supported for echo") + + # Some tests have un-redirected echo commands to help debug test failures. + # Buffer our output and return it to the caller. + is_redirected = True + if stdout == subprocess.PIPE: + is_redirected = False + stdout = StringIO.StringIO() + elif kIsWindows: + # Reopen stdout in binary mode to avoid CRLF translation. The versions + # of echo we are replacing on Windows all emit plain LF, and the LLVM + # tests now depend on this. + stdout = open(stdout.name, stdout.mode + 'b') + opened_files.append((None, None, stdout, None)) + + # Implement echo flags. We only support -e and -n, and not yet in + # combination. We have to ignore unknown flags, because `echo "-D FOO"` + # prints the dash. + args = cmd.args[1:] + interpret_escapes = False + write_newline = True + while len(args) >= 1 and args[0] in ('-e', '-n'): + flag = args[0] + args = args[1:] + if flag == '-e': + interpret_escapes = True + elif flag == '-n': + write_newline = False + + def maybeUnescape(arg): + if not interpret_escapes: + return arg + # Python string escapes and "echo" escapes are obviously different, but + # this should be enough for the LLVM test suite. + return arg.decode('string_escape') + + if args: + for arg in args[:-1]: + stdout.write(maybeUnescape(arg)) + stdout.write(' ') + stdout.write(maybeUnescape(args[-1])) + if write_newline: + stdout.write('\n') + + for (name, mode, f, path) in opened_files: + f.close() + + if not is_redirected: + return stdout.getvalue() + return "" + def processRedirects(cmd, stdin_source, cmd_shenv, opened_files): """Return the standard fds for cmd after applying redirects @@ -360,6 +423,17 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): # following Popen calls will fail instead. return 0 + # Handle "echo" as a builtin if it is not part of a pipeline. This greatly + # speeds up tests that construct input files by repeatedly echo-appending to + # a file. + # FIXME: Standardize on the builtin echo implementation. We can use a + # temporary file to sidestep blocking pipe write issues. + if cmd.commands[0].args[0] == 'echo' and len(cmd.commands) == 1: + output = executeBuiltinEcho(cmd.commands[0], shenv) + results.append(ShellCommandResult(cmd.commands[0], output, "", 0, + False)) + return 0 + if cmd.commands[0].args[0] == 'export': if len(cmd.commands) != 1: raise ValueError("'export' cannot be part of a pipeline") -- 2.7.4