Perf: De-threadify and make compatible with 3DS

This commit is contained in:
Jeffrey Pfau 2016-02-25 23:54:14 -08:00
parent 9919fffcb7
commit 9f6837da42
4 changed files with 96 additions and 77 deletions

View File

@ -45,7 +45,7 @@ file(GLOB GBA_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c)
file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c)
file(GLOB GB_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gb/renderers/*.c) file(GLOB GB_RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gb/renderers/*.c)
file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c) file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c)
list(APPEND GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c) set(CLI_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c)
set(CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c) set(CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c)
set(VFS_SRC) set(VFS_SRC)
source_group("ARM core" FILES ${ARM_SRC}) source_group("ARM core" FILES ${ARM_SRC})
@ -529,7 +529,8 @@ if(NOT MINIMAL_CORE)
${SIO_SRC}) ${SIO_SRC})
endif() endif()
list(APPEND SRC list(APPEND SRC
${FEATURE_SRC}) ${FEATURE_SRC}
${CLI_SRC})
endif() endif()
if(NOT SKIP_LIBRARY) if(NOT SKIP_LIBRARY)
@ -622,13 +623,13 @@ if(BUILD_QT)
endif() endif()
if(BUILD_PERF) if(BUILD_PERF)
set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c) set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c ${CLI_SRC})
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
list(APPEND PERF_LIB rt) list(APPEND PERF_LIB rt)
endif() endif()
add_executable(${BINARY_NAME}-perf ${PERF_SRC}) add_executable(${BINARY_NAME}-perf ${PERF_SRC})
target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB}) target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB} ${OS_LIB})
set_target_properties(${BINARY_NAME}-perf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") set_target_properties(${BINARY_NAME}-perf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
install(TARGETS ${BINARY_NAME}-perf DESTINATION bin COMPONENT ${BINARY_NAME}-perf) install(TARGETS ${BINARY_NAME}-perf DESTINATION bin COMPONENT ${BINARY_NAME}-perf)
install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf)

View File

@ -14,8 +14,9 @@ set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
list(APPEND OS_LIB ctru) list(APPEND OS_LIB ctru)
file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c) file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c ${CMAKE_CURRENT_SOURCE_DIR}/ctru-heap.c)
set(OS_SRC ${OS_SRC} PARENT_SCOPE) set(OS_SRC ${OS_SRC} PARENT_SCOPE)
set(OS_LIB ${OS_LIB} PARENT_SCOPE)
source_group("3DS-specific code" FILES ${OS_SRC}) source_group("3DS-specific code" FILES ${OS_SRC})
if(USE_VFS_3DS) if(USE_VFS_3DS)
@ -45,7 +46,7 @@ set_source_files_properties(
${CMAKE_CURRENT_BINARY_DIR}/uishader.h ${CMAKE_CURRENT_BINARY_DIR}/uishader.h
${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h
PROPERTIES GENERATED ON) PROPERTIES GENERATED ON)
add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c ctru-heap.c) add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c)
set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${OS_LIB}) target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${OS_LIB})
@ -93,6 +94,12 @@ add_custom_target(${BINARY_NAME}.cia ALL
add_custom_target(run ${3DSLINK} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx add_custom_target(run ${3DSLINK} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx
DEPENDS ${BINARY_NAME}.3dsx) DEPENDS ${BINARY_NAME}.3dsx)
if(BUILD_PERF)
add_custom_target(${BINARY_NAME}-perf.3dsx ALL
${3DSXTOOL} ../${BINARY_NAME}-perf ${BINARY_NAME}-perf.3dsx --smdh=${BINARY_NAME}.smdh
DEPENDS ${BINARY_NAME}-perf ${BINARY_NAME}.smdh)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cia.rsf.in ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cia.rsf.in ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf)
install(FILES install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx

View File

@ -25,7 +25,7 @@ set(CMAKE_PROGRAM_PATH ${DEVKITARM}/bin)
set(cross_prefix ${CMAKE_PROGRAM_PATH}/arm-none-eabi-) set(cross_prefix ${CMAKE_PROGRAM_PATH}/arm-none-eabi-)
set(arch_flags "-march=armv6k -mtune=mpcore -mfpu=vfp -mfloat-abi=hard") set(arch_flags "-march=armv6k -mtune=mpcore -mfpu=vfp -mfloat-abi=hard")
set(inc_flags "-I${CTRULIB}/include ${arch_flags} -mword-relocations") set(inc_flags "-I${CTRULIB}/include ${arch_flags} -mword-relocations")
set(link_flags "-L${CTRULIB}/lib -lctru -specs=3dsx.specs ${arch_flags}") set(link_flags "-L${CTRULIB}/lib -specs=3dsx.specs ${arch_flags}")
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name") set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor") set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor")

View File

@ -4,7 +4,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "core/config.h" #include "core/config.h"
#include "core/thread.h"
#include "gba/core.h" #include "gba/core.h"
#include "gba/gba.h" #include "gba/gba.h"
#include "gba/renderers/video-software.h" #include "gba/renderers/video-software.h"
@ -14,6 +13,10 @@
#include "util/string.h" #include "util/string.h"
#include "util/vfs.h" #include "util/vfs.h"
#ifdef _3DS
#include <3ds.h>
#endif
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
@ -37,17 +40,40 @@ struct PerfOpts {
char* savestate; char* savestate;
}; };
static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet); #ifdef _3DS
static void _GBAPerfShutdown(int signal); extern bool allocateRomBuffer(void);
static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg); FS_Archive sdmcArchive;
static void _loadSavestate(struct mCoreThread* context); #endif
static void _mPerfRunloop(struct mCore* context, int* frames, bool quiet);
static void _mPerfShutdown(int signal);
static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg);
static void _log(struct mLogger*, int, enum mLogLevel, const char*, va_list);
static struct mCoreThread* _thread;
static bool _dispatchExiting = false; static bool _dispatchExiting = false;
static struct VFile* _savestate = 0; static struct VFile* _savestate = 0;
int main(int argc, char** argv) { int main(int argc, char** argv) {
signal(SIGINT, _GBAPerfShutdown); #ifdef _3DS
gfxInitDefault();
osSetSpeedupEnable(true);
consoleInit(GFX_BOTTOM, NULL);
if (!allocateRomBuffer()) {
return 1;
}
sdmcArchive = (FS_Archive) {
ARCHIVE_SDMC,
(FS_Path) { PATH_EMPTY, 1, "" },
0
};
FSUSER_OpenArchive(&sdmcArchive);
#else
signal(SIGINT, _mPerfShutdown);
#endif
int didFail = 0;
struct mLogger logger = { .log = _log };
mLogSetDefaultLogger(&logger);
struct PerfOpts perfOpts = { false, false, 0, 0, 0 }; struct PerfOpts perfOpts = { false, false, 0, 0, 0 };
struct mSubParser subparser = { struct mSubParser subparser = {
@ -57,30 +83,26 @@ int main(int argc, char** argv) {
.opts = &perfOpts .opts = &perfOpts
}; };
struct mArguments args; struct mArguments args = {};
bool parsed = parseArguments(&args, argc, argv, &subparser); bool parsed = parseArguments(&args, argc, argv, &subparser);
if (!parsed || args.showHelp) { if (!parsed || args.showHelp) {
usage(argv[0], PERF_USAGE); usage(argv[0], PERF_USAGE);
freeArguments(&args); didFail = !parsed;
return !parsed; goto cleanup;
} }
if (args.showVersion) { if (args.showVersion) {
version(argv[0]); version(argv[0]);
freeArguments(&args); goto cleanup;
return 0;
} }
void* outputBuffer = malloc(256 * 256 * 4); void* outputBuffer = malloc(256 * 256 * 4);
struct mCore* core = mCoreFind(args.fname); struct mCore* core = mCoreFind(args.fname);
if (!core) { if (!core) {
freeArguments(&args); didFail = 1;
return 1; goto cleanup;
} }
struct mCoreThread context = {
.core = core
};
_thread = &context;
if (!perfOpts.noVideo) { if (!perfOpts.noVideo) {
core->setVideoBuffer(core, outputBuffer, 256); core->setVideoBuffer(core, outputBuffer, 256);
@ -89,9 +111,6 @@ int main(int argc, char** argv) {
_savestate = VFileOpen(perfOpts.savestate, O_RDONLY); _savestate = VFileOpen(perfOpts.savestate, O_RDONLY);
free(perfOpts.savestate); free(perfOpts.savestate);
} }
if (_savestate) {
context.startCallback = _loadSavestate;
}
// TODO: Put back debugger // TODO: Put back debugger
char gameCode[5] = { 0 }; char gameCode[5] = { 0 };
@ -110,19 +129,14 @@ int main(int argc, char** argv) {
mCoreConfigLoadDefaults(&core->config, &opts); mCoreConfigLoadDefaults(&core->config, &opts);
mCoreLoadConfig(core); mCoreLoadConfig(core);
int didStart = mCoreThreadStart(&context); core->reset(core);
if (_savestate) {
if (!didStart) { core->loadState(core, _savestate, 0);
goto cleanup; _savestate->close(_savestate);
} _savestate = NULL;
mCoreThreadInterrupt(&context);
if (mCoreThreadHasCrashed(&context)) {
mCoreThreadJoin(&context);
goto cleanup;
} }
GBAGetGameCode(core->board, gameCode); core->getGameCode(core, gameCode);
mCoreThreadContinue(&context);
int frames = perfOpts.frames; int frames = perfOpts.frames;
if (!frames) { if (!frames) {
@ -131,12 +145,12 @@ int main(int argc, char** argv) {
struct timeval tv; struct timeval tv;
gettimeofday(&tv, 0); gettimeofday(&tv, 0);
uint64_t start = 1000000LL * tv.tv_sec + tv.tv_usec; uint64_t start = 1000000LL * tv.tv_sec + tv.tv_usec;
_GBAPerfRunloop(&context, &frames, perfOpts.csv); _mPerfRunloop(core, &frames, perfOpts.csv);
gettimeofday(&tv, 0); gettimeofday(&tv, 0);
uint64_t end = 1000000LL * tv.tv_sec + tv.tv_usec; uint64_t end = 1000000LL * tv.tv_sec + tv.tv_usec;
uint64_t duration = end - start; uint64_t duration = end - start;
mCoreThreadJoin(&context); core->deinit(core);
float scaledFrames = frames * 1000000.f; float scaledFrames = frames * 1000000.f;
if (perfOpts.csv) { if (perfOpts.csv) {
@ -152,49 +166,46 @@ int main(int argc, char** argv) {
printf("%u frames in %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); printf("%u frames in %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f));
} }
cleanup:
if (_savestate) {
_savestate->close(_savestate);
}
mCoreConfigFreeOpts(&opts); mCoreConfigFreeOpts(&opts);
freeArguments(&args);
mCoreConfigDeinit(&core->config); mCoreConfigDeinit(&core->config);
free(outputBuffer); free(outputBuffer);
return !didStart || mCoreThreadHasCrashed(&context); cleanup:
freeArguments(&args);
#ifdef _3DS
gfxExit();
#endif
return didFail;
} }
static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet) { static void _mPerfRunloop(struct mCore* core, int* frames, bool quiet) {
struct timeval lastEcho; struct timeval lastEcho;
gettimeofday(&lastEcho, 0); gettimeofday(&lastEcho, 0);
int duration = *frames; int duration = *frames;
*frames = 0; *frames = 0;
int lastFrames = 0; int lastFrames = 0;
while (context->state < THREAD_EXITING) { while (!_dispatchExiting) {
if (mCoreSyncWaitFrameStart(&context->sync)) { core->runFrame(core);
++*frames; ++*frames;
++lastFrames; ++lastFrames;
if (!quiet) { if (!quiet) {
struct timeval currentTime; struct timeval currentTime;
long timeDiff; long timeDiff;
gettimeofday(&currentTime, 0); gettimeofday(&currentTime, 0);
timeDiff = currentTime.tv_sec - lastEcho.tv_sec; timeDiff = currentTime.tv_sec - lastEcho.tv_sec;
timeDiff *= 1000; timeDiff *= 1000;
timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000;
if (timeDiff >= 1000) { if (timeDiff >= 1000) {
printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f)));
fflush(stdout); fflush(stdout);
lastEcho = currentTime; lastEcho = currentTime;
lastFrames = 0; lastFrames = 0;
}
} }
} }
mCoreSyncWaitFrameEnd(&context->sync);
if (duration > 0 && *frames == duration) { if (duration > 0 && *frames == duration) {
_GBAPerfShutdown(0); break;
}
if (_dispatchExiting) {
mCoreThreadEnd(context);
} }
} }
if (!quiet) { if (!quiet) {
@ -202,11 +213,9 @@ static void _GBAPerfRunloop(struct mCoreThread* context, int* frames, bool quiet
} }
} }
static void _GBAPerfShutdown(int signal) { static void _mPerfShutdown(int signal) {
UNUSED(signal); UNUSED(signal);
// This will come in ON the GBA thread, so we have to handle it carefully
_dispatchExiting = true; _dispatchExiting = true;
ConditionWake(&_thread->sync.videoFrameAvailableCond);
} }
static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg) { static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg) {
@ -233,8 +242,10 @@ static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* ar
} }
} }
static void _loadSavestate(struct mCoreThread* context) { static void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {
context->core->loadState(context->core, _savestate, 0); UNUSED(log);
_savestate->close(_savestate); UNUSED(category);
_savestate = 0; UNUSED(level);
UNUSED(format);
UNUSED(args);
} }