Add a debug-only mode to log everything going through a serialiser

* We also allow structured export on write, again in debug builds only
This commit is contained in:
baldurk
2019-10-29 16:42:48 +00:00
parent 253194c9a1
commit 14bc99947c
2 changed files with 115 additions and 7 deletions
+95 -1
View File
@@ -29,11 +29,58 @@
#include "core/core.h"
#include "strings/string_utils.h"
#if !defined(RELEASE)
#if ENABLED(RDOC_DEVEL)
int64_t Chunk::m_LiveChunks = 0;
int64_t Chunk::m_TotalMem = 0;
void DumpObject(FileIO::LogFileHandle *log, const rdcstr &indent, SDObject *obj)
{
if(obj->NumChildren() > 0)
{
std::string msg =
StringFormat::Fmt("%s%s%s %s:\n", indent.c_str(), obj->type.name.c_str(),
obj->type.basetype == SDBasic::Array ? "[]" : "", obj->name.c_str());
FileIO::logfile_append(log, msg.c_str(), msg.size());
for(size_t i = 0; i < obj->NumChildren(); i++)
DumpObject(log, indent + " ", obj->GetChild(i));
}
else
{
rdcstr val;
switch(obj->type.basetype)
{
case SDBasic::Chunk: val = "{Chunk}"; break;
case SDBasic::Struct: val = "{Struct}"; break;
case SDBasic::Array:
// this must be an empty array, or it would have children above
val = "{}";
break;
case SDBasic::Buffer: val = "[buffer]"; break;
case SDBasic::Null: val = "NULL"; break;
case SDBasic::String: val = obj->data.str; break;
case SDBasic::Enum: val = obj->data.str; break;
case SDBasic::UnsignedInteger: val = ToStr(obj->data.basic.u); break;
case SDBasic::SignedInteger: val = ToStr(obj->data.basic.i); break;
case SDBasic::Float: val = ToStr(obj->data.basic.d); break;
case SDBasic::Boolean: val = ToStr(obj->data.basic.b); break;
case SDBasic::Character: val = ToStr(obj->data.basic.c); break;
case SDBasic::Resource: val = ToStr(obj->data.basic.id); break;
}
std::string msg = StringFormat::Fmt("%s%s %s = %s\n", indent.c_str(), obj->type.name.c_str(),
obj->name.c_str(), val.c_str());
FileIO::logfile_append(log, msg.c_str(), msg.size());
}
}
void DumpChunk(bool reading, FileIO::LogFileHandle *log, SDChunk *chunk)
{
std::string msg = StringFormat::Fmt("%s %s @ %llu:\n", reading ? "Read" : "Wrote",
chunk->name.c_str(), chunk->metadata.timestampMicro);
FileIO::logfile_append(log, msg.c_str(), msg.size());
DumpObject(log, " ", chunk);
}
#endif
/////////////////////////////////////////////////////////////
@@ -217,6 +264,13 @@ void Serialiser<SerialiserMode::Reading>::EndChunk()
m_StructureStack.back()->type.byteSize = m_ChunkMetadata.length;
m_StructureStack.pop_back();
}
#if ENABLED(RDOC_DEVEL)
if(m_DebugDumpLog && !m_StructuredFile->chunks.empty())
{
DumpChunk(true, m_DebugDumpLog, m_StructuredFile->chunks.back());
}
#endif
}
// only skip remaining bytes if we have a valid length - if we have a length of 0 we wrote this
@@ -379,6 +433,22 @@ uint32_t Serialiser<SerialiserMode::Writing>::BeginChunk(uint32_t chunkID, uint6
}
}
if(ExportStructure())
{
std::string name = m_ChunkLookup ? m_ChunkLookup(chunkID) : "";
if(name.empty())
name = "<Unknown Chunk>";
SDChunk *chunk = new SDChunk(name.c_str());
chunk->metadata = m_ChunkMetadata;
m_StructuredFile->chunks.push_back(chunk);
m_StructureStack.push_back(chunk);
m_InternalElement = false;
}
return chunkID;
}
@@ -409,6 +479,8 @@ void Serialiser<SerialiserMode::Writing>::EndChunk()
}
m_Write->WriteAt(chunkOffset, uint32_t(chunkLength & 0xffffffff));
m_ChunkMetadata.length = chunkLength;
}
else
{
@@ -443,6 +515,25 @@ void Serialiser<SerialiserMode::Writing>::EndChunk()
}
}
if(ExportStructure())
{
RDCASSERTMSG("Object Stack is imbalanced!", m_StructureStack.size() <= 1,
m_StructureStack.size());
if(!m_StructureStack.empty())
{
m_StructureStack.back()->type.byteSize = m_ChunkMetadata.length;
m_StructureStack.pop_back();
}
#if ENABLED(RDOC_DEVEL)
if(m_DebugDumpLog && !m_StructuredFile->chunks.empty())
{
DumpChunk(false, m_DebugDumpLog, m_StructuredFile->chunks.back());
}
#endif
}
// align to the natural chunk alignment
m_Write->AlignTo<ChunkAlignment>();
@@ -562,6 +653,8 @@ rdcstr DoStringise(const SDTypeFlags &el)
STRINGISE_BITFIELD_CLASS_BIT(Hidden);
STRINGISE_BITFIELD_CLASS_BIT(Nullable);
STRINGISE_BITFIELD_CLASS_BIT(NullString);
STRINGISE_BITFIELD_CLASS_BIT(FixedArray);
STRINGISE_BITFIELD_CLASS_BIT(Union);
}
END_BITFIELD_STRINGISE();
}
@@ -574,6 +667,7 @@ rdcstr DoStringise(const SDChunkFlags &el)
STRINGISE_BITFIELD_CLASS_VALUE(NoFlags);
STRINGISE_BITFIELD_CLASS_BIT(OpaqueChunk);
STRINGISE_BITFIELD_CLASS_BIT(HasCallstack);
}
END_BITFIELD_STRINGISE();
}
+20 -6
View File
@@ -90,7 +90,13 @@ public:
static constexpr bool IsWriting() { return sertype == SerialiserMode::Writing; }
bool ExportStructure() const
{
return sertype == SerialiserMode::Reading && m_ExportStructured && !m_InternalElement;
// in debug builds, allow structured export during write for debugging. In release, only allow
// it on read to compile out the extra code on the writing path
return
#if ENABLED(RDOC_RELEASE)
sertype == SerialiserMode::Reading &&
#endif
m_ExportStructured && !m_InternalElement;
}
enum ChunkFlags
@@ -116,6 +122,11 @@ public:
uint32_t GetChunkMetadataRecording() { return m_ChunkFlags; }
void SetChunkMetadataRecording(uint32_t flags);
// debug-only option to dump out (roughly) the data going through the serialiser as it happens
#if ENABLED(RDOC_DEVEL)
void EnableDumping(FileIO::LogFileHandle *debugLog) { m_DebugDumpLog = debugLog; }
#endif
SDChunkMetaData &ChunkMetadata() { return m_ChunkMetadata; }
//////////////////////////////////////////
// Utility functions
@@ -1573,6 +1584,9 @@ private:
}
ChunkLookup m_ChunkLookup = NULL;
#if ENABLED(RDOC_DEVEL)
FileIO::LogFileHandle *m_DebugDumpLog = NULL;
#endif
};
#ifndef SERIALISER_IMPL
@@ -1695,7 +1709,7 @@ public:
{
FreeAlignedBuffer(m_Data);
#if !defined(RELEASE)
#if ENABLED(RDOC_DEVEL)
Atomic::Dec64(&m_LiveChunks);
Atomic::ExchAdd64(&m_TotalMem, -int64_t(m_Length));
#endif
@@ -1706,7 +1720,7 @@ public:
{
return (ChunkType)m_ChunkType;
}
#if !defined(RELEASE)
#if ENABLED(RDOC_DEVEL)
static uint64_t NumLiveChunks() { return m_LiveChunks; }
static uint64_t TotalMem() { return m_TotalMem; }
#else
@@ -1729,7 +1743,7 @@ public:
ser.GetWriter()->Rewind();
#if !defined(RELEASE)
#if ENABLED(RDOC_DEVEL)
Atomic::Inc64(&m_LiveChunks);
Atomic::ExchAdd64(&m_TotalMem, int64_t(m_Length));
#endif
@@ -1746,7 +1760,7 @@ public:
memcpy(ret->m_Data, m_Data, (size_t)m_Length);
#if !defined(RELEASE)
#if ENABLED(RDOC_DEVEL)
Atomic::Inc64(&m_LiveChunks);
Atomic::ExchAdd64(&m_TotalMem, int64_t(m_Length));
#endif
@@ -1771,7 +1785,7 @@ private:
uint32_t m_Length;
byte *m_Data;
#if !defined(RELEASE)
#if ENABLED(RDOC_DEVEL)
static int64_t m_LiveChunks, m_TotalMem;
#endif
};