all repos — mgba @ 5734819cb22ccb1b802df3850df47ab47d1753d8

mGBA Game Boy Advance Emulator

tools/perf.py (view raw)

  1#!/usr/bin/env python
  2from __future__ import print_function
  3import argparse
  4import csv
  5import os
  6import signal
  7import subprocess
  8import sys
  9import time
 10
 11class PerfTest(object):
 12    EXECUTABLE = 'mgba-perf'
 13
 14    def __init__(self, rom, renderer='software'):
 15        self.rom = rom
 16        self.renderer = renderer
 17        self.results = None
 18        self.name = 'Perf Test: {}'.format(rom)
 19
 20    def get_args(self):
 21        return []
 22
 23    def wait(self, proc):
 24        pass
 25
 26    def run(self, cwd):
 27        args = [os.path.join(os.getcwd(), self.EXECUTABLE), '-P']
 28        args.extend(self.get_args())
 29        if self.renderer != 'software':
 30            args.append('-N')
 31        args.append(self.rom)
 32        env = {}
 33        if 'LD_LIBRARY_PATH' in os.environ:
 34            env['LD_LIBRARY_PATH'] = os.path.abspath(os.environ['LD_LIBRARY_PATH'])
 35            env['DYLD_LIBRARY_PATH'] = env['LD_LIBRARY_PATH'] # Fake it on OS X
 36        proc = subprocess.Popen(args, stdout=subprocess.PIPE, cwd=cwd, universal_newlines=True, env=env)
 37        try:
 38            self.wait(proc)
 39            proc.wait()
 40        except:
 41            proc.kill()
 42            raise
 43        if proc.returncode:
 44            print('Game crashed!', file=sys.stderr)
 45            return
 46        reader = csv.DictReader(proc.stdout)
 47        self.results = next(reader)
 48
 49class WallClockTest(PerfTest):
 50    def __init__(self, rom, duration, renderer='software'):
 51        super(WallClockTest, self).__init__(rom, renderer)
 52        self.duration = duration
 53        self.name = 'Wall-Clock Test ({} seconds, {} renderer): {}'.format(duration, renderer, rom)
 54
 55    def wait(self, proc):
 56        time.sleep(self.duration)
 57        proc.send_signal(signal.SIGINT)
 58
 59class GameClockTest(PerfTest):
 60    def __init__(self, rom, frames, renderer='software'):
 61        super(GameClockTest, self).__init__(rom, renderer)
 62        self.frames = frames
 63        self.name = 'Game-Clock Test ({} frames, {} renderer): {}'.format(frames, renderer, rom)
 64
 65    def get_args(self):
 66        return ['-F', str(self.frames)]
 67
 68class Suite(object):
 69    def __init__(self, cwd, wall=None, game=None, renderer='software'):
 70        self.cwd = cwd
 71        self.tests = []
 72        self.wall = wall
 73        self.game = game
 74        self.renderer = renderer
 75
 76    def collect_tests(self):
 77        roms = []
 78        for f in os.listdir(self.cwd):
 79            if f.endswith('.gba') or f.endswith('.zip'):
 80                roms.append(f)
 81        roms.sort()
 82        for rom in roms:
 83            self.add_tests(rom)
 84
 85    def add_tests(self, rom):
 86        if self.wall:
 87            self.tests.append(WallClockTest(rom, self.wall, renderer=self.renderer))
 88        if self.game:
 89            self.tests.append(GameClockTest(rom, self.game, renderer=self.renderer))
 90
 91    def run(self):
 92        results = []
 93        for test in self.tests:
 94            print('Running test {}'.format(test.name), file=sys.stderr)
 95            try:
 96                test.run(self.cwd)
 97            except KeyboardInterrupt:
 98                print('Interrupted, returning early...', file=sys.stderr)
 99                return results
100            if test.results:
101                results.append(test.results)
102        return results
103
104if __name__ == '__main__':
105    parser = argparse.ArgumentParser()
106    parser.add_argument('-w', '--wall-time', type=float, default=0, metavar='TIME', help='wall-clock time')
107    parser.add_argument('-g', '--game-frames', type=int, default=0, metavar='FRAMES', help='game-clock frames')
108    parser.add_argument('-N', '--disable-renderer', action='store_const', const=True, help='disable video rendering')
109    parser.add_argument('-o', '--out', metavar='FILE', help='output file path')
110    parser.add_argument('directory', help='directory containing ROM files')
111    args = parser.parse_args()
112
113    s = Suite(args.directory, wall=args.wall_time, game=args.game_frames, renderer=None if args.disable_renderer else 'software')
114    s.collect_tests()
115    results = s.run()
116    fout = sys.stdout
117    if args.out:
118        fout = open(args.out, 'w')
119    writer = csv.DictWriter(fout, results[0].keys())
120    writer.writeheader()
121    writer.writerows(results)
122    if fout is not sys.stdout:
123        fout.close()