Merge pull request #7227 from unknownbrackets/io-minor

Add an option to prevent cpu stall on slow IO
This commit is contained in:
Henrik Rydgård committed 2014-12-26 10:25:34 +01:00
commit 442fe9cccc
15 files changed
+302 -67

No files matched your search

+1
View File
@@ -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),
+8
View File
@@ -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;
@@ -109,6 +116,7 @@ public:
// Definitely cannot be changed while game is running.
bool bSeparateCPUThread;
int iIOTimingMethod;
bool bSeparateIOThread;
bool bAtomicAudioLocks;
int iLockedCPUSpeed;
+20
View File
@@ -600,6 +600,11 @@ int DirectoryFileSystem::DevType(u32 handle) {
}
size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
int ignored;
return ReadFile(handle, pointer, size, ignored);
}
size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {
EntryMap::iterator iter = entries.find(handle);
if (iter != entries.end())
{
@@ -613,6 +618,11 @@ size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
}
size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
int ignored;
return WriteFile(handle, pointer, size, ignored);
}
size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) {
EntryMap::iterator iter = entries.find(handle);
if (iter != entries.end())
{
@@ -971,6 +981,11 @@ int VFSFileSystem::DevType(u32 handle) {
}
size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
int ignored;
return ReadFile(handle, pointer, size, ignored);
}
size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {
DEBUG_LOG(FILESYS,"VFSFileSystem::ReadFile %08x %p %i", handle, pointer, (u32)size);
EntryMap::iterator iter = entries.find(handle);
if (iter != entries.end())
@@ -986,6 +1001,11 @@ size_t VFSFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
}
size_t VFSFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
int ignored;
return WriteFile(handle, pointer, size, ignored);
}
size_t VFSFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) {
// NOT SUPPORTED - READ ONLY
return 0;
}
+4
View File
@@ -96,7 +96,9 @@ public:
u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) override;
void CloseFile(u32 handle) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override;
@@ -139,7 +141,9 @@ public:
u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) override;
void CloseFile(u32 handle) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override;
+4
View File
@@ -111,7 +111,9 @@ public:
virtual u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) = 0;
virtual void CloseFile(u32 handle) = 0;
virtual size_t ReadFile(u32 handle, u8 *pointer, s64 size) = 0;
virtual size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) = 0;
virtual size_t WriteFile(u32 handle, const u8 *pointer, s64 size) = 0;
virtual size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) = 0;
virtual size_t SeekFile(u32 handle, s32 position, FileMove type) = 0;
virtual PSPFileInfo GetFileInfo(std::string filename) = 0;
virtual bool OwnsHandle(u32 handle) = 0;
@@ -135,7 +137,9 @@ public:
u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) {return 0;}
void CloseFile(u32 handle) {}
size_t ReadFile(u32 handle, u8 *pointer, s64 size) {return 0;}
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {return 0;}
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) {return 0;}
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) {return 0;}
size_t SeekFile(u32 handle, s32 position, FileMove type) {return 0;}
PSPFileInfo GetFileInfo(std::string filename) {PSPFileInfo f; return f;}
bool OwnsHandle(u32 handle) {return false;}
+31 -2
View File
@@ -227,6 +227,7 @@ void ISOFileSystem::ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root,
{
u8 theSector[2048];
blockDevice->ReadBlock(secnum, theSector);
lastReadBlock_ = secnum;
for (int offset = 0; offset < 2048; )
{
@@ -519,6 +520,12 @@ int ISOFileSystem::DevType(u32 handle)
}
size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
{
int ignored;
return ReadFile(handle, pointer, size, ignored);
}
size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec)
{
EntryMap::iterator iter = entries.find(handle);
if (iter != entries.end())
@@ -529,7 +536,12 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
{
// Whole sectors! Shortcut to this simple code.
blockDevice->ReadBlocks(e.seekPos, (int)size, pointer);
if (abs((int)lastReadBlock_ - (int)e.seekPos) > 100) {
// This is an estimate, sometimes it takes 1+ seconds, but it definitely takes time.
usec = 100000;
}
e.seekPos += (int)size;
lastReadBlock_ = e.seekPos;
return (int)size;
}
@@ -588,6 +600,11 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
}
size_t totalBytes = pointer - start;
if (abs((int)lastReadBlock_ - (int)secNum) > 100) {
// This is an estimate, sometimes it takes 1+ seconds, but it definitely takes time.
usec = 100000;
}
lastReadBlock_ = secNum;
e.seekPos += (unsigned int)totalBytes;
return (size_t)totalBytes;
}
@@ -599,7 +616,13 @@ size_t ISOFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
}
}
size_t ISOFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
size_t ISOFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
{
ERROR_LOG(FILESYS, "Hey, what are you doing? You can't write to an ISO!");
return 0;
}
size_t ISOFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec)
{
ERROR_LOG(FILESYS, "Hey, what are you doing? You can't write to an ISO!");
return 0;
@@ -738,7 +761,7 @@ ISOFileSystem::TreeEntry::~TreeEntry() {
void ISOFileSystem::DoState(PointerWrap &p)
{
auto s = p.Section("ISOFileSystem", 1);
auto s = p.Section("ISOFileSystem", 1, 2);
if (!s)
return;
@@ -794,4 +817,10 @@ void ISOFileSystem::DoState(PointerWrap &p)
}
}
}
if (s >= 2) {
p.Do(lastReadBlock_);
} else {
lastReadBlock_ = 0;
}
}
+11 -1
View File
@@ -37,6 +37,7 @@ public:
u32 OpenFile(std::string filename, FileAccess access, const char *devicename = NULL) override;
void CloseFile(u32 handle) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override;
@@ -46,6 +47,8 @@ public:
u64 FreeSpace(const std::string &path) override { return 0; }
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
bool MkDir(const std::string &dirname) override {return false;}
bool RmDir(const std::string &dirname) override { return false; }
@@ -83,6 +86,7 @@ private:
IHandleAllocator *hAlloc;
TreeEntry *treeroot;
BlockDevice *blockDevice;
u32 lastReadBlock_;
TreeEntry entireISO;
@@ -116,6 +120,9 @@ public:
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override {
return isoFileSystem_->ReadFile(handle, pointer, size);
}
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override {
return isoFileSystem_->ReadFile(handle, pointer, size, usec);
}
size_t SeekFile(u32 handle, s32 position, FileMove type) override {
return isoFileSystem_->SeekFile(handle, position, type);
}
@@ -137,6 +144,9 @@ public:
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override {
return isoFileSystem_->WriteFile(handle, pointer, size);
}
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override {
return isoFileSystem_->WriteFile(handle, pointer, size, usec);
}
bool GetHostPath(const std::string &inpath, std::string &outpath) { return false; }
bool MkDir(const std::string &dirname) override { return false; }
bool RmDir(const std::string &dirname) override { return false; }
@@ -145,4 +155,4 @@ public:
private:
ISOFileSystem *isoFileSystem_;
};
};
+22 -2
View File
@@ -555,7 +555,7 @@ size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size)
lock_guard guard(lock);
IFileSystem *sys = GetHandleOwner(handle);
if (sys)
return sys->ReadFile(handle,pointer,size);
return sys->ReadFile(handle, pointer, size);
else
return 0;
}
@@ -565,7 +565,27 @@ size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
lock_guard guard(lock);
IFileSystem *sys = GetHandleOwner(handle);
if (sys)
return sys->WriteFile(handle,pointer,size);
return sys->WriteFile(handle, pointer, size);
else
return 0;
}
size_t MetaFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec)
{
lock_guard guard(lock);
IFileSystem *sys = GetHandleOwner(handle);
if (sys)
return sys->ReadFile(handle, pointer, size, usec);
else
return 0;
}
size_t MetaFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec)
{
lock_guard guard(lock);
IFileSystem *sys = GetHandleOwner(handle);
if (sys)
return sys->WriteFile(handle, pointer, size, usec);
else
return 0;
}
+2
View File
@@ -96,7 +96,9 @@ public:
u32 OpenWithError(int &error, std::string filename, FileAccess access, const char *devicename = NULL);
void CloseFile(u32 handle) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override { return false; }
+24 -1
View File
@@ -146,7 +146,7 @@ void VirtualDiscFileSystem::LoadFileListIndex() {
void VirtualDiscFileSystem::DoState(PointerWrap &p)
{
auto s = p.Section("VirtualDiscFileSystem", 1);
auto s = p.Section("VirtualDiscFileSystem", 1, 2);
if (!s)
return;
@@ -217,6 +217,12 @@ void VirtualDiscFileSystem::DoState(PointerWrap &p)
}
}
if (s >= 2) {
p.Do(lastReadBlock_);
} else {
lastReadBlock_ = 0;
}
// We don't savestate handlers (loaded on fs load), but if they change, it may not load properly.
}
@@ -422,6 +428,11 @@ size_t VirtualDiscFileSystem::SeekFile(u32 handle, s32 position, FileMove type)
}
size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
int ignored;
return ReadFile(handle, pointer, size, ignored);
}
size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {
EntryMap::iterator iter = entries.find(handle);
if (iter != entries.end())
{
@@ -468,6 +479,12 @@ size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
temp.Close();
iter->second.curOffset += size;
// TODO: This probably isn't enough...
if (abs((int)lastReadBlock_ - (int)iter->second.curOffset) > 100) {
// This is an estimate, sometimes it takes 1+ seconds, but it definitely takes time.
usec = 100000;
}
lastReadBlock_ = iter->second.curOffset;
return size;
}
@@ -701,6 +718,12 @@ size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
return 0;
}
size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec)
{
ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot write to file on virtual disc");
return 0;
}
bool VirtualDiscFileSystem::MkDir(const std::string &dirname)
{
ERROR_LOG(FILESYS,"VirtualDiscFileSystem: Cannot create directory on virtual disc");
+3
View File
@@ -33,6 +33,7 @@ public:
u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
void CloseFile(u32 handle) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override;
@@ -45,6 +46,7 @@ public:
// unsupported operations
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
bool MkDir(const std::string &dirname) override;
bool RmDir(const std::string &dirname) override;
int RenameFile(const std::string &from, const std::string &to) override;
@@ -178,6 +180,7 @@ private:
std::vector<FileListEntry> fileList;
u32 currentBlockIndex;
u32 lastReadBlock_;
std::map<std::string, Handler *> handlers;
};
+94 -52
View File
@@ -173,7 +173,7 @@ public:
}
void DoState(PointerWrap &p) override {
auto s = p.Section("FileNode", 1);
auto s = p.Section("FileNode", 2);
if (!s)
return;
@@ -204,6 +204,9 @@ public:
}
p.Do(waitingThreads);
if (s >= 2) {
p.Do(waitingSyncThreads);
}
p.Do(pausedWaits);
}
@@ -229,6 +232,7 @@ public:
PGD_DESC *pgdInfo;
std::vector<SceUID> waitingThreads;
std::vector<SceUID> waitingSyncThreads;
// Key is the callback id it was for, or if no callback, the thread id.
// Value is actually meaningless but kept for consistency with other wait types.
std::map<SceUID, u64> pausedWaits;
@@ -240,7 +244,7 @@ public:
/******************************************************************************/
void __IoCompleteAsyncIO(int fd);
u64 __IoCompleteAsyncIO(FileNode *f);
static void TellFsThreadEnded (SceUID threadID) {
pspFileSystem.ThreadEnded(threadID);
@@ -279,6 +283,11 @@ static void __IoFreeFd(int fd, u32 &error) {
HLEKernel::ResumeFromWait(f->waitingThreads[i], WAITTYPE_ASYNCIO, f->GetUID(), (int)SCE_KERNEL_ERROR_WAIT_DELETE);
}
CoreTiming::UnscheduleEvent(asyncNotifyEvent, fd);
for (size_t i = 0; i < f->waitingSyncThreads.size(); ++i) {
CoreTiming::UnscheduleEvent(syncNotifyEvent, ((u64)f->waitingSyncThreads[i] << 32) | fd);
}
// Discard any pending results.
AsyncIOResult managerResult;
ioManager.WaitResult(f->handle, managerResult);
@@ -302,10 +311,9 @@ static void __IoFreeFd(int fd, u32 &error) {
// Clearly a buffer is used, it doesn't seem like they are actually kernel objects.
// TODO: We don't do any of that yet.
// For now, let's at least delay the callback mnotification.
// For now, let's at least delay the callback notification.
static void __IoAsyncNotify(u64 userdata, int cyclesLate) {
int fd = (int) userdata;
__IoCompleteAsyncIO(fd);
u32 error;
FileNode *f = __IoGetFd(fd, error);
@@ -314,6 +322,21 @@ 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;
}
} else if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) {
u64 finishTicks = __IoCompleteAsyncIO(f);
if (finishTicks > CoreTiming::GetTicks()) {
// Reschedule for later, since we now know how long it ought to take.
CoreTiming::ScheduleEvent(finishTicks - CoreTiming::GetTicks(), asyncNotifyEvent, userdata);
return;
}
}
if (f->waitingThreads.empty()) {
return;
}
@@ -350,17 +373,36 @@ 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;
}
} else if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) {
u64 finishTicks = ioManager.ResultFinishTicks(f->handle);
if (finishTicks > CoreTiming::GetTicks()) {
// Reschedule for later when the result should finish.
CoreTiming::ScheduleEvent(finishTicks - CoreTiming::GetTicks(), syncNotifyEvent, userdata);
return;
}
}
f->pendingAsyncResult = false;
f->hasAsyncResult = false;
AsyncIOResult managerResult;
if (ioManager.WaitResult(f->handle, managerResult)) {
result = managerResult;
result = managerResult.result;
} else {
ERROR_LOG(SCEIO, "Unable to complete IO operation on %s", f->GetName());
}
f->pendingAsyncResult = false;
f->hasAsyncResult = false;
HLEKernel::ResumeFromWait(threadID, WAITTYPE_IO, fd, result);
f->waitingSyncThreads.erase(std::remove(f->waitingSyncThreads.begin(), f->waitingSyncThreads.end(), threadID), f->waitingSyncThreads.end());
}
static void __IoAsyncBeginCallback(SceUID threadID, SceUID prevCallbackId) {
@@ -567,22 +609,26 @@ 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.
u64 __IoCompleteAsyncIO(FileNode *f) {
if (g_Config.iIOTimingMethod == IOTIMING_REALISTIC) {
u64 finishTicks = ioManager.ResultFinishTicks(f->handle);
if (finishTicks > CoreTiming::GetTicks()) {
return finishTicks;
}
if (f->callbackID) {
__KernelNotifyCallback(f->callbackID, f->callbackArg);
}
f->pendingAsyncResult = false;
f->hasAsyncResult = true;
}
AsyncIOResult managerResult;
if (ioManager.WaitResult(f->handle, managerResult)) {
f->asyncResult = managerResult.result;
} else {
// It's okay, not all operations are deferred.
}
if (f->callbackID) {
__KernelNotifyCallback(f->callbackID, f->callbackArg);
}
f->pendingAsyncResult = false;
f->hasAsyncResult = true;
return 0;
}
void __IoCopyDate(ScePspDateTime& date_out, const tm& date_in)
@@ -709,7 +755,13 @@ static u32 npdrmRead(FileNode *f, u8 *data, int size) {
return size;
}
static bool __IoRead(int &result, int id, u32 data_addr, int size) {
static bool __IoRead(int &result, int id, u32 data_addr, int size, int &us) {
// Low estimate, may be improved later from the ReadFile result.
us = size / 100;
if (us < 100) {
us = 100;
}
if (id == PSP_STDIN) {
DEBUG_LOG(SCEIO, "sceIoRead STDIN");
result = 0; //stdin
@@ -753,7 +805,7 @@ static bool __IoRead(int &result, int id, u32 data_addr, int size) {
ioManager.ScheduleOperation(ev);
return false;
} else {
result = (int) pspFileSystem.ReadFile(f->handle, data, size);
result = (int) pspFileSystem.ReadFile(f->handle, data, size, us);
return true;
}
} else {
@@ -786,19 +838,15 @@ static u32 sceIoRead(int id, u32 data_addr, int size) {
}
}
// TODO: Timing is probably not very accurate, low estimate.
int us = size / 100;
if (us < 100) {
us = 100;
}
int result;
bool complete = __IoRead(result, id, data_addr, size);
int us;
bool complete = __IoRead(result, id, data_addr, size, us);
if (!complete) {
DEBUG_LOG(SCEIO, "sceIoRead(%d, %08x, %x): deferring result", id, data_addr, size);
__IoSchedSync(f, id, us);
__KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io read");
f->waitingSyncThreads.push_back(__KernelGetCurThread());
return 0;
} else if (result >= 0) {
DEBUG_LOG(SCEIO, "%x=sceIoRead(%d, %08x, %x)", result, id, data_addr, size);
@@ -810,12 +858,7 @@ static u32 sceIoRead(int id, u32 data_addr, int size) {
}
static u32 sceIoReadAsync(int id, u32 data_addr, int size) {
// TODO: Not sure what the correct delay is (and technically we shouldn't read into the buffer yet...)
int us = size / 100;
if (us < 100) {
us = 100;
}
// TODO: Technically we shouldn't read into the buffer yet...
u32 error;
FileNode *f = __IoGetFd(id, error);
if (f) {
@@ -824,7 +867,8 @@ static u32 sceIoReadAsync(int id, u32 data_addr, int size) {
return SCE_KERNEL_ERROR_ASYNC_BUSY;
}
int result;
bool complete = __IoRead(result, id, data_addr, size);
int us;
bool complete = __IoRead(result, id, data_addr, size, us);
if (complete) {
f->asyncResult = result;
DEBUG_LOG(SCEIO, "%llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
@@ -839,7 +883,13 @@ static u32 sceIoReadAsync(int id, u32 data_addr, int size) {
}
}
static bool __IoWrite(int &result, int id, u32 data_addr, int size) {
static bool __IoWrite(int &result, int id, u32 data_addr, int size, int &us) {
// Low estimate, may be improved later from the WriteFile result.
us = size / 100;
if (us < 100) {
us = 100;
}
const void *data_ptr = Memory::GetPointer(data_addr);
// Let's handle stdout/stderr specially.
if (id == PSP_STDOUT || id == PSP_STDERR) {
@@ -883,7 +933,7 @@ static bool __IoWrite(int &result, int id, u32 data_addr, int size) {
ioManager.ScheduleOperation(ev);
return false;
} else {
result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size);
result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size, us);
}
return true;
} else {
@@ -907,19 +957,15 @@ static u32 sceIoWrite(int id, u32 data_addr, int size) {
}
}
// TODO: Timing is probably not very accurate, low estimate.
int us = size / 100;
if (us < 100) {
us = 100;
}
int result;
bool complete = __IoWrite(result, id, data_addr, size);
int us;
bool complete = __IoWrite(result, id, data_addr, size, us);
if (!complete) {
DEBUG_LOG(SCEIO, "sceIoWrite(%d, %08x, %x): deferring result", id, data_addr, size);
__IoSchedSync(f, id, us);
__KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io write");
f->waitingSyncThreads.push_back(__KernelGetCurThread());
return 0;
} else if (result >= 0) {
DEBUG_LOG(SCEIO, "%x=sceIoWrite(%d, %08x, %x)", result, id, data_addr, size);
@@ -940,12 +986,7 @@ static u32 sceIoWrite(int id, u32 data_addr, int size) {
}
static u32 sceIoWriteAsync(int id, u32 data_addr, int size) {
// TODO: Not sure what the correct delay is (and technically we shouldn't read from the buffer yet...)
int us = size / 100;
if (us < 100) {
us = 100;
}
// TODO: Technically we shouldn't read from the buffer yet...
u32 error;
FileNode *f = __IoGetFd(id, error);
if (f) {
@@ -954,7 +995,8 @@ static u32 sceIoWriteAsync(int id, u32 data_addr, int size) {
return SCE_KERNEL_ERROR_ASYNC_BUSY;
}
int result;
bool complete = __IoWrite(result, id, data_addr, size);
int us;
bool complete = __IoWrite(result, id, data_addr, size, us);
if (complete) {
f->asyncResult = result;
DEBUG_LOG(SCEIO, "%llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
@@ -1366,7 +1408,7 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o
return ERROR_MEMSTICK_DEVCTL_BAD_PARAMS;
}
break;
// TODO: What does these do? Seem to require a u32 in, no output.
// TODO: What do these do? Seem to require a u32 in, no output.
case 0x01F100A6:
case 0x01F100A8:
case 0x01F100A9:
+49 -7
View File
@@ -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()) {
@@ -59,6 +64,16 @@ bool AsyncIOManager::PopResult(u32 handle, AsyncIOResult &result) {
}
}
bool AsyncIOManager::ReadResult(u32 handle, AsyncIOResult &result) {
lock_guard guard(resultsLock_);
if (results_.find(handle) != results_.end()) {
result = results_[handle];
return true;
} else {
return false;
}
}
bool AsyncIOManager::WaitResult(u32 handle, AsyncIOResult &result) {
lock_guard guard(resultsLock_);
ScheduleEvent(IO_EVENT_SYNC);
@@ -75,6 +90,24 @@ bool AsyncIOManager::WaitResult(u32 handle, AsyncIOResult &result) {
return false;
}
u64 AsyncIOManager::ResultFinishTicks(u32 handle) {
AsyncIOResult result;
lock_guard guard(resultsLock_);
ScheduleEvent(IO_EVENT_SYNC);
while (HasEvents() && ThreadEnabled() && resultsPending_.find(handle) != resultsPending_.end()) {
if (ReadResult(handle, result)) {
return result.finishTicks;
}
resultsWait_.wait_for(resultsLock_, 16);
}
if (ReadResult(handle, result)) {
return result.finishTicks;
}
return 0;
}
void AsyncIOManager::ProcessEvent(AsyncIOEvent ev) {
switch (ev.type) {
case IO_EVENT_READ:
@@ -91,14 +124,15 @@ void AsyncIOManager::ProcessEvent(AsyncIOEvent ev) {
}
void AsyncIOManager::Read(u32 handle, u8 *buf, size_t bytes) {
size_t result = pspFileSystem.ReadFile(handle, buf, bytes);
EventResult(handle, result);
int usec = 0;
s64 result = pspFileSystem.ReadFile(handle, buf, bytes, usec);
EventResult(handle, AsyncIOResult(result, usec));
}
void AsyncIOManager::Write(u32 handle, u8 *buf, size_t bytes) {
// We want to sign extend this on 32-bit.
AsyncIOResult result = (ssize_t)pspFileSystem.WriteFile(handle, buf, bytes);
EventResult(handle, result);
int usec = 0;
s64 result = pspFileSystem.WriteFile(handle, buf, bytes, usec);
EventResult(handle, AsyncIOResult(result, usec));
}
void AsyncIOManager::EventResult(u32 handle, AsyncIOResult result) {
@@ -111,12 +145,20 @@ void AsyncIOManager::EventResult(u32 handle, AsyncIOResult result) {
}
void AsyncIOManager::DoState(PointerWrap &p) {
auto s = p.Section("AsyncIoManager", 1);
auto s = p.Section("AsyncIoManager", 1, 2);
if (!s)
return;
SyncThread();
lock_guard guard(resultsLock_);
p.Do(resultsPending_);
p.Do(results_);
if (s >= 2) {
p.Do(results_);
} else {
std::map<u32, size_t> oldResults;
p.Do(oldResults);
for (auto it = oldResults.begin(), end = oldResults.end(); it != end; ++it) {
results_[it->first] = AsyncIOResult(it->second);
}
}
}
+26 -2
View File
@@ -43,8 +43,29 @@ struct AsyncIOEvent {
}
};
// TODO: Something better.
typedef s64 AsyncIOResult;
struct AsyncIOResult {
AsyncIOResult() : result(0), finishTicks(0) {
}
explicit AsyncIOResult(s64 r) : result(r), finishTicks(0) {
}
AsyncIOResult(s64 r, int usec) : result(r) {
finishTicks = CoreTiming::GetTicks() + usToCycles(usec);
}
void DoState(PointerWrap &p) {
auto s = p.Section("AsyncIOResult", 1);
if (!s)
return;
p.Do(result);
p.Do(finishTicks);
}
s64 result;
u64 finishTicks;
};
typedef ThreadEventQueue<NoBase, AsyncIOEvent, AsyncIOEventType, IO_EVENT_INVALID, IO_EVENT_SYNC, IO_EVENT_FINISH> IOThreadEventQueue;
class AsyncIOManager : public IOThreadEventQueue {
@@ -55,8 +76,11 @@ public:
void ScheduleOperation(AsyncIOEvent ev);
void Shutdown();
bool HasResult(u32 handle);
bool PopResult(u32 handle, AsyncIOResult &result);
bool ReadResult(u32 handle, AsyncIOResult &result);
bool WaitResult(u32 handle, AsyncIOResult &result);
u64 ResultFinishTicks(u32 handle);
protected:
virtual void ProcessEvent(AsyncIOEvent ref);
+3
View File
@@ -392,6 +392,9 @@ void GameSettingsScreen::CreateViews() {
systemSettings->Add(new CheckBox(&g_Config.bSeparateCPUThread, s->T("Multithreaded (experimental)")));
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)", "Simulate UMD delays" };
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