all repos — mgba @ bac0d35034f8e31aec09cfd12676c7b34b0cd38f

mGBA Game Boy Advance Emulator

Enhance perf-main with higher granularity output, optional parseable output and higher granularity duration setting
Jeffrey Pfau jeffrey@endrift.com
Mon, 06 Oct 2014 23:32:26 -0700
commit

bac0d35034f8e31aec09cfd12676c7b34b0cd38f

parent

32bc6750c1d0df840ed81234c330a33ee0142ba4

3 files changed, 64 insertions(+), 25 deletions(-)

jump to
M src/gba/gba.csrc/gba/gba.c

@@ -618,6 +618,10 @@ }

return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0; } +void GBAGetGameCode(struct GBA* gba, char* out) { + memcpy(out, &((struct GBACartridge*) gba->memory.rom)->id, 4); +} + void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) { struct GBA* gba = (struct GBA*) cpu->master; enum GBALogLevel level = GBA_LOG_FATAL;
M src/gba/gba.hsrc/gba/gba.h

@@ -148,6 +148,7 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf);

void GBAApplyPatch(struct GBA* gba, struct Patch* patch); bool GBAIsROM(struct VFile* vf); +void GBAGetGameCode(struct GBA* gba, char* out); __attribute__((format (printf, 3, 4))) void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...);
M src/platform/perf-main.csrc/platform/perf-main.c

@@ -7,18 +7,22 @@ #include <fcntl.h>

#include <signal.h> #include <sys/time.h> -#define PERF_OPTIONS "NS:" +#define PERF_OPTIONS "F:NPS:" #define PERF_USAGE \ "\nBenchmark options:\n" \ + " -F FRAMES Run for the specified number of FRAMES before exiting\n" \ " -N Disable video rendering entirely\n" \ + " -P CSV output, useful for parsing\n" \ " -S SEC Run for SEC in-game seconds before exiting" struct PerfOpts { bool noVideo; - int duration; + bool csv; + unsigned duration; + unsigned frames; }; -static void _GBAPerfRunloop(struct GBAThread* context, int* frames); +static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet); static void _GBAPerfShutdown(int signal); static bool _parsePerfOpts(struct SubParser* parser, int option, const char* arg);

@@ -30,7 +34,7 @@

struct GBAVideoSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer); - struct PerfOpts perfOpts = { false, 0 }; + struct PerfOpts perfOpts = { false, false, 0, 0 }; struct SubParser subparser = { .usage = PERF_USAGE, .parse = _parsePerfOpts,

@@ -58,16 +62,24 @@ context.renderer = &renderer.d;

} context.debugger = createDebugger(&opts); + char gameCode[5] = { 0 }; GBAMapOptionsToContext(&opts, &context); GBAThreadStart(&context); + GBAGetGameCode(context.gba, gameCode); - int frames = perfOpts.duration; - time_t start = time(0); - _GBAPerfRunloop(&context, &frames); - time_t end = time(0); - int duration = end - start; + int frames = perfOpts.frames; + if (!frames) { + frames = perfOpts.duration * 60; + } + struct timeval tv; + gettimeofday(&tv, 0); + uint64_t start = 1000000 * tv.tv_sec + tv.tv_usec; + _GBAPerfRunloop(&context, &frames, perfOpts.csv); + gettimeofday(&tv, 0); + uint64_t end = 1000000 * tv.tv_sec + tv.tv_usec; + uint64_t duration = end - start; GBAThreadJoin(&context); freeOptions(&opts);

@@ -75,12 +87,24 @@ free(context.debugger);

free(renderer.outputBuffer); - printf("%u frames in %i seconds: %g fps (%gx)\n", frames, duration, frames / (float) duration, frames / (duration * 60.f)); + float scaledFrames = frames * 1000000.f; + if (perfOpts.csv) { + puts("game_code,frames,duration,renderer"); + const char* rendererName; + if (perfOpts.noVideo) { + rendererName = "none"; + } else { + rendererName = "software"; + } + printf("%s,%i,%lli,%s\n", gameCode, frames, duration, rendererName); + } else { + printf("%u frames in %lli microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); + } return 0; } -static void _GBAPerfRunloop(struct GBAThread* context, int* frames) { +static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet) { struct timeval lastEcho; gettimeofday(&lastEcho, 0); int duration = *frames;

@@ -90,25 +114,29 @@ while (context->state < THREAD_EXITING) {

if (GBASyncWaitFrameStart(&context->sync, 0)) { ++*frames; ++lastFrames; - struct timeval currentTime; - long timeDiff; - gettimeofday(&currentTime, 0); - timeDiff = currentTime.tv_sec - lastEcho.tv_sec; - timeDiff *= 1000; - timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; - if (timeDiff >= 1000) { - printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); - fflush(stdout); - lastEcho = currentTime; - lastFrames = 0; + if (!quiet) { + struct timeval currentTime; + long timeDiff; + gettimeofday(&currentTime, 0); + timeDiff = currentTime.tv_sec - lastEcho.tv_sec; + timeDiff *= 1000; + timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; + if (timeDiff >= 1000) { + printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); + fflush(stdout); + lastEcho = currentTime; + lastFrames = 0; + } } } GBASyncWaitFrameEnd(&context->sync); - if (*frames == duration * 60) { + if (*frames == duration) { _GBAPerfShutdown(0); } } - printf("\033[2K\r"); + if (!quiet) { + printf("\033[2K\r"); + } } static void _GBAPerfShutdown(int signal) {

@@ -121,11 +149,17 @@

static bool _parsePerfOpts(struct SubParser* parser, int option, const char* arg) { struct PerfOpts* opts = parser->opts; switch (option) { + case 'F': + opts->frames = strtoul(arg, 0, 10); + return !errno; case 'N': opts->noVideo = true; return true; + case 'P': + opts->csv = true; + return true; case 'S': - opts->duration = strtol(arg, 0, 10); + opts->duration = strtoul(arg, 0, 10); return !errno; default: return false;