all repos — mgba @ f62ccde49d484c65b212ae86299f4720c9dc836d

mGBA Game Boy Advance Emulator

src/platform/perf-main.c (view raw)

  1#include "gba-thread.h"
  2#include "gba.h"
  3#include "renderers/video-software.h"
  4
  5#include <errno.h>
  6#include <fcntl.h>
  7#include <signal.h>
  8#include <sys/time.h>
  9
 10#define PERF_OPTIONS "S:"
 11#define PERF_USAGE \
 12	"\nBenchmark options:\n" \
 13	"  -S SEC           Run for SEC in-game seconds before exiting"
 14
 15struct PerfOpts {
 16	int duration;
 17};
 18
 19static void _GBAPerfRunloop(struct GBAThread* context, int* frames);
 20static void _GBAPerfShutdown(int signal);
 21static int _parsePerfOpts(struct SubParser* parser, int option, const char* arg);
 22
 23static struct GBAThread* _thread;
 24
 25int main(int argc, char** argv) {
 26	signal(SIGINT, _GBAPerfShutdown);
 27
 28	struct GBAVideoSoftwareRenderer renderer;
 29	GBAVideoSoftwareRendererCreate(&renderer);
 30
 31	struct PerfOpts perfOpts = { 0 };
 32	struct SubParser subparser = {
 33		.usage = PERF_USAGE,
 34		.parse = _parsePerfOpts,
 35		.extraOptions = PERF_OPTIONS,
 36		.opts = &perfOpts
 37	};
 38
 39	struct StartupOptions opts;
 40	if (!parseCommandArgs(&opts, argc, argv, &subparser)) {
 41		usage(argv[0], PERF_USAGE);
 42		return 1;
 43	}
 44
 45	renderer.outputBuffer = malloc(256 * 256 * 4);
 46	renderer.outputBufferStride = 256;
 47
 48	struct GBAThread context = {
 49		.renderer = &renderer.d,
 50		.sync.videoFrameWait = 0,
 51		.sync.audioWait = 0
 52	};
 53	_thread = &context;
 54
 55	context.debugger = createDebugger(&opts);
 56
 57	GBAMapOptionsToContext(&opts, &context);
 58
 59	GBAThreadStart(&context);
 60
 61	int frames = perfOpts.duration;
 62	time_t start = time(0);
 63	_GBAPerfRunloop(&context, &frames);
 64	time_t end = time(0);
 65	int duration = end - start;
 66
 67	GBAThreadJoin(&context);
 68	freeOptions(&opts);
 69	free(context.debugger);
 70
 71	free(renderer.outputBuffer);
 72
 73	printf("%u frames in %i seconds: %g fps (%gx)\n", frames, duration, frames / (float) duration, frames / (duration * 60.f));
 74
 75	return 0;
 76}
 77
 78static void _GBAPerfRunloop(struct GBAThread* context, int* frames) {
 79	struct timeval lastEcho;
 80	gettimeofday(&lastEcho, 0);
 81	int duration = *frames;
 82	*frames = 0;
 83	int lastFrames = 0;
 84	while (context->state < THREAD_EXITING) {
 85		if (GBASyncWaitFrameStart(&context->sync, 0)) {
 86			++*frames;
 87			++lastFrames;
 88			struct timeval currentTime;
 89			long timeDiff;
 90			gettimeofday(&currentTime, 0);
 91			timeDiff = currentTime.tv_sec - lastEcho.tv_sec;
 92			timeDiff *= 1000;
 93			timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000;
 94			if (timeDiff >= 1000) {
 95				printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f)));
 96				fflush(stdout);
 97				lastEcho = currentTime;
 98				lastFrames = 0;
 99			}
100		}
101		GBASyncWaitFrameEnd(&context->sync);
102		if (*frames == duration * 60) {
103			_GBAPerfShutdown(0);
104		}
105	}
106	printf("\033[2K\r");
107}
108
109static void _GBAPerfShutdown(int signal) {
110	UNUSED(signal);
111	pthread_mutex_lock(&_thread->stateMutex);
112	_thread->state = THREAD_EXITING;
113	pthread_mutex_unlock(&_thread->stateMutex);
114}
115
116static int _parsePerfOpts(struct SubParser* parser, int option, const char* arg) {
117	struct PerfOpts* opts = parser->opts;
118	switch (option) {
119	case 'S':
120		opts->duration = strtol(arg, 0, 10);
121		return !errno;
122	default:
123		return 0;
124	}
125}