[Perf-training] Adding support for tests to skip the clang driver

This patch adds a new set of substitutions to the lit run lines for order files and PGO generation which run the clang driver to get the cc1 command, then execute the cc1 command directly. This allows the scripts to bypass profiling the clang driver over and over again.

The approach in this patch was discussed via IRC with Sean Silvas.

Special thanks to Daniel Dunbar whose out-of-tree code I liberally plagiarized.

llvm-svn: 263997
This commit is contained in:
Chris Bieneman 2016-03-21 22:37:14 +00:00
parent e9b02d68f4
commit 12fd02db6b
5 changed files with 69 additions and 2 deletions

View File

@ -1,4 +1,5 @@
// RUN: %clang_cpp -c %s
// RUN: %clang_cpp_skip_driver -Wall -pedantic -c %s
#include <iostream>
int main(int, char**) {

View File

@ -26,10 +26,13 @@ config.clang = lit.util.which('clang', config.clang_tools_dir).replace('\\', '/'
config.name = 'Clang Perf Training'
config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap']
cc1_wrapper = '%s %s/perf-helper.py cc1' % (config.python_exe, config.test_source_root)
use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
config.test_format = lit.formats.ShTest(use_lit_shell == "0")
config.substitutions.append( ('%clang_cpp_skip_driver', ' %s %s %s ' % (cc1_wrapper, config.clang, sysroot_flags)))
config.substitutions.append( ('%clang_cpp', ' %s --driver-mode=cpp %s ' % (config.clang, sysroot_flags)))
config.substitutions.append( ('%clang_cc1', ' %s -cc1 %s ' % (config.clang, sysroot_flags)))
config.substitutions.append( ('%clang_skip_driver', ' %s %s %s ' % (cc1_wrapper, config.clang, sysroot_flags)))
config.substitutions.append( ('%clang', ' %s %s ' % (config.clang, sysroot_flags) ) )
config.substitutions.append( ('%test_root', config.test_exec_root ) )

View File

@ -6,6 +6,7 @@ config.clang_tools_dir = "@CLANG_TOOLS_DIR@"
config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@"
config.test_source_root = "@CMAKE_CURRENT_SOURCE_DIR@"
config.target_triple = "@TARGET_TRIPLE@"
config.python_exe = "@PYTHON_EXECUTABLE@"
# Support substitution of the tools and libs dirs with user parameters. This is
# used when we can't determine the tool dir at configuration time.

View File

@ -28,11 +28,13 @@ config.name = 'Clang Perf Training'
config.suffixes = ['.c', '.cpp', '.m', '.mm', '.cu', '.ll', '.cl', '.s', '.S', '.modulemap']
dtrace_wrapper = '%s %s/perf-helper.py dtrace' % (config.python_exe, config.test_source_root)
dtrace_wrapper_cc1 = '%s %s/perf-helper.py dtrace --cc1' % (config.python_exe, config.test_source_root)
use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL")
config.test_format = lit.formats.ShTest(use_lit_shell == "0")
config.substitutions.append( ('%clang_cpp_skip_driver', ' %s %s --driver-mode=cpp %s ' % (dtrace_wrapper_cc1, config.clang, sysroot_flags)))
config.substitutions.append( ('%clang_cpp', ' %s %s --driver-mode=cpp %s ' % (dtrace_wrapper, config.clang, sysroot_flags)))
config.substitutions.append( ('%clang_cc1', ' %s %s -cc1 %s ' % (dtrace_wrapper, config.clang, sysroot_flags)))
config.substitutions.append( ('%clang_skip_driver', ' %s %s %s ' % (dtrace_wrapper_cc1, config.clang, sysroot_flags)))
config.substitutions.append( ('%clang', ' %s %s %s ' % (dtrace_wrapper, config.clang, sysroot_flags) ) )
config.substitutions.append( ('%test_root', config.test_exec_root ) )

View File

@ -15,6 +15,9 @@ import subprocess
import argparse
import time
import bisect
import shlex
test_env = { 'PATH' : os.environ['PATH'] }
def findFilesWithExtension(path, extension):
filenames = []
@ -52,6 +55,8 @@ def dtrace(args):
help='Use dtrace\'s oneshot probes')
parser.add_argument('--use-ustack', required=False, action='store_true',
help='Use dtrace\'s ustack to print function names')
parser.add_argument('--cc1', required=False, action='store_true',
help='Execute cc1 directly (don\'t profile the driver)')
parser.add_argument('cmd', nargs='*', help='')
# Use python's arg parser to handle all leading option arguments, but pass
@ -62,6 +67,9 @@ def dtrace(args):
opts = parser.parse_args(args[:last_arg_idx])
cmd = args[last_arg_idx:]
if opts.cc1:
cmd = get_cc1_command_for_args(cmd, test_env)
if opts.use_oneshot:
target = "oneshot$target:::entry"
else:
@ -98,6 +106,57 @@ def dtrace(args):
return 0
def get_cc1_command_for_args(cmd, env):
# Find the cc1 command used by the compiler. To do this we execute the
# compiler with '-###' to figure out what it wants to do.
cmd = cmd + ['-###']
cc_output = check_output(cmd, stderr=subprocess.STDOUT, env=env).strip()
cc_commands = []
for ln in cc_output.split('\n'):
# Filter out known garbage.
if (ln == 'Using built-in specs.' or
ln.startswith('Configured with:') or
ln.startswith('Target:') or
ln.startswith('Thread model:') or
ln.startswith('InstalledDir:') or
' version ' in ln):
continue
cc_commands.append(ln)
if len(cc_commands) != 1:
print('Fatal error: unable to determine cc1 command: %r' % cc_output)
exit(1)
cc1_cmd = shlex.split(cc_commands[0])
if not cc1_cmd:
print('Fatal error: unable to determine cc1 command: %r' % cc_output)
exit(1)
return cc1_cmd
def cc1(args):
parser = argparse.ArgumentParser(prog='perf-helper cc1',
description='cc1 wrapper for order file generation')
parser.add_argument('cmd', nargs='*', help='')
# Use python's arg parser to handle all leading option arguments, but pass
# everything else through to dtrace
first_cmd = next(arg for arg in args if not arg.startswith("--"))
last_arg_idx = args.index(first_cmd)
opts = parser.parse_args(args[:last_arg_idx])
cmd = args[last_arg_idx:]
# clear the profile file env, so that we don't generate profdata
# when capturing the cc1 command
cc1_env = test_env
cc1_env["LLVM_PROFILE_FILE"] = "driver.prfraw"
cc1_cmd = get_cc1_command_for_args(cmd, cc1_env)
os.remove("driver.prfraw")
subprocess.check_call(cc1_cmd)
return 0;
def parse_dtrace_symbol_file(path, all_symbols, all_symbols_set,
missing_symbols, opts):
def fix_mangling(symbol):
@ -341,6 +400,7 @@ def genOrderFile(args):
commands = {'clean' : clean,
'merge' : merge,
'dtrace' : dtrace,
'cc1' : cc1,
'gen-order-file' : genOrderFile}
def main():