Save/memory dumper performance improvements

save_ext
Jonathan G Rennison 6 years ago
parent 3b83a9e186
commit c71ed22e7a

@ -444,13 +444,48 @@ struct ReadBuffer {
/** Container for dumping the savegame (quickly) to memory. */
struct MemoryDumper {
AutoFreeSmallVector<byte *, 16> blocks; ///< Buffer with blocks of allocated memory.
struct BufferInfo {
byte *data;
size_t size = 0;
BufferInfo(byte *d) : data(d) {}
~BufferInfo() { free(this->data); }
BufferInfo(const BufferInfo &) = delete;
BufferInfo(BufferInfo &&other) : data(other.data), size(other.size) { other.data = nullptr; };
};
std::vector<BufferInfo> blocks; ///< Buffer with blocks of allocated memory.
byte *buf; ///< Buffer we're going to write to.
byte *bufe; ///< End of the buffer we write to.
size_t completed_block_bytes; ///< Total byte count of completed blocks
/** Initialise our variables. */
MemoryDumper() : buf(NULL), bufe(NULL)
MemoryDumper() : buf(NULL), bufe(NULL), completed_block_bytes(0)
{
}
void FinaliseBlock()
{
if (!this->blocks.empty()) {
size_t s = MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
this->blocks.back().size = s;
this->completed_block_bytes += s;
}
this->buf = this->bufe = nullptr;
}
void AllocateBuffer()
{
this->FinaliseBlock();
this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
this->blocks.emplace_back(this->buf);
this->bufe = this->buf + MEMORY_CHUNK_SIZE;
}
void CheckBytes(size_t bytes)
{
if (unlikely(this->buf + bytes > this->bufe)) this->AllocateBuffer();
}
/**
@ -460,29 +495,79 @@ struct MemoryDumper {
inline void WriteByte(byte b)
{
/* Are we at the end of this chunk? */
if (this->buf == this->bufe) {
this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
*this->blocks.Append() = this->buf;
this->bufe = this->buf + MEMORY_CHUNK_SIZE;
if (unlikely(this->buf == this->bufe)) {
this->AllocateBuffer();
}
*this->buf++ = b;
}
inline void CopyBytes(byte *ptr, size_t length)
{
while (length) {
if (unlikely(this->buf == this->bufe)) {
this->AllocateBuffer();
}
size_t to_copy = min<size_t>(this->bufe - this->buf, length);
memcpy(this->buf, ptr, to_copy);
this->buf += to_copy;
ptr += to_copy;
length -= to_copy;
}
}
inline void RawWriteUint16(uint16 v)
{
#if OTTD_ALIGNMENT == 0
*((uint16 *) this->buf) = TO_BE16(v);
#else
this->buf[0] = GB(v, 8, 8));
this->buf[1] = GB(v, 0, 8));
#endif
this->buf += 2;
}
inline void RawWriteUint32(uint32 v)
{
#if OTTD_ALIGNMENT == 0
*((uint32 *) this->buf) = TO_BE32(v);
#else
this->buf[0] = GB(v, 24, 8));
this->buf[1] = GB(v, 16, 8));
this->buf[2] = GB(v, 8, 8));
this->buf[3] = GB(v, 0, 8));
#endif
this->buf += 4;
}
inline void RawWriteUint64(uint64 v)
{
#if OTTD_ALIGNMENT == 0
*((uint64 *) this->buf) = TO_BE64(v);
#else
this->buf[0] = GB(v, 56, 8));
this->buf[1] = GB(v, 48, 8));
this->buf[2] = GB(v, 40, 8));
this->buf[3] = GB(v, 32, 8));
this->buf[4] = GB(v, 24, 8));
this->buf[5] = GB(v, 16, 8));
this->buf[6] = GB(v, 8, 8));
this->buf[7] = GB(v, 0, 8));
#endif
this->buf += 8;
}
/**
* Flush this dumper into a writer.
* @param writer The filter we want to use.
*/
void Flush(SaveFilter *writer)
{
uint i = 0;
size_t t = this->GetSize();
while (t > 0) {
size_t to_write = min(MEMORY_CHUNK_SIZE, t);
this->FinaliseBlock();
writer->Write(this->blocks[i++], to_write);
t -= to_write;
uint block_count = this->blocks.size();
for (uint i = 0; i < block_count; i++) {
writer->Write(this->blocks[i].data, this->blocks[i].size);
}
writer->Finish();
@ -494,7 +579,7 @@ struct MemoryDumper {
*/
size_t GetSize() const
{
return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
return this->completed_block_bytes + (this->bufe ? (MEMORY_CHUNK_SIZE - (this->bufe - this->buf)) : 0);
}
};
@ -782,6 +867,24 @@ void SlWriteByte(byte b)
_sl.dumper->WriteByte(b);
}
void SlWriteUint16(uint16 v)
{
_sl.dumper->CheckBytes(2);
_sl.dumper->RawWriteUint16(v);
}
void SlWriteUint32(uint32 v)
{
_sl.dumper->CheckBytes(4);
_sl.dumper->RawWriteUint32(v);
}
void SlWriteUint64(uint64 v)
{
_sl.dumper->CheckBytes(8);
_sl.dumper->RawWriteUint64(v);
}
/**
* Returns number of bytes read so far
* May only be called during a load/load check action
@ -1074,7 +1177,7 @@ static void SlCopyBytes(void *ptr, size_t length)
_sl.reader->CopyBytes(p, length);
break;
case SLA_SAVE:
for (; length != 0; length--) SlWriteByte(*p++);
_sl.dumper->CopyBytes(p, length);
break;
default: NOT_REACHED();
}

@ -683,23 +683,9 @@ int SlReadUint16();
uint32 SlReadUint32();
uint64 SlReadUint64();
static inline void SlWriteUint16(uint16 v)
{
SlWriteByte(GB(v, 8, 8));
SlWriteByte(GB(v, 0, 8));
}
static inline void SlWriteUint32(uint32 v)
{
SlWriteUint16(GB(v, 16, 16));
SlWriteUint16(GB(v, 0, 16));
}
static inline void SlWriteUint64(uint64 x)
{
SlWriteUint32((uint32)(x >> 32));
SlWriteUint32((uint32)x);
}
void SlWriteUint16(uint16 v);
void SlWriteUint32(uint32 v);
void SlWriteUint64(uint64 v);
void SlSkipBytes(size_t length);

Loading…
Cancel
Save