mirror of https://github.com/mgba-emu/mgba.git
Test: Initial threading work in CInema
This commit is contained in:
parent
51c3fca3bf
commit
6bdae813be
|
@ -13,6 +13,7 @@
|
||||||
#include <mgba-util/png-io.h>
|
#include <mgba-util/png-io.h>
|
||||||
#include <mgba-util/string.h>
|
#include <mgba-util/string.h>
|
||||||
#include <mgba-util/table.h>
|
#include <mgba-util/table.h>
|
||||||
|
#include <mgba-util/threading.h>
|
||||||
#include <mgba-util/vector.h>
|
#include <mgba-util/vector.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
|
@ -32,11 +33,13 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define MAX_TEST 200
|
#define MAX_TEST 200
|
||||||
|
#define MAX_JOBS 128
|
||||||
|
|
||||||
static const struct option longOpts[] = {
|
static const struct option longOpts[] = {
|
||||||
{ "base", required_argument, 0, 'b' },
|
{ "base", required_argument, 0, 'b' },
|
||||||
{ "diffs", no_argument, 0, 'd' },
|
{ "diffs", no_argument, 0, 'd' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ "jobs", required_argument, 0, 'j' },
|
||||||
{ "dry-run", no_argument, 0, 'n' },
|
{ "dry-run", no_argument, 0, 'n' },
|
||||||
{ "outdir", required_argument, 0, 'o' },
|
{ "outdir", required_argument, 0, 'o' },
|
||||||
{ "quiet", no_argument, 0, 'q' },
|
{ "quiet", no_argument, 0, 'q' },
|
||||||
|
@ -46,7 +49,7 @@ static const struct option longOpts[] = {
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char shortOpts[] = "b:dhno:qrv";
|
static const char shortOpts[] = "b:dhj:no:qrv";
|
||||||
|
|
||||||
enum CInemaStatus {
|
enum CInemaStatus {
|
||||||
CI_PASS,
|
CI_PASS,
|
||||||
|
@ -91,8 +94,17 @@ static bool diffs = false;
|
||||||
static bool rebaseline = false;
|
static bool rebaseline = false;
|
||||||
static int verbosity = 0;
|
static int verbosity = 0;
|
||||||
|
|
||||||
|
static struct Table configTree;
|
||||||
|
static Mutex configMutex;
|
||||||
|
|
||||||
|
static int jobs = 1;
|
||||||
|
static size_t jobIndex = 0;
|
||||||
|
static Mutex jobMutex;
|
||||||
|
static Thread jobThreads[MAX_JOBS];
|
||||||
|
static int jobStatus;
|
||||||
|
|
||||||
bool CInemaTestInit(struct CInemaTest*, const char* directory, const char* filename);
|
bool CInemaTestInit(struct CInemaTest*, const char* directory, const char* filename);
|
||||||
void CInemaTestRun(struct CInemaTest*, struct Table* configTree);
|
void CInemaTestRun(struct CInemaTest*);
|
||||||
|
|
||||||
bool CInemaConfigGetUInt(struct Table* configTree, const char* testName, const char* key, unsigned* value);
|
bool CInemaConfigGetUInt(struct Table* configTree, const char* testName, const char* key, unsigned* value);
|
||||||
void CInemaConfigLoad(struct Table* configTree, const char* testName, struct mCore* core);
|
void CInemaConfigLoad(struct Table* configTree, const char* testName, struct mCore* core);
|
||||||
|
@ -142,6 +154,9 @@ static bool parseCInemaArgs(int argc, char* const* argv) {
|
||||||
case 'h':
|
case 'h':
|
||||||
showUsage = true;
|
showUsage = true;
|
||||||
break;
|
break;
|
||||||
|
case 'j':
|
||||||
|
jobs = atoi(optarg);
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
dryRun = true;
|
dryRun = true;
|
||||||
break;
|
break;
|
||||||
|
@ -552,9 +567,11 @@ static void _writeBaseline(struct VDir* dir, const struct CInemaImage* image, si
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInemaTestRun(struct CInemaTest* test, struct Table* configTree) {
|
void CInemaTestRun(struct CInemaTest* test) {
|
||||||
unsigned ignore = 0;
|
unsigned ignore = 0;
|
||||||
CInemaConfigGetUInt(configTree, test->name, "ignore", &ignore);
|
MutexLock(&configMutex);
|
||||||
|
CInemaConfigGetUInt(&configTree, test->name, "ignore", &ignore);
|
||||||
|
MutexUnlock(&configMutex);
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
test->status = CI_SKIP;
|
test->status = CI_SKIP;
|
||||||
return;
|
return;
|
||||||
|
@ -603,11 +620,13 @@ void CInemaTestRun(struct CInemaTest* test, struct Table* configTree) {
|
||||||
unsigned fail = 0;
|
unsigned fail = 0;
|
||||||
unsigned video = 0;
|
unsigned video = 0;
|
||||||
|
|
||||||
CInemaConfigGetUInt(configTree, test->name, "frames", &limit);
|
MutexLock(&configMutex);
|
||||||
CInemaConfigGetUInt(configTree, test->name, "skip", &skip);
|
CInemaConfigGetUInt(&configTree, test->name, "frames", &limit);
|
||||||
CInemaConfigGetUInt(configTree, test->name, "fail", &fail);
|
CInemaConfigGetUInt(&configTree, test->name, "skip", &skip);
|
||||||
CInemaConfigGetUInt(configTree, test->name, "video", &video);
|
CInemaConfigGetUInt(&configTree, test->name, "fail", &fail);
|
||||||
CInemaConfigLoad(configTree, test->name, core);
|
CInemaConfigGetUInt(&configTree, test->name, "video", &video);
|
||||||
|
CInemaConfigLoad(&configTree, test->name, core);
|
||||||
|
MutexUnlock(&configMutex);
|
||||||
|
|
||||||
struct VFile* save = VFileMemChunk(NULL, 0);
|
struct VFile* save = VFileMemChunk(NULL, 0);
|
||||||
core->loadROM(core, rom);
|
core->loadROM(core, rom);
|
||||||
|
@ -825,6 +844,69 @@ void CInemaTestRun(struct CInemaTest* test, struct Table* configTree) {
|
||||||
dir->close(dir);
|
dir->close(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool CInemaTask(struct CInemaTestList* tests, size_t i) {
|
||||||
|
bool success = true;
|
||||||
|
struct CInemaTest* test = CInemaTestListGetPointer(tests, i);
|
||||||
|
if (dryRun) {
|
||||||
|
CIlog(-1, "%s\n", test->name);
|
||||||
|
} else {
|
||||||
|
CIlog(1, "%s: ", test->name);
|
||||||
|
fflush(stdout);
|
||||||
|
CInemaTestRun(test);
|
||||||
|
switch (test->status) {
|
||||||
|
case CI_PASS:
|
||||||
|
CIlog(1, "pass\n");
|
||||||
|
break;
|
||||||
|
case CI_FAIL:
|
||||||
|
success = false;
|
||||||
|
CIlog(1, "fail\n");
|
||||||
|
break;
|
||||||
|
case CI_XPASS:
|
||||||
|
CIlog(1, "xpass\n");
|
||||||
|
break;
|
||||||
|
case CI_XFAIL:
|
||||||
|
CIlog(1, "xfail\n");
|
||||||
|
break;
|
||||||
|
case CI_SKIP:
|
||||||
|
CIlog(1, "skip\n");
|
||||||
|
break;
|
||||||
|
case CI_ERROR:
|
||||||
|
success = false;
|
||||||
|
CIlog(1, "error\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (test->failedFrames) {
|
||||||
|
CIlog(2, "\tfailed frames: %u/%u (%1.3g%%)\n", test->failedFrames, test->totalFrames, test->failedFrames / (test->totalFrames * 0.01));
|
||||||
|
CIlog(2, "\tfailed pixels: %" PRIu64 "/%" PRIu64 " (%1.3g%%)\n", test->failedPixels, test->totalPixels, test->failedPixels / (test->totalPixels * 0.01));
|
||||||
|
CIlog(2, "\tdistance: %" PRIu64 "/%" PRIu64 " (%1.3g%%)\n", test->totalDistance, test->totalPixels * 765, test->totalDistance / (test->totalPixels * 7.65));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static THREAD_ENTRY CInemaJob(void* context) {
|
||||||
|
struct CInemaTestList* tests = context;
|
||||||
|
bool success = true;
|
||||||
|
while (true) {
|
||||||
|
size_t i;
|
||||||
|
MutexLock(&jobMutex);
|
||||||
|
i = jobIndex;
|
||||||
|
++jobIndex;
|
||||||
|
MutexUnlock(&jobMutex);
|
||||||
|
if (i >= CInemaTestListSize(tests)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!CInemaTask(tests, i)) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MutexLock(&jobMutex);
|
||||||
|
if (!success) {
|
||||||
|
jobStatus = 1;
|
||||||
|
}
|
||||||
|
MutexUnlock(&jobMutex);
|
||||||
|
}
|
||||||
|
|
||||||
void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {
|
void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||||
UNUSED(log);
|
UNUSED(log);
|
||||||
if (verbosity < 0) {
|
if (verbosity < 0) {
|
||||||
|
@ -918,48 +1000,31 @@ int main(int argc, char** argv) {
|
||||||
reduceTestList(&tests);
|
reduceTestList(&tests);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Table configTree;
|
|
||||||
HashTableInit(&configTree, 0, free);
|
HashTableInit(&configTree, 0, free);
|
||||||
|
MutexInit(&configMutex);
|
||||||
|
|
||||||
size_t i;
|
if (jobs == 1) {
|
||||||
for (i = 0; i < CInemaTestListSize(&tests); ++i) {
|
size_t i;
|
||||||
struct CInemaTest* test = CInemaTestListGetPointer(&tests, i);
|
for (i = 0; i < CInemaTestListSize(&tests); ++i) {
|
||||||
if (dryRun) {
|
bool success = CInemaTask(&tests, i);
|
||||||
CIlog(-1, "%s\n", test->name);
|
if (!success) {
|
||||||
} else {
|
|
||||||
CIlog(1, "%s: ", test->name);
|
|
||||||
fflush(stdout);
|
|
||||||
CInemaTestRun(test, &configTree);
|
|
||||||
switch (test->status) {
|
|
||||||
case CI_PASS:
|
|
||||||
CIlog(1, "pass\n");
|
|
||||||
break;
|
|
||||||
case CI_FAIL:
|
|
||||||
status = 1;
|
status = 1;
|
||||||
CIlog(1, "fail\n");
|
|
||||||
break;
|
|
||||||
case CI_XPASS:
|
|
||||||
CIlog(1, "xpass\n");
|
|
||||||
break;
|
|
||||||
case CI_XFAIL:
|
|
||||||
CIlog(1, "xfail\n");
|
|
||||||
break;
|
|
||||||
case CI_SKIP:
|
|
||||||
CIlog(1, "skip\n");
|
|
||||||
break;
|
|
||||||
case CI_ERROR:
|
|
||||||
status = 1;
|
|
||||||
CIlog(1, "error\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (test->failedFrames) {
|
|
||||||
CIlog(2, "\tfailed frames: %u/%u (%1.3g%%)\n", test->failedFrames, test->totalFrames, test->failedFrames / (test->totalFrames * 0.01));
|
|
||||||
CIlog(2, "\tfailed pixels: %" PRIu64 "/%" PRIu64 " (%1.3g%%)\n", test->failedPixels, test->totalPixels, test->failedPixels / (test->totalPixels * 0.01));
|
|
||||||
CIlog(2, "\tdistance: %" PRIu64 "/%" PRIu64 " (%1.3g%%)\n", test->totalDistance, test->totalPixels * 765, test->totalDistance / (test->totalPixels * 7.65));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
MutexInit(&jobMutex);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < jobs; ++i) {
|
||||||
|
ThreadCreate(&jobThreads[i], CInemaJob, &tests);
|
||||||
|
}
|
||||||
|
for (i = 0; i < jobs; ++i) {
|
||||||
|
ThreadJoin(&jobThreads[i]);
|
||||||
|
}
|
||||||
|
MutexDeinit(&jobMutex);
|
||||||
|
status = jobStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MutexDeinit(&configMutex);
|
||||||
HashTableEnumerate(&configTree, _unloadConfigTree, NULL);
|
HashTableEnumerate(&configTree, _unloadConfigTree, NULL);
|
||||||
HashTableDeinit(&configTree);
|
HashTableDeinit(&configTree);
|
||||||
CInemaTestListDeinit(&tests);
|
CInemaTestListDeinit(&tests);
|
||||||
|
|
Loading…
Reference in New Issue