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(¤tTime, 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}