| Index: tools/skpbench/parseskpbench.py
|
| diff --git a/tools/skpbench/parseskpbench.py b/tools/skpbench/parseskpbench.py
|
| index 5fe146ee0917474331f24f9964c437088a4e5157..800c1ca12458a23f88d6e632b16f3080c2418c9d 100755
|
| --- a/tools/skpbench/parseskpbench.py
|
| +++ b/tools/skpbench/parseskpbench.py
|
| @@ -8,8 +8,8 @@
|
| from __future__ import print_function
|
| from _benchresult import BenchResult
|
| from argparse import ArgumentParser
|
| +from collections import defaultdict, namedtuple
|
| from datetime import datetime
|
| -import collections
|
| import operator
|
| import os
|
| import sys
|
| @@ -27,7 +27,7 @@ This script can also be used to generate a Google sheet:
|
| (1) Install the "Office Editing for Docs, Sheets & Slides" Chrome extension:
|
| https://chrome.google.com/webstore/detail/office-editing-for-docs-s/gbkeegbaiigmenfmjfclcdgdpimamgkj
|
|
|
| -(2) Designate Chrome os-wide as the default application for opening .csv files.
|
| +(2) Update your global OS file associations to use Chrome for .csv files.
|
|
|
| (3) Run parseskpbench.py with the --open flag.
|
|
|
| @@ -49,75 +49,92 @@ __argparse.add_argument('sources',
|
|
|
| FLAGS = __argparse.parse_args()
|
|
|
| +RESULT_QUALIFIERS = ('sample_ms', 'clock', 'metric')
|
| +
|
| +class FullConfig(namedtuple('fullconfig', ('config',) + RESULT_QUALIFIERS)):
|
| + def qualified_name(self, qualifiers=RESULT_QUALIFIERS):
|
| + return get_qualified_name(self.config.replace(',', ' '),
|
| + {x:getattr(self, x) for x in qualifiers})
|
| +
|
| +def get_qualified_name(name, qualifiers):
|
| + if not qualifiers:
|
| + return name
|
| + else:
|
| + args = ('%s=%s' % (k,v) for k,v in qualifiers.iteritems())
|
| + return '%s (%s)' % (name, ' '.join(args))
|
|
|
| class Parser:
|
| def __init__(self):
|
| - self.configs = list() # use list to preserve the order configs appear in.
|
| - self.rows = collections.defaultdict(dict)
|
| - self.cols = collections.defaultdict(dict)
|
| - self.metric = None
|
| - self.sample_ms = None
|
| + self.sheet_qualifiers = {x:None for x in RESULT_QUALIFIERS}
|
| + self.config_qualifiers = set()
|
| + self.fullconfigs = list() # use list to preserve the order.
|
| + self.rows = defaultdict(dict)
|
| + self.cols = defaultdict(dict)
|
|
|
| def parse_file(self, infile):
|
| for line in infile:
|
| match = BenchResult.match(line)
|
| if not match:
|
| continue
|
| - if self.metric is None:
|
| - self.metric = match.metric
|
| - elif match.metric != self.metric:
|
| - raise ValueError("results have mismatched metrics (%s and %s)" %
|
| - (self.metric, match.metric))
|
| - if self.sample_ms is None:
|
| - self.sample_ms = match.sample_ms
|
| - elif not FLAGS.force and match.sample_ms != self.sample_ms:
|
| - raise ValueError("results have mismatched sampling times. "
|
| - "(use --force to ignore)")
|
| - if not match.config in self.configs:
|
| - self.configs.append(match.config)
|
| - self.rows[match.bench][match.config] = match.get_string(FLAGS.result)
|
| - self.cols[match.config][match.bench] = getattr(match, FLAGS.result)
|
| +
|
| + fullconfig = FullConfig(*(match.get_string(x)
|
| + for x in FullConfig._fields))
|
| + if not fullconfig in self.fullconfigs:
|
| + self.fullconfigs.append(fullconfig)
|
| +
|
| + for qualifier, value in self.sheet_qualifiers.items():
|
| + if value is None:
|
| + self.sheet_qualifiers[qualifier] = match.get_string(qualifier)
|
| + elif value != match.get_string(qualifier):
|
| + del self.sheet_qualifiers[qualifier]
|
| + self.config_qualifiers.add(qualifier)
|
| +
|
| + self.rows[match.bench][fullconfig] = match.get_string(FLAGS.result)
|
| + self.cols[fullconfig][match.bench] = getattr(match, FLAGS.result)
|
|
|
| def print_csv(self, outfile=sys.stdout):
|
| - print('%s_%s' % (FLAGS.result, self.metric), file=outfile)
|
| + # Write the title.
|
| + print(get_qualified_name(FLAGS.result, self.sheet_qualifiers), file=outfile)
|
|
|
| # Write the header.
|
| outfile.write('bench,')
|
| - for config in self.configs:
|
| - outfile.write('%s,' % config)
|
| + for fullconfig in self.fullconfigs:
|
| + outfile.write('%s,' % fullconfig.qualified_name(self.config_qualifiers))
|
| outfile.write('\n')
|
|
|
| # Write the rows.
|
| - for bench, row in self.rows.items():
|
| + for bench, row in self.rows.iteritems():
|
| outfile.write('%s,' % bench)
|
| - for config in self.configs:
|
| - if config in row:
|
| - outfile.write('%s,' % row[config])
|
| + for fullconfig in self.fullconfigs:
|
| + if fullconfig in row:
|
| + outfile.write('%s,' % row[fullconfig])
|
| elif FLAGS.force:
|
| - outfile.write(',')
|
| + outfile.write('NULL,')
|
| else:
|
| raise ValueError("%s: missing value for %s. (use --force to ignore)" %
|
| - (bench, config))
|
| + (bench,
|
| + fullconfig.qualified_name(self.config_qualifiers)))
|
| outfile.write('\n')
|
|
|
| # Add simple, literal averages.
|
| if len(self.rows) > 1:
|
| outfile.write('\n')
|
| - self.__print_computed_row('MEAN',
|
| + self._print_computed_row('MEAN',
|
| lambda col: reduce(operator.add, col.values()) / len(col),
|
| outfile=outfile)
|
| - self.__print_computed_row('GEOMEAN',
|
| + self._print_computed_row('GEOMEAN',
|
| lambda col: reduce(operator.mul, col.values()) ** (1.0 / len(col)),
|
| outfile=outfile)
|
|
|
| - def __print_computed_row(self, name, func, outfile=sys.stdout):
|
| + def _print_computed_row(self, name, func, outfile=sys.stdout):
|
| outfile.write('%s,' % name)
|
| - for config in self.configs:
|
| - assert(len(self.cols[config]) == len(self.rows))
|
| - outfile.write('%.4g,' % func(self.cols[config]))
|
| + for fullconfig in self.fullconfigs:
|
| + if len(self.cols[fullconfig]) != len(self.rows):
|
| + outfile.write('NULL,')
|
| + continue
|
| + outfile.write('%.4g,' % func(self.cols[fullconfig]))
|
| outfile.write('\n')
|
|
|
| -
|
| def main():
|
| parser = Parser()
|
|
|
|
|