Compress/decompress memory automatically in trace files
This commit is contained in:
parent
f3832a06c1
commit
0f2f4ab9b6
|
@ -11,6 +11,7 @@ project("xenia-gpu")
|
||||||
"xenia-base",
|
"xenia-base",
|
||||||
"xenia-ui",
|
"xenia-ui",
|
||||||
"xxhash",
|
"xxhash",
|
||||||
|
"zlib",
|
||||||
})
|
})
|
||||||
defines({
|
defines({
|
||||||
})
|
})
|
||||||
|
|
|
@ -150,8 +150,14 @@ void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data,
|
||||||
case TraceCommandType::kMemoryRead: {
|
case TraceCommandType::kMemoryRead: {
|
||||||
auto cmd = reinterpret_cast<const MemoryReadCommand*>(trace_ptr);
|
auto cmd = reinterpret_cast<const MemoryReadCommand*>(trace_ptr);
|
||||||
trace_ptr += sizeof(*cmd);
|
trace_ptr += sizeof(*cmd);
|
||||||
std::memcpy(memory->TranslatePhysical(cmd->base_ptr), trace_ptr,
|
if (cmd->full_length) {
|
||||||
cmd->length);
|
DecompressMemory(trace_ptr, cmd->length,
|
||||||
|
memory->TranslatePhysical(cmd->base_ptr),
|
||||||
|
cmd->full_length);
|
||||||
|
} else {
|
||||||
|
std::memcpy(memory->TranslatePhysical(cmd->base_ptr), trace_ptr,
|
||||||
|
cmd->length);
|
||||||
|
}
|
||||||
trace_ptr += cmd->length;
|
trace_ptr += cmd->length;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,12 +61,14 @@ struct MemoryReadCommand {
|
||||||
TraceCommandType type;
|
TraceCommandType type;
|
||||||
uint32_t base_ptr;
|
uint32_t base_ptr;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
|
uint32_t full_length; // Length after inflation. 0 if not deflated.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryWriteCommand {
|
struct MemoryWriteCommand {
|
||||||
TraceCommandType type;
|
TraceCommandType type;
|
||||||
uint32_t base_ptr;
|
uint32_t base_ptr;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
|
uint32_t full_length; // Length after inflation. 0 if not deflated.
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EventType {
|
enum class EventType {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "xenia/gpu/trace_protocol.h"
|
#include "xenia/gpu/trace_protocol.h"
|
||||||
#include "xenia/memory.h"
|
#include "xenia/memory.h"
|
||||||
|
|
||||||
|
#include "third_party/zlib/zlib.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
@ -148,5 +150,13 @@ void TraceReader::ParseTrace() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TraceReader::DecompressMemory(const uint8_t* src, size_t src_size,
|
||||||
|
uint8_t* dest, size_t dest_size) {
|
||||||
|
uLongf dest_len = uint32_t(dest_size);
|
||||||
|
int ret = uncompress(dest, &dest_len, src, uint32_t(src_size));
|
||||||
|
assert_true(ret >= 0);
|
||||||
|
return ret >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -89,6 +89,8 @@ class TraceReader {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ParseTrace();
|
void ParseTrace();
|
||||||
|
bool DecompressMemory(const uint8_t* src, size_t src_size, uint8_t* dest,
|
||||||
|
size_t dest_size);
|
||||||
|
|
||||||
std::unique_ptr<MappedMemory> mmap_;
|
std::unique_ptr<MappedMemory> mmap_;
|
||||||
const uint8_t* trace_data_ = nullptr;
|
const uint8_t* trace_data_ = nullptr;
|
||||||
|
|
|
@ -9,8 +9,12 @@
|
||||||
|
|
||||||
#include "xenia/gpu/trace_writer.h"
|
#include "xenia/gpu/trace_writer.h"
|
||||||
|
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
|
|
||||||
|
#include "third_party/zlib/zlib.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
@ -22,6 +26,9 @@ TraceWriter::~TraceWriter() = default;
|
||||||
bool TraceWriter::Open(const std::wstring& path) {
|
bool TraceWriter::Open(const std::wstring& path) {
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
|
// Reserve 2 MB of space.
|
||||||
|
tmp_buff_.reserve(1024 * 2048);
|
||||||
|
|
||||||
auto canonical_path = xe::to_absolute_path(path);
|
auto canonical_path = xe::to_absolute_path(path);
|
||||||
auto base_path = xe::find_base_path(canonical_path);
|
auto base_path = xe::find_base_path(canonical_path);
|
||||||
xe::filesystem::CreateFolder(base_path);
|
xe::filesystem::CreateFolder(base_path);
|
||||||
|
@ -109,22 +116,48 @@ void TraceWriter::WriteMemoryRead(uint32_t base_ptr, size_t length) {
|
||||||
if (!file_) {
|
if (!file_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compress = compress_output_ && length > compression_threshold_;
|
||||||
|
|
||||||
auto cmd = MemoryReadCommand({
|
auto cmd = MemoryReadCommand({
|
||||||
TraceCommandType::kMemoryRead, base_ptr, uint32_t(length),
|
TraceCommandType::kMemoryRead, base_ptr, uint32_t(length), 0,
|
||||||
});
|
});
|
||||||
fwrite(&cmd, 1, sizeof(cmd), file_);
|
|
||||||
fwrite(membase_ + base_ptr, 1, length, file_);
|
if (compress) {
|
||||||
|
size_t written = WriteCompressed(membase_ + base_ptr, length);
|
||||||
|
cmd.length = uint32_t(written);
|
||||||
|
cmd.full_length = uint32_t(length);
|
||||||
|
|
||||||
|
fwrite(&cmd, 1, sizeof(cmd), file_);
|
||||||
|
fwrite(tmp_buff_.data(), 1, written, file_);
|
||||||
|
} else {
|
||||||
|
fwrite(&cmd, 1, sizeof(cmd), file_);
|
||||||
|
fwrite(membase_ + base_ptr, 1, length, file_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWriter::WriteMemoryWrite(uint32_t base_ptr, size_t length) {
|
void TraceWriter::WriteMemoryWrite(uint32_t base_ptr, size_t length) {
|
||||||
if (!file_) {
|
if (!file_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool compress = compress_output_ && length > compression_threshold_;
|
||||||
|
|
||||||
auto cmd = MemoryWriteCommand({
|
auto cmd = MemoryWriteCommand({
|
||||||
TraceCommandType::kMemoryWrite, base_ptr, uint32_t(length),
|
TraceCommandType::kMemoryWrite, base_ptr, uint32_t(length), 0,
|
||||||
});
|
});
|
||||||
fwrite(&cmd, 1, sizeof(cmd), file_);
|
|
||||||
fwrite(membase_ + base_ptr, 1, length, file_);
|
if (compress) {
|
||||||
|
size_t written = WriteCompressed(membase_ + base_ptr, length);
|
||||||
|
cmd.length = uint32_t(written);
|
||||||
|
cmd.full_length = uint32_t(length);
|
||||||
|
|
||||||
|
fwrite(&cmd, 1, sizeof(cmd), file_);
|
||||||
|
fwrite(tmp_buff_.data(), 1, written, file_);
|
||||||
|
} else {
|
||||||
|
fwrite(&cmd, 1, sizeof(cmd), file_);
|
||||||
|
fwrite(membase_ + base_ptr, 1, length, file_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceWriter::WriteEvent(EventType event_type) {
|
void TraceWriter::WriteEvent(EventType event_type) {
|
||||||
|
@ -137,5 +170,15 @@ void TraceWriter::WriteEvent(EventType event_type) {
|
||||||
fwrite(&cmd, 1, sizeof(cmd), file_);
|
fwrite(&cmd, 1, sizeof(cmd), file_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t TraceWriter::WriteCompressed(void* buf, size_t length) {
|
||||||
|
tmp_buff_.resize(compressBound(uint32_t(length)));
|
||||||
|
|
||||||
|
uLongf dest_len = (uint32_t)tmp_buff_.size();
|
||||||
|
int ret =
|
||||||
|
compress(tmp_buff_.data(), &dest_len, (uint8_t*)buf, uint32_t(length));
|
||||||
|
assert_true(ret >= 0);
|
||||||
|
return dest_len;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -40,8 +40,14 @@ class TraceWriter {
|
||||||
void WriteEvent(EventType event_type);
|
void WriteEvent(EventType event_type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
size_t WriteCompressed(void* buf, size_t length);
|
||||||
|
|
||||||
uint8_t* membase_;
|
uint8_t* membase_;
|
||||||
FILE* file_;
|
FILE* file_;
|
||||||
|
|
||||||
|
bool compress_output_ = true;
|
||||||
|
size_t compression_threshold_ = 0x1000; // min. number of bytes to compress.
|
||||||
|
std::vector<uint8_t> tmp_buff_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
Loading…
Reference in New Issue