aboutsummaryrefslogtreecommitdiff
path: root/backends/fs/psp/psp-stream.cpp
diff options
context:
space:
mode:
authorYotam Barnoy2010-05-26 14:43:25 +0000
committerYotam Barnoy2010-05-26 14:43:25 +0000
commit8b54efd8a62a68a0544dfc5438c4efe42c0f79f1 (patch)
tree8e4f94dc14dd172d812857cd6b5592fdb7b90a83 /backends/fs/psp/psp-stream.cpp
parentaf8a82aa13f2a316f6a9b4fd857230cbf87c6b1c (diff)
downloadscummvm-rg350-8b54efd8a62a68a0544dfc5438c4efe42c0f79f1.tar.gz
scummvm-rg350-8b54efd8a62a68a0544dfc5438c4efe42c0f79f1.tar.bz2
scummvm-rg350-8b54efd8a62a68a0544dfc5438c4efe42c0f79f1.zip
PSP: implemented basic file cache. Turns out the PSP reads 1 byte as fast as it reads 1 KB.
svn-id: r49243
Diffstat (limited to 'backends/fs/psp/psp-stream.cpp')
-rw-r--r--backends/fs/psp/psp-stream.cpp249
1 files changed, 174 insertions, 75 deletions
diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp
index 8cb7dfea17..d3d6311836 100644
--- a/backends/fs/psp/psp-stream.cpp
+++ b/backends/fs/psp/psp-stream.cpp
@@ -32,28 +32,26 @@
#include <errno.h>
+#define MIN2(a,b) ((a < b) ? a : b)
+#define MIN3(a,b,c) ( (a < b) ? (a < c ? a : c) : (b < c ? b : c) )
+
//#define __PSP_PRINT_TO_FILE__
//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
#include "backends/platform/psp/trace.h"
PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode)
- : StdioStream((void *)1), _path(path), _writeMode(writeMode) {
+ : StdioStream((void *)1), _path(path), _writeMode(writeMode),
+ _ferror(false), _pos(0),
+ _physicalPos(0), _fileSize(0), _inCache(false),
+ _cacheStartOffset(-1), _cache(0),
+ _errorSuspend(0), _errorSource(0),
+ _errorPos(0), _errorHandle(0), _suspendCount(0) {
DEBUG_ENTER_FUNC();
- assert(!path.empty());
+ // assert(!path.empty()); // do we need this?
_handle = (void *)0; // Need to do this since base class asserts not 0.
- _ferror = false;
- _feof = false;
- _pos = 0;
-
- /* for error checking */
- _errorSuspend = 0;
- _errorSource = 0;
- _errorPos = 0;
- _errorHandle = 0;
- _suspendCount = 0;
}
PSPIoStream::~PSPIoStream() {
@@ -63,9 +61,12 @@ PSPIoStream::~PSPIoStream() {
PSP_DEBUG_PRINT_FUNC("Suspended\n");
PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended
- // Must do this before fclose() or resume() will reopen.
+ // Must do this before fclose() or resume() will reopen.
- fclose((FILE *)_handle); // We don't need a critical section(?). Worst case, the handle gets closed on its own
+ fclose((FILE *)_handle); // We don't need a critical section. Worst case, the handle gets closed on its own
+
+ if (_cache)
+ free(_cache);
PowerMan.endCriticalSection();
}
@@ -82,6 +83,16 @@ void *PSPIoStream::open() {
_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); // open
+ if (_handle) {
+ // Get the file size
+ fseek((FILE *)_handle, 0, SEEK_END); // go to the end
+ _fileSize = ftell((FILE *)_handle);
+ fseek((FILE *)_handle, 0, SEEK_SET); // back to the beginning
+
+ // Allocate the cache
+ _cache = (char *)memalign(64, CACHE_SIZE);
+ }
+
PowerMan.registerSuspend(this); // Register with the powermanager to be suspended
PowerMan.endCriticalSection();
@@ -91,100 +102,177 @@ void *PSPIoStream::open() {
bool PSPIoStream::err() const {
DEBUG_ENTER_FUNC();
- if (_ferror)
- PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n",
- _ferror, _errorSource, _errorSuspend, _pos, _errorPos, _errorHandle, _suspendCount);
+ if (_ferror) // We dump since no printing to screen with suspend
+ PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], \
+ _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n",
+ _ferror, _errorSource, _errorSuspend, _pos,
+ _errorPos, _errorHandle, _suspendCount);
return _ferror;
}
void PSPIoStream::clearErr() {
- _ferror = false; // Remove regular error bit
+ _ferror = false;
}
bool PSPIoStream::eos() const {
- return _feof;
+ return (_pos >= _fileSize);
}
int32 PSPIoStream::pos() const {
return _pos;
}
-
int32 PSPIoStream::size() const {
- DEBUG_ENTER_FUNC();
- if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
- PSP_DEBUG_PRINT_FUNC("Suspended\n");
-
- fseek((FILE *)_handle, 0, SEEK_END);
- int32 length = ftell((FILE *)_handle);
- fseek((FILE *)_handle, _pos, SEEK_SET);
-
- if (_pos < 0 || length < 0) { // Check for errors
- _errorSource = 2;
- PSP_ERROR("pos[%d] or length[%d] < 0!\n", _pos, length);
- _ferror = true;
- length = -1; // If our oldPos is bad, we want length to be bad too to signal
- clearerr((FILE *)_handle);
- }
-
- PowerMan.endCriticalSection();
-
- return length;
+ return _fileSize;
}
bool PSPIoStream::seek(int32 offs, int whence) {
DEBUG_ENTER_FUNC();
-
- // Check if we can access the file
- if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
- PSP_DEBUG_PRINT_FUNC("Suspended\n");
-
- int ret = fseek((FILE *)_handle, offs, whence);
-
- if (ret != 0) {
+ PSP_DEBUG_PRINT_FUNC("offset[%d], whence[%d], _pos[%d], _physPos[%d]\n", offs, whence, _pos, _physicalPos);
+ bool success = true;
+
+ int32 posToSearchFor = 0;
+ switch (whence) {
+ case SEEK_CUR:
+ posToSearchFor = _pos;
+ break;
+ case SEEK_END:
+ posToSearchFor = _fileSize; // unsure. Does it take us here or to EOS - 1?
+ break;
+ }
+ posToSearchFor += offs;
+
+ // Check for bad values
+ if (posToSearchFor < 0 || posToSearchFor > _fileSize) {
_ferror = true;
- PSP_ERROR("fseek returned with [%d], non-zero\n", ret);
- clearerr((FILE *)_handle);
- _feof = feof((FILE *)_handle);
- _errorSource = 3;
- } else { // everything ok
- _feof = false; // Reset eof flag since we know it was ok
+ return false;
}
-
- _pos = ftell((FILE *)_handle); // update pos
-
- PowerMan.endCriticalSection();
-
- return (ret == 0);
+
+ // See if we can find it in cache
+ if (isOffsetInCache(posToSearchFor)) {
+ PSP_DEBUG_PRINT("seek offset[%d] found in cache. Cache starts[%d]\n", posToSearchFor, _cacheStartOffset);
+ _inCache = true;
+ } else { // not in cache
+ _inCache = false;
+ }
+ _pos = posToSearchFor;
+ return success;
}
+// for debugging
+/*
+void printBuffer(byte *ptr, uint32 len) {
+ for (int i = 0; i < len; i++) {
+ PSP_INFO_PRINT("%x ", *ptr);
+ ptr++;
+ }
+ PSP_INFO_PRINT("\n");
+}*/
+
uint32 PSPIoStream::read(void *ptr, uint32 len) {
DEBUG_ENTER_FUNC();
- // Check if we can access the file
+ PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d], ptr[%p]\n", _path.c_str(), len, ptr);
+
+ byte *destPtr = (byte *)ptr;
+ uint32 lenFromFile = len; // how much we read from the actual file
+ uint32 lenFromCache = 0; // how much we read from cache
+ uint32 lenRemainingInFile = _fileSize - _pos;
+
+ if (lenFromFile > lenRemainingInFile)
+ lenFromFile = lenRemainingInFile;
+
+ // Are we in cache?
+ if (_inCache && isCacheValid()) {
+ uint32 offsetInCache = _pos - _cacheStartOffset;
+ // We can read at most what's in the cache or the remaining size of the file
+ lenFromCache = MIN2(lenFromFile, CACHE_SIZE - offsetInCache); // unsure
+
+ PSP_DEBUG_PRINT("reading %d bytes from cache to %p. pos[%d] physPos[%d] cacheStart[%d]\n", lenFromCache, destPtr, _pos, _physicalPos, _cacheStartOffset);
+
+ memcpy(destPtr, &_cache[offsetInCache], lenFromCache);
+ _pos += lenFromCache;
+
+ if (lenFromCache < lenFromFile) { // there's more to copy from the file
+ lenFromFile -= lenFromCache;
+ lenRemainingInFile -= lenFromCache; // since we moved pos
+ destPtr += lenFromCache;
+ } else { // we're done
+ // debug
+ //if (len < 10) printBuffer((byte *)ptr, len);
+ return lenFromCache; // how much we actually read
+ }
+ }
+
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
PSP_DEBUG_PRINT_FUNC("Suspended\n");
-
- PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len);
-
- size_t ret = fread((byte *)ptr, 1, len, (FILE *)_handle);
-
- _pos += ret; // Update pos
-
- if (ret != len) { // Check for eof
- _feof = feof((FILE *)_handle);
- if (!_feof) { // It wasn't an eof. Must be an error
+
+
+ synchronizePhysicalPos(); // we need to update our physical position
+
+ if (lenFromFile <= MIN_READ_SIZE) { // We load the cache in case the read is small enough
+ // This optimization is based on the principle that reading 1 byte is as expensive as 1000 bytes
+ uint32 lenToCopyToCache = MIN2((uint32)MIN_READ_SIZE, lenRemainingInFile); // at most remaining file size
+
+ PSP_DEBUG_PRINT("filling cache with %d bytes from physicalPos[%d]. cacheStart[%d], pos[%d], fileSize[%d]\n", lenToCopyToCache, _physicalPos, _cacheStartOffset, _pos, _fileSize);
+
+ size_t ret = fread(_cache, 1, lenToCopyToCache, (FILE *)_handle);
+ if (ret != lenToCopyToCache) {
+ PSP_ERROR("in filling cache, failed to get %d bytes. Only got %d\n", lenToCopyToCache, ret);
+ _ferror = true;
+ clearerr((FILE *)_handle);
+ }
+ _cacheStartOffset = _physicalPos;
+ _inCache = true;
+
+ _physicalPos += ret;
+
+ PSP_DEBUG_PRINT("copying %d bytes from cache to %p\n", lenFromFile, destPtr);
+
+ // Copy to the destination buffer from cache
+ memcpy(destPtr, _cache, lenFromFile);
+ _pos += lenFromFile;
+
+ } else { // Too big for cache. No caching
+ PSP_DEBUG_PRINT("reading %d bytes from file to %p. Pos[%d], physPos[%d]\n", lenFromFile, destPtr, _pos, _physicalPos);
+ size_t ret = fread(destPtr, 1, lenFromFile, (FILE *)_handle);
+
+ _physicalPos += ret; // Update pos
+ _pos = _physicalPos;
+
+ if (ret != lenFromFile) { // error
+ PSP_ERROR("fread returned [%d] instead of len[%d]\n", ret, lenFromFile);
_ferror = true;
clearerr((FILE *)_handle);
- _pos = ftell((FILE *)_handle); // Update our position
- _errorSource = 4;
- PSP_ERROR("fread returned ret[%d] instead of len[%d]\n", ret, len);
+ _errorSource = 4;
}
+ _inCache = false;
}
PowerMan.endCriticalSection();
- return ret;
+ // debug
+ //if (len < 10) printBuffer((byte *)ptr, len);
+ return lenFromCache + lenFromFile; // total of what was copied
+}
+
+// TODO: Test if seeking backwards/forwards has any effect on performance
+inline bool PSPIoStream::synchronizePhysicalPos() {
+ if (_pos != _physicalPos) {
+ if (fseek((FILE *)_handle, _pos - _physicalPos, SEEK_CUR) != 0)
+ return false;
+ _physicalPos = _pos;
+ }
+
+ return true;
+}
+
+inline bool PSPIoStream::isOffsetInCache(uint32 offset) {
+ if (_cacheStartOffset != -1 &&
+ offset >= (uint32)_cacheStartOffset &&
+ offset < (uint32)(_cacheStartOffset + CACHE_SIZE))
+ return true;
+ return false;
}
uint32 PSPIoStream::write(const void *ptr, uint32 len) {
@@ -195,9 +283,17 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) {
PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len);
+ synchronizePhysicalPos();
+
size_t ret = fwrite(ptr, 1, len, (FILE *)_handle);
- _pos += ret;
+ // If we're making the file bigger, adjust the size
+ if (_physicalPos + (int)ret > _fileSize)
+ _fileSize = _physicalPos + ret;
+ _physicalPos += ret;
+ _pos = _physicalPos;
+ _inCache = false;
+ _cacheStartOffset = -1; // invalidate cache
if (ret != len) { // Set error
_ferror = true;
@@ -286,6 +382,9 @@ int PSPIoStream::resume() {
// Resume our previous position
if (_handle > 0 && _pos > 0) {
ret = fseek((FILE *)_handle, _pos, SEEK_SET);
+
+ _physicalPos = _pos;
+ _inCache = false;
if (ret != 0) { // Check for problem
_errorSuspend = ResumeError;