Attempt to speed up drive reading by doing larger block reads - didn't help very much. we need to support async reads, I think.

Also delete some copypasta in DriveBlob - it already inherits those functions so it doesn't need them itself.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2368 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard
2009-02-22 16:48:54 +00:00
parent 42a7d2fc85
commit e3d1704979
5 changed files with 68 additions and 70 deletions

View File

@ -719,7 +719,7 @@
> >
</File> </File>
<Filter <Filter
Name="Filemapping" Name="Blob"
> >
<File <File
RelativePath=".\Src\Blob.cpp" RelativePath=".\Src\Blob.cpp"

View File

@ -41,11 +41,12 @@ void SectorReader::SetSectorSize(int blocksize)
SectorReader::~SectorReader() { SectorReader::~SectorReader() {
for (int i = 0; i < CACHE_SIZE; i++) for (int i = 0; i < CACHE_SIZE; i++)
delete[] cache[i]; delete [] cache[i];
} }
const u8 *SectorReader::GetBlockData(u64 block_num) const u8 *SectorReader::GetBlockData(u64 block_num)
{ {
// TODO : Expand usage of the cache to more than one block :P
if (cache_tags[0] == block_num) if (cache_tags[0] == block_num)
{ {
return cache[0]; return cache[0];
@ -68,19 +69,33 @@ bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr)
while (remain > 0) while (remain > 0)
{ {
const u8* data = GetBlockData(block); // Check if we are ready to do a large block read. > instead of >= so we don't bother if remain is only one block.
if (!data) if (positionInBlock == 0 && remain > m_blocksize)
return false; {
u64 num_blocks = remain / m_blocksize;
ReadMultipleAlignedBlocks(block, num_blocks, out_ptr);
block += num_blocks;
out_ptr += num_blocks * m_blocksize;
remain -= num_blocks * m_blocksize;
}
u32 toCopy = m_blocksize - positionInBlock; u32 toCopy = m_blocksize - positionInBlock;
if (toCopy >= remain) if (toCopy >= remain)
{ {
// yay, we are done! const u8* data = GetBlockData(block);
if (!data)
return false;
// Yay, we are done!
memcpy(out_ptr, data + positionInBlock, (size_t)remain); memcpy(out_ptr, data + positionInBlock, (size_t)remain);
return true; return true;
} }
else else
{ {
const u8* data = GetBlockData(block);
if (!data)
return false;
memcpy(out_ptr, data + positionInBlock, toCopy); memcpy(out_ptr, data + positionInBlock, toCopy);
out_ptr += toCopy; out_ptr += toCopy;
remain -= toCopy; remain -= toCopy;
@ -91,10 +106,21 @@ bool SectorReader::Read(u64 offset, u64 size, u8* out_ptr)
return true; return true;
} }
bool SectorReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr)
{
for (int i = 0; i < num_blocks; i++)
{
const u8 *data = GetBlockData(block_num + i);
if (!data)
return false;
memcpy(out_ptr, data, m_blocksize);
}
return true;
}
IBlobReader* CreateBlobReader(const char* filename) IBlobReader* CreateBlobReader(const char* filename)
{ {
if(File::IsDisk(filename)) if (File::IsDisk(filename))
return DriveReader::Create(filename); return DriveReader::Create(filename);
if (!File::Exists(filename)) if (!File::Exists(filename))

View File

@ -25,7 +25,7 @@
// allow random access. Or you may store them on an odd device, like raw on a DVD. // allow random access. Or you may store them on an odd device, like raw on a DVD.
// Always read your BLOBs using an interface returned by CreateBlobReader(). It will // Always read your BLOBs using an interface returned by CreateBlobReader(). It will
// detect whether the file is a compressed blob, or just a big hunk of data, and // detect whether the file is a compressed blob, or just a big hunk of data, or a drive, and
// automatically do the right thing. // automatically do the right thing.
#include "Common.h" #include "Common.h"
@ -49,33 +49,41 @@ protected:
// Provides caching and split-operation-to-block-operations facilities. // Provides caching and split-operation-to-block-operations facilities.
// Used for compressed blob reading and direct drive reading. // Used for compressed blob reading and direct drive reading.
// Currently only uses a single entry cache.
// Multi-block reads are not cached.
class SectorReader : public IBlobReader class SectorReader : public IBlobReader
{ {
private: private:
virtual void GetBlock(u64 block_num, u8 *out) = 0;
enum { CACHE_SIZE = 32 }; enum { CACHE_SIZE = 32 };
int m_blocksize; int m_blocksize;
u8* cache[CACHE_SIZE]; u8* cache[CACHE_SIZE];
u64 cache_tags[CACHE_SIZE]; u64 cache_tags[CACHE_SIZE];
int cache_age[CACHE_SIZE]; int cache_age[CACHE_SIZE];
protected: protected:
void SetSectorSize(int blocksize); void SetSectorSize(int blocksize);
virtual void GetBlock(u64 block_num, u8 *out) = 0;
// This one is uncached. The default implementation is to simply call GetBlockData multiple times and memcpy.
virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr);
public: public:
~SectorReader(); virtual ~SectorReader();
// A pointer returned by GetBlockData is invalidated as soon as GetBlockData, Read, or ReadMultipleAlignedBlocks is called again.
const u8 *GetBlockData(u64 block_num); const u8 *GetBlockData(u64 block_num);
bool Read(u64 offset, u64 size, u8* out_ptr); virtual bool Read(u64 offset, u64 size, u8 *out_ptr);
friend class DriveReader; friend class DriveReader;
}; };
// Factory function - examines the path to choose the right type of IBlobReader, and returns one. // Factory function - examines the path to choose the right type of IBlobReader, and returns one.
IBlobReader* CreateBlobReader(const char* filename); IBlobReader* CreateBlobReader(const char *filename);
typedef void (*CompressCB)(const char* text, float percent, void* arg); typedef void (*CompressCB)(const char *text, float percent, void* arg);
bool CompressFileToBlob(const char* infile, const char* outfile, u32 sub_type = 0, int sector_size = 16384, bool CompressFileToBlob(const char *infile, const char *outfile, u32 sub_type = 0, int sector_size = 16384,
CompressCB callback = 0, void* arg = 0); CompressCB callback = 0, void *arg = 0);
bool DecompressBlobToFile(const char* infile, const char* outfile, bool DecompressBlobToFile(const char *infile, const char *outfile,
CompressCB callback = 0, void* arg = 0); CompressCB callback = 0, void *arg = 0);
} // namespace } // namespace

View File

@ -49,7 +49,7 @@ namespace DiscIO
#else #else
file_ = fopen(drive, "rb"); file_ = fopen(drive, "rb");
if (!file_) if (!file_)
PanicAlert("Load from DVD backup failed"); PanicAlert("Load from DVD backup failed");
else else
SetSectorSize(2048); SetSectorSize(2048);
#endif #endif
@ -69,46 +69,13 @@ namespace DiscIO
#else #else
fclose(file_); fclose(file_);
#endif #endif
} // DriveReader::~DriveReader }
DriveReader * DriveReader::Create(const char *drive) DriveReader * DriveReader::Create(const char *drive)
{ {
return new DriveReader(drive); return new DriveReader(drive);
} }
bool DriveReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
{
u64 startingBlock = offset / m_blocksize;
u64 remain = nbytes;
int positionInBlock = (int)(offset % m_blocksize);
u64 block = startingBlock;
while (remain > 0)
{
const u8* data = GetBlockData(block);
if (!data)
return false;
u32 toCopy = m_blocksize - positionInBlock;
if (toCopy >= remain)
{
// yay, we are done!
memcpy(out_ptr, data + positionInBlock, (size_t)remain);
return true;
}
else
{
memcpy(out_ptr, data + positionInBlock, toCopy);
out_ptr += toCopy;
remain -= toCopy;
positionInBlock = 0;
block++;
}
}
return true;
} // DriveReader::Read
void DriveReader::GetBlock(u64 block_num, u8 *out_ptr) void DriveReader::GetBlock(u64 block_num, u8 *out_ptr)
{ {
u32 NotUsed; u32 NotUsed;
@ -124,23 +91,24 @@ namespace DiscIO
fseek(file_, m_blocksize*block_num, SEEK_SET); fseek(file_, m_blocksize*block_num, SEEK_SET);
fread(lpSector, 1, m_blocksize, file_); fread(lpSector, 1, m_blocksize, file_);
#endif #endif
memcpy(out_ptr, lpSector, m_blocksize); memcpy(out_ptr, lpSector, m_blocksize);
delete lpSector; delete lpSector;
} }
const u8 *DriveReader::GetBlockData(u64 block_num) bool DriveReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr)
{ {
if (SectorReader::cache_tags[0] == block_num) u32 NotUsed;
{ #ifdef _WIN32
return SectorReader::cache[0]; u64 offset = m_blocksize * block_num;
} LONG off_low = (LONG)offset & 0xFFFFFFFF;
else LONG off_high = (LONG)(offset >> 32);
{ SetFilePointer(hDisc, off_low, &off_high, FILE_BEGIN);
GetBlock(block_num, cache[0]); if (!ReadFile(hDisc, out_ptr, (DWORD)(m_blocksize * num_blocks), (LPDWORD)&NotUsed, NULL))
SectorReader::cache_tags[0] = block_num; PanicAlert("DRE");
return SectorReader::cache[0]; #else
} fseek(file_, m_blocksize*block_num, SEEK_SET);
fread(out_ptr, 1, m_blocksize * num_blocks, file_);
#endif
return true;
} }
} // namespace } // namespace

View File

@ -48,14 +48,10 @@ public:
~DriveReader(); ~DriveReader();
u64 GetDataSize() const { return size; } u64 GetDataSize() const { return size; }
u64 GetRawSize() const { return size; } u64 GetRawSize() const { return size; }
bool Read(u64 offset, u64 nbytes, u8* out_ptr);
const u8 *GetBlockData(u64 block_num);
virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr);
}; };
} // namespace } // namespace
#endif // _DRIVE_BLOB_H #endif // _DRIVE_BLOB_H