Core: Move rewind diffing to its own thread
Vicki Pfau vi@endrift.com
Fri, 28 Apr 2017 19:45:52 -0700
5 files changed,
104 insertions(+),
16 deletions(-)
M
CHANGES
→
CHANGES
@@ -110,6 +110,7 @@ - Core: Ability to enumerate and modify video and audio channels
- Debugger: Make attaching a backend idempotent - VFS: Optimize expanding in-memory files - VFS: Add VFileFIFO for operating on circle buffers + - Core: Move rewind diffing to its own thread 0.5.2: (2016-12-31) Bugfixes:
M
include/mgba/core/rewind.h
→
include/mgba/core/rewind.h
@@ -11,6 +11,9 @@
CXX_GUARD_START #include <mgba-util/vector.h> +#ifndef DISABLE_THREADING +#include <mgba-util/threading.h> +#endif DECLARE_VECTOR(mCoreRewindPatches, struct PatchFast);@@ -22,9 +25,16 @@ size_t size;
int stateFlags; struct VFile* previousState; struct VFile* currentState; + +#ifndef DISABLE_THREADING + bool onThread; + Thread thread; + Condition cond; + Mutex mutex; +#endif }; -void mCoreRewindContextInit(struct mCoreRewindContext*, size_t entries); +void mCoreRewindContextInit(struct mCoreRewindContext*, size_t entries, bool onThread); void mCoreRewindContextDeinit(struct mCoreRewindContext*); struct mCore;
M
src/core/rewind.c
→
src/core/rewind.c
@@ -12,7 +12,13 @@ #include <mgba-util/vfs.h>
DEFINE_VECTOR(mCoreRewindPatches, struct PatchFast); -void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries) { +void _rewindDiff(struct mCoreRewindContext* context); + +#ifndef DISABLE_THREADING +THREAD_ENTRY _rewindThread(void* context); +#endif + +void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries, bool onThread) { mCoreRewindPatchesInit(&context->patchMemory, entries); size_t e; for (e = 0; e < entries; ++e) {@@ -22,9 +28,30 @@ context->previousState = VFileMemChunk(0, 0);
context->currentState = VFileMemChunk(0, 0); context->size = 0; context->stateFlags = SAVESTATE_SAVEDATA; +#ifndef DISABLE_THREADING + context->onThread = onThread; + if (onThread) { + MutexInit(&context->mutex); + ConditionInit(&context->cond); + ThreadCreate(&context->thread, _rewindThread, context); + } +#else + UNUSED(onThread); +#endif } void mCoreRewindContextDeinit(struct mCoreRewindContext* context) { +#ifndef DISABLE_THREADING + if (context->onThread) { + MutexLock(&context->mutex); + context->onThread = false; + MutexUnlock(&context->mutex); + ConditionWake(&context->cond); + ThreadJoin(context->thread); + MutexDeinit(&context->mutex); + ConditionDeinit(&context->cond); + } +#endif context->previousState->close(context->previousState); context->currentState->close(context->currentState); size_t s;@@ -35,7 +62,26 @@ mCoreRewindPatchesDeinit(&context->patchMemory);
} void mCoreRewindAppend(struct mCoreRewindContext* context, struct mCore* core) { +#ifndef DISABLE_THREADING + if (context->onThread) { + MutexLock(&context->mutex); + } +#endif struct VFile* nextState = context->previousState; + mCoreSaveStateNamed(core, nextState, context->stateFlags); + context->previousState = context->currentState; + context->currentState = nextState; +#ifndef DISABLE_THREADING + if (context->onThread) { + ConditionWake(&context->cond); + MutexUnlock(&context->mutex); + return; + } +#endif + _rewindDiff(context); +} + +void _rewindDiff(struct mCoreRewindContext* context) { ++context->current; if (context->size < mCoreRewindPatchesSize(&context->patchMemory)) { ++context->size;@@ -43,27 +89,34 @@ }
if (context->current >= mCoreRewindPatchesSize(&context->patchMemory)) { context->current = 0; } - mCoreSaveStateNamed(core, nextState, context->stateFlags); struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current); - size_t size2 = nextState->size(nextState); - size_t size = context->currentState->size(context->currentState); + size_t size2 = context->currentState->size(context->currentState); + size_t size = context->previousState->size(context->previousState); if (size2 > size) { - context->currentState->truncate(context->currentState, size2); + context->previousState->truncate(context->previousState, size2); size = size2; } else if (size > size2) { - nextState->truncate(nextState, size); + context->currentState->truncate(context->currentState, size); } - void* current = context->currentState->map(context->currentState, size, MAP_READ); - void* next = nextState->map(nextState, size, MAP_READ); + void* current = context->previousState->map(context->previousState, size, MAP_READ); + void* next = context->currentState->map(context->currentState, size, MAP_READ); diffPatchFast(patch, current, next, size); - context->currentState->unmap(context->currentState, current, size); - nextState->unmap(next, nextState, size); - context->previousState = context->currentState; - context->currentState = nextState; + context->previousState->unmap(context->previousState, current, size); + context->currentState->unmap(context->currentState, next, size); } bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) { +#ifndef DISABLE_THREADING + if (context->onThread) { + MutexLock(&context->mutex); + } +#endif if (!context->size) { +#ifndef DISABLE_THREADING + if (context->onThread) { + MutexUnlock(&context->mutex); + } +#endif return false; } --context->size;@@ -88,5 +141,29 @@ if (context->current == 0) {
context->current = mCoreRewindPatchesSize(&context->patchMemory); } --context->current; +#ifndef DISABLE_THREADING + if (context->onThread) { + MutexUnlock(&context->mutex); + } +#endif return true; } + +#ifndef DISABLE_THREADING +THREAD_ENTRY _rewindThread(void* context) { + struct mCoreRewindContext* rewindContext = context; + ThreadSetName("Rewind Diff Thread"); + MutexLock(&rewindContext->mutex); + struct VFile* state = rewindContext->currentState; + while (rewindContext->onThread) { + if (rewindContext->currentState != state) { + _rewindDiff(rewindContext); + state = rewindContext->currentState; + } + ConditionWait(&rewindContext->cond, &rewindContext->mutex); + } + MutexUnlock(&rewindContext->mutex); + return 0; +} +#endif +
M
src/core/thread.c
→
src/core/thread.c
@@ -168,7 +168,7 @@ mLogFilterLoad(threadContext->logger.d.filter, &core->config);
} if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) { - mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity); + mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity, true); threadContext->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0; }
M
src/platform/qt/GameController.cpp
→
src/platform/qt/GameController.cpp
@@ -741,8 +741,8 @@ m_threadContext.core->opts.rewindEnable = enable;
m_threadContext.core->opts.rewindBufferCapacity = capacity; m_threadContext.core->opts.rewindSave = rewindSave; if (enable && capacity > 0) { - mCoreRewindContextInit(&m_threadContext.rewind, capacity); - m_threadContext.rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0; + mCoreRewindContextInit(&m_threadContext.rewind, capacity, true); + m_threadContext.rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0; } } }