diff options
Diffstat (limited to 'tools/pcmk_simtimes.in')
-rw-r--r-- | tools/pcmk_simtimes.in | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/tools/pcmk_simtimes.in b/tools/pcmk_simtimes.in new file mode 100644 index 0000000..c8b0af6 --- /dev/null +++ b/tools/pcmk_simtimes.in @@ -0,0 +1,159 @@ +#!@PYTHON@ +""" Timing comparisons for crm_simulate profiling output +""" + +__copyright__ = "Copyright 2019-2023 the Pacemaker project contributors" +__license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY" + +import io +import re +import sys +import errno +import argparse +import os + +# These imports allow running from a source checkout after running `make`. +# Note that while this doesn't necessarily mean it will successfully run tests, +# but being able to see --help output can be useful. +if os.path.exists("@abs_top_srcdir@/python"): + sys.path.insert(0, "@abs_top_srcdir@/python") + +if os.path.exists("@abs_top_builddir@/python") and "@abs_top_builddir@" != "@abs_top_srcdir@": + sys.path.insert(0, "@abs_top_builddir@/python") + +from pacemaker.exitstatus import ExitStatus + +DESC = """Compare timings from crm_simulate profiling output""" + +BEFORE_HELP = """Output of "crm_simulate --profile cts/scheduler --repeat <N>" from earlier Pacemaker build""" + +# line like: * Testing cts/scheduler/xml/1360.xml ... 0.07 secs +PATTERN = r"""^\s*\*\s+Testing\s+.*/([^/]+)\.xml\s+\.+\s+([.0-9]+)\s+secs\s*$""" + +def parse_args(argv=sys.argv): + """ Parse command-line arguments """ + + parser = argparse.ArgumentParser(description=DESC) + + parser.add_argument('-V', '--verbose', action='count', + help='Increase verbosity') + + parser.add_argument('-p', '--threshold-percent', type=float, default=0, + help="Don't show tests with less than this percentage difference in times") + + parser.add_argument('-s', '--threshold-seconds', type=float, default=0, + help="Don't show tests with less than this seconds difference in times") + + parser.add_argument('-S', '--sort', choices=['test', 'before', 'after', 'diff', 'percent'], + default='test', help="Sort results by this column") + + parser.add_argument('-r', '--reverse', action='store_true', + help="Sort results in descending order") + + parser.add_argument('before_file', metavar='BEFORE', + type=argparse.FileType('r'), + help=BEFORE_HELP) + + parser.add_argument('after_file', metavar='AFTER', + type=argparse.FileType('r'), + help='Output of same command from later Pacemaker build') + + return parser.parse_args(argv[1:]) + + +def extract_times(infile): + """ Extract test names and times into hash table from file """ + + result = {} + for line in infile: + match = re.search(PATTERN, line) + if match is not None: + result[match.group(1)] = match.group(2) + return result + + +def compare_test(test, before, after, args): + """ Compare one test's timings """ + + try: + before_time = float(before[test]) + except KeyError: + if args.verbose > 0: + print("No previous test " + test + " to compare") + return None + + after_time = float(after[test]) + + time_diff = after_time - before_time + time_diff_percent = (time_diff / before_time) * 100 + + if ((abs(time_diff) >= args.threshold_seconds) + and (abs(time_diff_percent) >= args.threshold_percent)): + return { 'test': test, + 'before': before_time, + 'after': after_time, + 'diff': time_diff, + 'percent': time_diff_percent + } + return None + +def sort_diff(result): + """ Sort two test results by time difference """ + + global sort_field + + return result[sort_field] + + +def print_results(results, sort_reverse): + """ Output the comparison results """ + + if results == []: + return + + # Sort and print test differences + results.sort(reverse=sort_reverse, key=sort_diff) + for result in results: + print("%-40s %6.2fs vs %6.2fs (%+.2fs = %+6.2f%%)" % (result['test'], + result['before'], result['after'], result['diff'], + result['percent'])) + + # Print average differences + diff_total = sum(d['diff'] for d in results) + percent_total = sum(d['percent'] for d in results) + nresults = len(results) + print("\nAverages: %+.2fs %+6.2f%%" % ((diff_total / nresults), + (percent_total / nresults))) + + +if __name__ == "__main__": + + global sort_field + + try: + args = parse_args() + if args.verbose is None: + args.verbose = 0 + + before = extract_times(args.before_file) + after = extract_times(args.after_file) + sort_field = args.sort + + # Build a list of test differences + results = [] + for test in after.keys(): + result = compare_test(test, before, after, args) + if result is not None: + results = results + [ result ] + + print_results(results, sort_reverse=args.reverse) + + except KeyboardInterrupt: + pass + except IOError as e: + if e.errno != errno.EPIPE: + raise + + sys.exit(ExitStatus.OK) + +# vim: set filetype=python expandtab tabstop=4 softtabstop=4 shiftwidth=4 textwidth=120: |