summaryrefslogtreecommitdiffstats
path: root/tools/pcmk_simtimes.in
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pcmk_simtimes.in')
-rw-r--r--tools/pcmk_simtimes.in159
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: