Merge pull request #466 from DrChat/trace_compression

GPU Tracefile Compression
This commit is contained in:
Ben Vanik 2015-11-20 15:12:48 -08:00
commit 4b5d2edbe0
11 changed files with 124 additions and 8 deletions

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
[submodule "third_party/libav"] [submodule "third_party/libav"]
path = third_party/libav path = third_party/libav
url = https://github.com/xenia-project/libav.git url = https://github.com/xenia-project/libav.git
[submodule "third_party/zlib"]
path = third_party/zlib
url = https://github.com/madler/zlib

View File

@ -164,6 +164,7 @@ solution("xenia")
include("third_party/imgui.lua") include("third_party/imgui.lua")
include("third_party/libav.lua") include("third_party/libav.lua")
include("third_party/xxhash.lua") include("third_party/xxhash.lua")
include("third_party/zlib.lua")
include("build_tools/third_party/gflags.lua") include("build_tools/third_party/gflags.lua")
include("src/xenia") include("src/xenia")

View File

@ -11,6 +11,7 @@ project("xenia-gpu")
"xenia-base", "xenia-base",
"xenia-ui", "xenia-ui",
"xxhash", "xxhash",
"zlib",
}) })
defines({ defines({
}) })

View File

@ -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;
} }

View File

@ -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 {

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

1
third_party/zlib vendored Submodule

@ -0,0 +1 @@
Subproject commit 50893291621658f355bc5b4d450a8d06a563053d

41
third_party/zlib.lua vendored Normal file
View File

@ -0,0 +1,41 @@
group("third_party")
project("zlib")
uuid("AF89D75F-F723-47B1-9E29-29CDFA58CCAA")
kind("StaticLib")
language("C")
links({
})
defines({
"_LIB",
})
includedirs({
"zlib",
})
files({
"zlib/adler32.c",
"zlib/compress.c",
"zlib/crc32.c",
"zlib/crc32.h",
"zlib/deflate.c",
"zlib/deflate.h",
"zlib/gzclose.c",
"zlib/gzguts.h",
"zlib/gzlib.c",
"zlib/gzread.c",
"zlib/gzwrite.c",
"zlib/infback.c",
"zlib/inffast.c",
"zlib/inffast.h",
"zlib/inffixed.h",
"zlib/inflate.c",
"zlib/inflate.h",
"zlib/inftrees.c",
"zlib/inftrees.h",
"zlib/trees.c",
"zlib/trees.h",
"zlib/uncompr.c",
"zlib/zconf.h",
"zlib/zlib.h",
"zlib/zutil.c",
"zlib/zutil.h",
})