Skip to content

Commit

Permalink
Add an option to prevent cpu stall on slow IO.
Browse files Browse the repository at this point in the history
This is good for any slow storage, including:
  * Hard disk spinning up.
  * Generally slow (cheap) SD cards.
  * HTTP or Samba streaming.

May possibly cause bugs in some cases where timing is unrealistic.  That
being said, as long as the game is a UMD game, and there's caching (could
enable memory caching for storage), it should not be a problem usually.
  • Loading branch information
unknownbrackets committed Dec 26, 2014
1 parent 326c298 commit 5f2fd6f
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 17 deletions.
1 change: 1 addition & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ static ConfigSetting cpuSettings[] = {
ConfigSetting("AtomicAudioLocks", &g_Config.bAtomicAudioLocks, false, true, true),

ReportedConfigSetting("SeparateIOThread", &g_Config.bSeparateIOThread, true, true, true),
ReportedConfigSetting("IOTimingMethod", &g_Config.iIOTimingMethod, IOTIMING_FAST, true, true),
ConfigSetting("FastMemoryAccess", &g_Config.bFastMemory, true, true, true),
ReportedConfigSetting("FuncReplacements", &g_Config.bFuncReplacements, true, true, true),
ReportedConfigSetting("CPUSpeed", &g_Config.iLockedCPUSpeed, 0, true, true),
Expand Down
8 changes: 8 additions & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ enum {
GPU_BACKEND_DIRECT3D9 = 1,
};

// For iIOTimingMethod.
enum IOTimingMethods {
IOTIMING_FAST = 0,
IOTIMING_HOST = 1,
IOTIMING_REALISTIC = 2,
};

namespace http {
class Download;
class Downloader;
Expand Down Expand Up @@ -109,6 +116,7 @@ struct Config {

// Definitely cannot be changed while game is running.
bool bSeparateCPUThread;
int iIOTimingMethod;
bool bSeparateIOThread;
bool bAtomicAudioLocks;
int iLockedCPUSpeed;
Expand Down
47 changes: 30 additions & 17 deletions Core/HLE/sceIo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ class FileNode : public KernelObject {

/******************************************************************************/

void __IoCompleteAsyncIO(int fd);
void __IoCompleteAsyncIO(FileNode *f);

static void TellFsThreadEnded (SceUID threadID) {
pspFileSystem.ThreadEnded(threadID);
Expand Down Expand Up @@ -305,7 +305,6 @@ static void __IoFreeFd(int fd, u32 &error) {
// For now, let's at least delay the callback mnotification.
static void __IoAsyncNotify(u64 userdata, int cyclesLate) {
int fd = (int) userdata;
__IoCompleteAsyncIO(fd);

u32 error;
FileNode *f = __IoGetFd(fd, error);
Expand All @@ -314,6 +313,16 @@ static void __IoAsyncNotify(u64 userdata, int cyclesLate) {
return;
}

if (g_Config.iIOTimingMethod == IOTIMING_HOST) {
if (!ioManager.HasResult(f->handle)) {
// Try again in another 0.5ms until the IO completes on the host.
CoreTiming::ScheduleEvent(usToCycles(500) - cyclesLate, asyncNotifyEvent, userdata);
return;
}
}

__IoCompleteAsyncIO(f);

if (f->waitingThreads.empty()) {
return;
}
Expand Down Expand Up @@ -350,6 +359,14 @@ static void __IoSyncNotify(u64 userdata, int cyclesLate) {
return;
}

if (g_Config.iIOTimingMethod == IOTIMING_HOST) {
if (!ioManager.HasResult(f->handle)) {
// Try again in another 0.5ms until the IO completes on the host.
CoreTiming::ScheduleEvent(usToCycles(500) - cyclesLate, syncNotifyEvent, userdata);
return;
}
}

f->pendingAsyncResult = false;
f->hasAsyncResult = false;

Expand Down Expand Up @@ -567,22 +584,18 @@ static u32 sceKernelStderr() {
return PSP_STDERR;
}

void __IoCompleteAsyncIO(int fd) {
u32 error;
FileNode *f = __IoGetFd(fd, error);
if (f) {
AsyncIOResult managerResult;
if (ioManager.WaitResult(f->handle, managerResult)) {
f->asyncResult = managerResult;
} else {
// It's okay, not all operations are deferred.
}
if (f->callbackID) {
__KernelNotifyCallback(f->callbackID, f->callbackArg);
}
f->pendingAsyncResult = false;
f->hasAsyncResult = true;
void __IoCompleteAsyncIO(FileNode *f) {
AsyncIOResult managerResult;
if (ioManager.WaitResult(f->handle, managerResult)) {
f->asyncResult = managerResult;
} else {
// It's okay, not all operations are deferred.
}
if (f->callbackID) {
__KernelNotifyCallback(f->callbackID, f->callbackArg);
}
f->pendingAsyncResult = false;
f->hasAsyncResult = true;
}

void __IoCopyDate(ScePspDateTime& date_out, const tm& date_in)
Expand Down
5 changes: 5 additions & 0 deletions Core/HW/AsyncIOManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ void AsyncIOManager::Shutdown() {
results_.clear();
}

bool AsyncIOManager::HasResult(u32 handle) {
lock_guard guard(resultsLock_);
return results_.find(handle) != results_.end();
}

bool AsyncIOManager::PopResult(u32 handle, AsyncIOResult &result) {
lock_guard guard(resultsLock_);
if (results_.find(handle) != results_.end()) {
Expand Down
1 change: 1 addition & 0 deletions Core/HW/AsyncIOManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class AsyncIOManager : public IOThreadEventQueue {
void ScheduleOperation(AsyncIOEvent ev);
void Shutdown();

bool HasResult(u32 handle);
bool PopResult(u32 handle, AsyncIOResult &result);
bool WaitResult(u32 handle, AsyncIOResult &result);

Expand Down
3 changes: 3 additions & 0 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,9 @@ void GameSettingsScreen::CreateViews() {

systemSettings->Add(new CheckBox(&g_Config.bSeparateCPUThread, s->T("Multithreaded (experimental)")))->SetEnabled(!PSP_IsInited());
systemSettings->Add(new CheckBox(&g_Config.bSeparateIOThread, s->T("I/O on thread (experimental)")))->SetEnabled(!PSP_IsInited());
static const char *ioTimingMethods[] = { "Fast (lag on slow storage)", "Host (bugs, less lag)" };
View *ioTimingMethod = systemSettings->Add(new PopupMultiChoice(&g_Config.iIOTimingMethod, s->T("IO timing method"), ioTimingMethods, 0, ARRAY_SIZE(ioTimingMethods), s, screenManager()));
ioTimingMethod->SetEnabledPtr(&g_Config.bSeparateIOThread);
systemSettings->Add(new CheckBox(&g_Config.bForceLagSync, s->T("Force real clock sync (slower, less lag)")));
systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, s->T("Change CPU Clock", "Change CPU Clock (0 = default) (unstable)"), screenManager()));
#ifndef MOBILE_DEVICE
Expand Down

0 comments on commit 5f2fd6f

Please sign in to comment.