Simple profiling script for outputing CSV batches
Jeffrey Pfau jeffrey@endrift.com
Thu, 09 Oct 2014 00:08:46 -0700
2 files changed,
121 insertions(+),
0 deletions(-)
M
CMakeLists.txt
→
CMakeLists.txt
@@ -23,6 +23,8 @@ include_directories(${CMAKE_SOURCE_DIR}/src/arm)
include_directories(${CMAKE_SOURCE_DIR}/src/gba) include_directories(${CMAKE_SOURCE_DIR}/src) +include(GNUInstallDirs) + # Function definitions include(FindPkgConfig) function(find_feature FEATURE_NAME FEATURE_REQUIRES)@@ -160,6 +162,7 @@
add_executable(${BINARY_NAME}-perf ${PERF_SRC}) target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB}) install(TARGETS ${BINARY_NAME}-perf DESTINATION bin) + install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}") endif() # Summaries
A
tools/perf.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python +from __future__ import print_function +import argparse +import csv +import os +import signal +import subprocess +import sys +import time + +class PerfTest(object): + EXECUTABLE = 'mgba-perf' + + def __init__(self, rom, renderer='software'): + self.rom = rom + self.renderer = renderer + self.results = None + self.name = 'Perf Test: {}'.format(rom) + + def get_args(self): + return [] + + def wait(self, proc): + pass + + def run(self, cwd): + args = [os.path.join(os.getcwd(), self.EXECUTABLE), '-P'] + args.extend(self.get_args()) + if self.renderer != 'software': + args.append('-N') + args.append(self.rom) + proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True) + try: + self.wait(proc) + proc.wait() + except: + proc.kill() + raise + if proc.returncode < 0: + return + reader = csv.DictReader(proc.stdout) + self.results = next(reader) + +class WallClockTest(PerfTest): + def __init__(self, rom, duration, renderer='software'): + super(WallClockTest, self).__init__(rom, renderer) + self.duration = duration + self.name = 'Wall-Clock Test ({} seconds, {} renderer): {}'.format(duration, renderer, rom) + + def wait(self, proc): + time.sleep(self.duration) + proc.send_signal(signal.SIGINT) + +class GameClockTest(PerfTest): + def __init__(self, rom, frames, renderer='software'): + super(GameClockTest, self).__init__(rom, renderer) + self.frames = frames + self.name = 'Game-Clock Test ({} frames, {} renderer): {}'.format(frames, renderer, rom) + + def get_args(self): + return ['-F', str(self.frames)] + +class Suite(object): + def __init__(self, cwd, wall=None, game=None): + self.cwd = cwd + self.tests = [] + self.wall = wall + self.game = game + + def collect_tests(self): + roms = [] + for f in os.listdir(self.cwd): + if f.endswith('.gba'): + roms.append(f) + roms.sort() + for rom in roms: + self.add_tests(rom) + + def add_tests(self, rom): + if self.wall: + self.tests.append(WallClockTest(rom, self.wall)) + self.tests.append(WallClockTest(rom, self.wall, renderer=None)) + if self.game: + self.tests.append(GameClockTest(rom, self.game)) + self.tests.append(GameClockTest(rom, self.game, renderer=None)) + + def run(self): + results = [] + for test in self.tests: + print('Running test {}'.format(test.name), file=sys.stderr) + try: + test.run(self.cwd) + except KeyboardInterrupt: + print('Interrupted, returning early...', file=sys.stderr) + return results + if test.results: + results.append(test.results) + return results + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-w', '--wall-time', type=float, default=120, metavar='TIME', help='wall-clock time') + parser.add_argument('-g', '--game-frames', type=int, default=120*60, metavar='FRAMES', help='game-clock frames') + parser.add_argument('-o', '--out', metavar='FILE', help='output file path') + parser.add_argument('directory', help='directory containing ROM files') + args = parser.parse_args() + + s = Suite(args.directory, wall=args.wall_time, game=args.game_frames) + s.collect_tests() + results = s.run() + fout = sys.stdout + if args.out: + fout = open(args.out, 'w') + writer = csv.DictWriter(fout, results[0].keys()) + writer.writeheader() + writer.writerows(results) + if fout is not sys.stdout: + fout.close()