]> granicus.if.org Git - clang/commitdiff
[Perf-training] Adding support for tests to skip the clang driver
authorChris Bieneman <beanz@apple.com>
Mon, 21 Mar 2016 22:37:14 +0000 (22:37 +0000)
committerChris Bieneman <beanz@apple.com>
Mon, 21 Mar 2016 22:37:14 +0000 (22:37 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@263997 91177308-0d34-0410-b5e6-96231b3b80d8

utils/perf-training/cxx/hello_world.cpp
utils/perf-training/lit.cfg
utils/perf-training/lit.site.cfg.in
utils/perf-training/order-files.lit.cfg
utils/perf-training/perf-helper.py

index 66e00d00d26140aca53a0e853c562ba3bcfc7b91..fc9f6892eb7405c4f6545f1efe38d387863d0d9f 100644 (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**) {
index af4b43b78b09f000c5e846575cc43fad19a0da9c..85d35514341029c71391d4680268f038b8b44c5c 100644 (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 ) )
 
index 9dc380242e52f56f13ede7ad8b0e51e891499753..52c5465dc34605fabd704b8cc424d1319f16eb86 100644 (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.
index 0e151bf1fa8fa865e5937633b701c5cab9ba5157..75501f8c629799a22fe37f0394d87aa800431803 100644 (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 ) )
 
index a4ae68c849a271cf66b59dde67a01dec2cb0b0ec..19f3819b301ce656fbd2db1b8d4f42918a572385 100644 (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():