mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
sceKernelLoadModule: Charge for reading the file and loading it
On hardware a load costs an open and a read of the file, plus about 1ms and 30us per KB of loader work (pspautotests threads/scheduling/callcosts), with the caller waiting throughout. It now charges sceIoOpen's and sceIoRead's estimates for the file plus that, instead of a flat 500us. Also notes why sceKernelLoadModuleByID fails from a game's own fd on ms0: or host0: on hardware, which we don't emulate. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
4ba981b5b3
commit
f2eba8f711
3 files changed
+31
-17
No files matched your search
+18
-15
@@ -1053,20 +1053,26 @@ static u32 npdrmRead(FileNode *f, u8 *data, int size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
int __IoOpenDelayUs(const char *filename) {
|
||||
// UMD: Speed varies from 1-6ms.
|
||||
// Card: Path depth matters, but typically between 10-13ms on a standard Pro Duo.
|
||||
return pspFileSystem.FlagsFromFilename(filename) & FileSystemFlags::UMD ? 4000 : 10000;
|
||||
}
|
||||
|
||||
int __IoReadDelayUs(int size) {
|
||||
int us;
|
||||
if (PSP_CoreParameter().compat.flags().ForceUMDReadSpeed || g_Config.iIOTimingMethod == IOTIMING_UMDSLOWREALISTIC) {
|
||||
us = size / 4.2;
|
||||
} else {
|
||||
us = size / 100;
|
||||
}
|
||||
return std::max(us, 100);
|
||||
}
|
||||
|
||||
static bool __IoRead(int &result, int id, u32 data_addr, int size, int &us) {
|
||||
PROFILE_THIS_SCOPE("io_rw");
|
||||
// Low estimate, may be improved later from the ReadFile result.
|
||||
|
||||
if (PSP_CoreParameter().compat.flags().ForceUMDReadSpeed || g_Config.iIOTimingMethod == IOTIMING_UMDSLOWREALISTIC) {
|
||||
us = size / 4.2;
|
||||
}
|
||||
else {
|
||||
us = size / 100;
|
||||
}
|
||||
|
||||
if (us < 100) {
|
||||
us = 100;
|
||||
}
|
||||
us = __IoReadDelayUs(size);
|
||||
|
||||
if (id == PSP_STDIN) {
|
||||
DEBUG_LOG(Log::sceIo, "sceIoRead STDIN");
|
||||
@@ -1641,10 +1647,7 @@ static u32 sceIoOpen(const char *filename, int flags, int mode) {
|
||||
// These are fast to open, no delay or even rescheduling happens.
|
||||
return hleLogDebug(Log::sceIo, id);
|
||||
}
|
||||
// UMD: Speed varies from 1-6ms.
|
||||
// Card: Path depth matters, but typically between 10-13ms on a standard Pro Duo.
|
||||
int delay = pspFileSystem.FlagsFromFilename(filename) & FileSystemFlags::UMD ? 4000 : 10000;
|
||||
return hleDelayResult(hleLogDebug(Log::sceIo, id), "file opened", delay);
|
||||
return hleDelayResult(hleLogDebug(Log::sceIo, id), "file opened", __IoOpenDelayUs(filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,9 @@ u32 sceIoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 ou
|
||||
int __IoIoctl(u32 id, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec);
|
||||
|
||||
u32 __IoGetFileHandleFromId(u32 id, u32 &outError);
|
||||
// What sceIoOpen and sceIoRead charge, for loaders that read whole files without going through them.
|
||||
int __IoOpenDelayUs(const char *filename);
|
||||
int __IoReadDelayUs(int size);
|
||||
void ConvertTmToPspDateTime(ScePspDateTime& date_out, const tm& date_in, int microSeconds);
|
||||
|
||||
KernelObject *__KernelFileNodeObject();
|
||||
|
||||
@@ -2453,6 +2453,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) {
|
||||
const u32 error = hleLogError(Log::Loader, SCE_KERNEL_ERROR_FILEERR, "module file size is 0");
|
||||
return hleDelayResult(error, "module loaded", 500);
|
||||
}
|
||||
const int fileSize = (int)fileData.size();
|
||||
|
||||
// A .sprx installed by a PKG game update comes wrapped in an NPDRM "\0PSPEDAT" container: a
|
||||
// 0x90-byte header naming the content ID, then the payload at the offset in its u16 at 0x0C.
|
||||
@@ -2544,8 +2545,11 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) {
|
||||
INFO_LOG(Log::sceModule,"%i=sceKernelLoadModule(name=%s,flag=%08x,(...))", module->GetUID(), name, flags);
|
||||
}
|
||||
|
||||
// TODO: This is not the right timing and probably not the right wait type, just an approximation.
|
||||
return hleDelayResult(hleNoLog(module->GetUID()), "module loaded", 500);
|
||||
// Opening and reading the file, then about 1ms plus 30us per KB of loader work, the caller waiting
|
||||
// throughout. The loader part is what a load took on hardware beyond an open and a read of the
|
||||
// same file (pspautotests threads/scheduling/callcosts, from an SD card in a memory stick adapter).
|
||||
const int loadUs = __IoOpenDelayUs(name) + __IoReadDelayUs(fileSize) + 1000 + fileSize / 34;
|
||||
return hleDelayResult(hleNoLog(module->GetUID()), "module loaded", loadUs);
|
||||
}
|
||||
|
||||
static u32 sceKernelLoadModuleNpDrm(const char *name, u32 flags, u32 optionAddr) {
|
||||
@@ -2984,6 +2988,10 @@ u32 sceKernelFindModuleByName(const char *name)
|
||||
}
|
||||
|
||||
// The id in question here is a file handle.
|
||||
// On hardware, from a game's own fd on ms0: or host0: this fails with
|
||||
// SCE_KERNEL_ERROR_PROHIBIT_LOADMODULE_DEVICE: the file has to pass a kernel-only ioctl (0x00208001),
|
||||
// which a user fd doesn't (it returns ILLEGAL_PERM). sceKernelLoadModule opens the file itself, so it
|
||||
// passes. Whether a disc0:/umd0: fd passes is untested, so we let every device through.
|
||||
static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) {
|
||||
u32 error;
|
||||
u32 handle = __IoGetFileHandleFromId(id, error);
|
||||
|
||||
Reference in new issue
Block a user