[Scummvm-cvs-logs] SF.net SVN: scummvm:[49243] scummvm/trunk/backends/fs/psp

Bluddy at users.sourceforge.net Bluddy at users.sourceforge.net
Wed May 26 16:43:25 CEST 2010


Revision: 49243
          http://scummvm.svn.sourceforge.net/scummvm/?rev=49243&view=rev
Author:   Bluddy
Date:     2010-05-26 14:43:25 +0000 (Wed, 26 May 2010)

Log Message:
-----------
PSP: implemented basic file cache. Turns out the PSP reads 1 byte as fast as it reads 1 KB.

Modified Paths:
--------------
    scummvm/trunk/backends/fs/psp/psp-stream.cpp
    scummvm/trunk/backends/fs/psp/psp-stream.h

Modified: scummvm/trunk/backends/fs/psp/psp-stream.cpp
===================================================================
--- scummvm/trunk/backends/fs/psp/psp-stream.cpp	2010-05-26 14:31:51 UTC (rev 49242)
+++ scummvm/trunk/backends/fs/psp/psp-stream.cpp	2010-05-26 14:43:25 UTC (rev 49243)
@@ -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 @@
 		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 @@
 
 	_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,102 +102,179 @@
 
 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;
 	}
+	
+	// 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;
+}
 
-	_pos = ftell((FILE *)_handle);	// update pos
+// 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");
+}*/
 
-	PowerMan.endCriticalSection();
+uint32 PSPIoStream::read(void *ptr, uint32 len) {
+	DEBUG_ENTER_FUNC();
+	PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d], ptr[%p]\n", _path.c_str(), len, ptr);
 
-	return (ret == 0);
-}
+	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
+		}		
+	}
 
-uint32 PSPIoStream::read(void *ptr, uint32 len) {
-	DEBUG_ENTER_FUNC();
-	// Check if we can access the file
 	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
 		PSP_DEBUG_PRINT_FUNC("Suspended\n");
+	
+	
+	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);
 
-	PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len);
+		_physicalPos += ret;	// Update pos
+		_pos = _physicalPos;
 
-	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
+		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) {
 	DEBUG_ENTER_FUNC();
 	// Check if we can access the file
@@ -195,9 +283,17 @@
 
 	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 @@
 	// 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;

Modified: scummvm/trunk/backends/fs/psp/psp-stream.h
===================================================================
--- scummvm/trunk/backends/fs/psp/psp-stream.h	2010-05-26 14:31:51 UTC (rev 49242)
+++ scummvm/trunk/backends/fs/psp/psp-stream.h	2010-05-26 14:43:25 UTC (rev 49243)
@@ -35,25 +35,38 @@
  */
 class PSPIoStream : public StdioStream, public Suspendable {
 protected:
-	Common::String _path;			/* Need to maintain for reopening after suspend */
-	bool _writeMode;				/* "" */
-	int _pos;						/* "" */
-	mutable int _ferror;			/* Save file ferror */
-	mutable bool _feof;						/* and eof */
-
+	Common::String _path;
+	int _fileSize;
+	bool _writeMode;	// for resuming in the right mode
+	int _physicalPos;	// position in the real file
+	int _pos;			// position. Sometimes virtual
+	bool _inCache;		// whether we're in cache (virtual) mode
+	
 	enum {
 		SuspendError = 2,
 		ResumeError = 3
 	};
 
-	int _errorSuspend;
+	enum {
+		CACHE_SIZE = 1024,
+		MIN_READ_SIZE = 1024	// reading less than 1024 takes exactly the same time as 1024
+	};
+	
+	// For caching
+	char *_cache;
+	int _cacheStartOffset;		// starting offset of the cache. -1 when cache is invalid
+	
+	mutable int _ferror;		// file error state
+	int _errorSuspend;			// for debugging
 	mutable int _errorSource;
-
-	// Error checking
 	int _errorPos;
 	void * _errorHandle;
 	int _suspendCount;
 
+	bool synchronizePhysicalPos();		// synchronize the physical and virtual positions
+	bool isOffsetInCache(uint32 pos);	// check if an offset is found in cache
+	bool isCacheValid() { return _cacheStartOffset != -1; }
+	
 public:
 
 	/**


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list