summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/utils/perf-training/perf-helper.py
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
commitb64793999546ed8adebaeebd9d8345d18db8927d (patch)
tree4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/clang/utils/perf-training/perf-helper.py
parentAdd support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff)
downloadwireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz
wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/clang/utils/perf-training/perf-helper.py')
-rw-r--r--gnu/llvm/tools/clang/utils/perf-training/perf-helper.py408
1 files changed, 0 insertions, 408 deletions
diff --git a/gnu/llvm/tools/clang/utils/perf-training/perf-helper.py b/gnu/llvm/tools/clang/utils/perf-training/perf-helper.py
deleted file mode 100644
index 65afbb6ed57..00000000000
--- a/gnu/llvm/tools/clang/utils/perf-training/perf-helper.py
+++ /dev/null
@@ -1,408 +0,0 @@
-#===- perf-helper.py - Clang Python Bindings -----------------*- python -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-from __future__ import absolute_import, division, print_function
-
-import sys
-import os
-import subprocess
-import argparse
-import time
-import bisect
-import shlex
-import tempfile
-
-test_env = { 'PATH' : os.environ['PATH'] }
-
-def findFilesWithExtension(path, extension):
- filenames = []
- for root, dirs, files in os.walk(path):
- for filename in files:
- if filename.endswith(extension):
- filenames.append(os.path.join(root, filename))
- return filenames
-
-def clean(args):
- if len(args) != 2:
- print('Usage: %s clean <path> <extension>\n' % __file__ +
- '\tRemoves all files with extension from <path>.')
- return 1
- for filename in findFilesWithExtension(args[0], args[1]):
- os.remove(filename)
- return 0
-
-def merge(args):
- if len(args) != 3:
- print('Usage: %s clean <llvm-profdata> <output> <path>\n' % __file__ +
- '\tMerges all profraw files from path into output.')
- return 1
- cmd = [args[0], 'merge', '-o', args[1]]
- cmd.extend(findFilesWithExtension(args[2], "profraw"))
- subprocess.check_call(cmd)
- return 0
-
-def dtrace(args):
- parser = argparse.ArgumentParser(prog='perf-helper dtrace',
- description='dtrace wrapper for order file generation')
- parser.add_argument('--buffer-size', metavar='size', type=int, required=False,
- default=1, help='dtrace buffer size in MB (default 1)')
- parser.add_argument('--use-oneshot', required=False, action='store_true',
- 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
- # 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:]
-
- if opts.cc1:
- cmd = get_cc1_command_for_args(cmd, test_env)
-
- if opts.use_oneshot:
- target = "oneshot$target:::entry"
- else:
- target = "pid$target:::entry"
- predicate = '%s/probemod=="%s"/' % (target, os.path.basename(cmd[0]))
- log_timestamp = 'printf("dtrace-TS: %d\\n", timestamp)'
- if opts.use_ustack:
- action = 'ustack(1);'
- else:
- action = 'printf("dtrace-Symbol: %s\\n", probefunc);'
- dtrace_script = "%s { %s; %s }" % (predicate, log_timestamp, action)
-
- dtrace_args = []
- if not os.geteuid() == 0:
- print(
- 'Script must be run as root, or you must add the following to your sudoers:'
- + '%%admin ALL=(ALL) NOPASSWD: /usr/sbin/dtrace')
- dtrace_args.append("sudo")
-
- dtrace_args.extend((
- 'dtrace', '-xevaltime=exec',
- '-xbufsize=%dm' % (opts.buffer_size),
- '-q', '-n', dtrace_script,
- '-c', ' '.join(cmd)))
-
- if sys.platform == "darwin":
- dtrace_args.append('-xmangled')
-
- start_time = time.time()
-
- with open("%d.dtrace" % os.getpid(), "w") as f:
- f.write("### Command: %s" % dtrace_args)
- subprocess.check_call(dtrace_args, stdout=f, stderr=subprocess.PIPE)
-
- elapsed = time.time() - start_time
- print("... data collection took %.4fs" % elapsed)
-
- 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 = subprocess.check_output(cmd, stderr=subprocess.STDOUT, env=env, universal_newlines=True).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
- ln.startswith('LLVM Profile Note') 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"] = os.devnull
- cc1_cmd = get_cc1_command_for_args(cmd, cc1_env)
-
- 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):
- if sys.platform == "darwin":
- if symbol[0] != '_' and symbol != 'start':
- symbol = '_' + symbol
- return symbol
-
- def get_symbols_with_prefix(symbol):
- start_index = bisect.bisect_left(all_symbols, symbol)
- for s in all_symbols[start_index:]:
- if not s.startswith(symbol):
- break
- yield s
-
- # Extract the list of symbols from the given file, which is assumed to be
- # the output of a dtrace run logging either probefunc or ustack(1) and
- # nothing else. The dtrace -xdemangle option needs to be used.
- #
- # This is particular to OS X at the moment, because of the '_' handling.
- with open(path) as f:
- current_timestamp = None
- for ln in f:
- # Drop leading and trailing whitespace.
- ln = ln.strip()
- if not ln.startswith("dtrace-"):
- continue
-
- # If this is a timestamp specifier, extract it.
- if ln.startswith("dtrace-TS: "):
- _,data = ln.split(': ', 1)
- if not data.isdigit():
- print("warning: unrecognized timestamp line %r, ignoring" % ln,
- file=sys.stderr)
- continue
- current_timestamp = int(data)
- continue
- elif ln.startswith("dtrace-Symbol: "):
-
- _,ln = ln.split(': ', 1)
- if not ln:
- continue
-
- # If there is a '`' in the line, assume it is a ustack(1) entry in
- # the form of <modulename>`<modulefunc>, where <modulefunc> is never
- # truncated (but does need the mangling patched).
- if '`' in ln:
- yield (current_timestamp, fix_mangling(ln.split('`',1)[1]))
- continue
-
- # Otherwise, assume this is a probefunc printout. DTrace on OS X
- # seems to have a bug where it prints the mangled version of symbols
- # which aren't C++ mangled. We just add a '_' to anything but start
- # which doesn't already have a '_'.
- symbol = fix_mangling(ln)
-
- # If we don't know all the symbols, or the symbol is one of them,
- # just return it.
- if not all_symbols_set or symbol in all_symbols_set:
- yield (current_timestamp, symbol)
- continue
-
- # Otherwise, we have a symbol name which isn't present in the
- # binary. We assume it is truncated, and try to extend it.
-
- # Get all the symbols with this prefix.
- possible_symbols = list(get_symbols_with_prefix(symbol))
- if not possible_symbols:
- continue
-
- # If we found too many possible symbols, ignore this as a prefix.
- if len(possible_symbols) > 100:
- print( "warning: ignoring symbol %r " % symbol +
- "(no match and too many possible suffixes)", file=sys.stderr)
- continue
-
- # Report that we resolved a missing symbol.
- if opts.show_missing_symbols and symbol not in missing_symbols:
- print("warning: resolved missing symbol %r" % symbol, file=sys.stderr)
- missing_symbols.add(symbol)
-
- # Otherwise, treat all the possible matches as having occurred. This
- # is an over-approximation, but it should be ok in practice.
- for s in possible_symbols:
- yield (current_timestamp, s)
-
-def uniq(list):
- seen = set()
- for item in list:
- if item not in seen:
- yield item
- seen.add(item)
-
-def form_by_call_order(symbol_lists):
- # Simply strategy, just return symbols in order of occurrence, even across
- # multiple runs.
- return uniq(s for symbols in symbol_lists for s in symbols)
-
-def form_by_call_order_fair(symbol_lists):
- # More complicated strategy that tries to respect the call order across all
- # of the test cases, instead of giving a huge preference to the first test
- # case.
-
- # First, uniq all the lists.
- uniq_lists = [list(uniq(symbols)) for symbols in symbol_lists]
-
- # Compute the successors for each list.
- succs = {}
- for symbols in uniq_lists:
- for a,b in zip(symbols[:-1], symbols[1:]):
- succs[a] = items = succs.get(a, [])
- if b not in items:
- items.append(b)
-
- # Emit all the symbols, but make sure to always emit all successors from any
- # call list whenever we see a symbol.
- #
- # There isn't much science here, but this sometimes works better than the
- # more naive strategy. Then again, sometimes it doesn't so more research is
- # probably needed.
- return uniq(s
- for symbols in symbol_lists
- for node in symbols
- for s in ([node] + succs.get(node,[])))
-
-def form_by_frequency(symbol_lists):
- # Form the order file by just putting the most commonly occurring symbols
- # first. This assumes the data files didn't use the oneshot dtrace method.
-
- counts = {}
- for symbols in symbol_lists:
- for a in symbols:
- counts[a] = counts.get(a,0) + 1
-
- by_count = list(counts.items())
- by_count.sort(key = lambda __n: -__n[1])
- return [s for s,n in by_count]
-
-def form_by_random(symbol_lists):
- # Randomize the symbols.
- merged_symbols = uniq(s for symbols in symbol_lists
- for s in symbols)
- random.shuffle(merged_symbols)
- return merged_symbols
-
-def form_by_alphabetical(symbol_lists):
- # Alphabetize the symbols.
- merged_symbols = list(set(s for symbols in symbol_lists for s in symbols))
- merged_symbols.sort()
- return merged_symbols
-
-methods = dict((name[len("form_by_"):],value)
- for name,value in locals().items() if name.startswith("form_by_"))
-
-def genOrderFile(args):
- parser = argparse.ArgumentParser(
- "%prog [options] <dtrace data file directories>]")
- parser.add_argument('input', nargs='+', help='')
- parser.add_argument("--binary", metavar="PATH", type=str, dest="binary_path",
- help="Path to the binary being ordered (for getting all symbols)",
- default=None)
- parser.add_argument("--output", dest="output_path",
- help="path to output order file to write", default=None, required=True,
- metavar="PATH")
- parser.add_argument("--show-missing-symbols", dest="show_missing_symbols",
- help="show symbols which are 'fixed up' to a valid name (requires --binary)",
- action="store_true", default=None)
- parser.add_argument("--output-unordered-symbols",
- dest="output_unordered_symbols_path",
- help="write a list of the unordered symbols to PATH (requires --binary)",
- default=None, metavar="PATH")
- parser.add_argument("--method", dest="method",
- help="order file generation method to use", choices=list(methods.keys()),
- default='call_order')
- opts = parser.parse_args(args)
-
- # If the user gave us a binary, get all the symbols in the binary by
- # snarfing 'nm' output.
- if opts.binary_path is not None:
- output = subprocess.check_output(['nm', '-P', opts.binary_path], universal_newlines=True)
- lines = output.split("\n")
- all_symbols = [ln.split(' ',1)[0]
- for ln in lines
- if ln.strip()]
- print("found %d symbols in binary" % len(all_symbols))
- all_symbols.sort()
- else:
- all_symbols = []
- all_symbols_set = set(all_symbols)
-
- # Compute the list of input files.
- input_files = []
- for dirname in opts.input:
- input_files.extend(findFilesWithExtension(dirname, "dtrace"))
-
- # Load all of the input files.
- print("loading from %d data files" % len(input_files))
- missing_symbols = set()
- timestamped_symbol_lists = [
- list(parse_dtrace_symbol_file(path, all_symbols, all_symbols_set,
- missing_symbols, opts))
- for path in input_files]
-
- # Reorder each symbol list.
- symbol_lists = []
- for timestamped_symbols_list in timestamped_symbol_lists:
- timestamped_symbols_list.sort()
- symbol_lists.append([symbol for _,symbol in timestamped_symbols_list])
-
- # Execute the desire order file generation method.
- method = methods.get(opts.method)
- result = list(method(symbol_lists))
-
- # Report to the user on what percentage of symbols are present in the order
- # file.
- num_ordered_symbols = len(result)
- if all_symbols:
- print("note: order file contains %d/%d symbols (%.2f%%)" % (
- num_ordered_symbols, len(all_symbols),
- 100.*num_ordered_symbols/len(all_symbols)), file=sys.stderr)
-
- if opts.output_unordered_symbols_path:
- ordered_symbols_set = set(result)
- with open(opts.output_unordered_symbols_path, 'w') as f:
- f.write("\n".join(s for s in all_symbols if s not in ordered_symbols_set))
-
- # Write the order file.
- with open(opts.output_path, 'w') as f:
- f.write("\n".join(result))
- f.write("\n")
-
- return 0
-
-commands = {'clean' : clean,
- 'merge' : merge,
- 'dtrace' : dtrace,
- 'cc1' : cc1,
- 'gen-order-file' : genOrderFile}
-
-def main():
- f = commands[sys.argv[1]]
- sys.exit(f(sys.argv[2:]))
-
-if __name__ == '__main__':
- main()