--- a/rts/Sim/Units/Scripts/UnitScript.cpp +++ b/rts/Sim/Units/Scripts/UnitScript.cpp @@ -212,6 +212,9 @@ // clear doneAnims here to preserve them for DumpState doneAnims.clear(); +#ifdef WEBBAR_SYNC_TRACE + webbarTraceAnims.clear(); +#endif for (auto& ai : anims) { LocalModelPiece& lmp = *pieces[ai.piece]; @@ -223,6 +226,9 @@ // checksum all anims (live + done) checksum = spring::LiteHash(ai, checksum); +#ifdef WEBBAR_SYNC_TRACE + { std::array raw; memcpy(raw.data(), &ai, sizeof(AnimInfo)); webbarTraceAnims.push_back(raw); } +#endif } spring::VectorEraseIfAll(anims, [](const auto& ai) { return ai.done; }); --- a/rts/Sim/Units/Scripts/UnitScript.h +++ b/rts/Sim/Units/Scripts/UnitScript.h @@ -117,6 +117,9 @@ const CUnit* GetUnit() const { return unit; } auto GetAnimArrayChecksum() const { return checksum; } +#ifdef WEBBAR_SYNC_TRACE + std::vector> webbarTraceAnims; +#endif void TickAllAnims(int tickRate); bool TickAnimFinished(); // note: must copy-and-set here (LMP dirty flag, etc) --- a/rts/Sim/Units/Scripts/UnitScriptEngine.cpp +++ b/rts/Sim/Units/Scripts/UnitScriptEngine.cpp @@ -150,6 +150,9 @@ currentScript = animating[i]; // deal with synced checksum here, before animating is possibly popped below cs = spring::hash_combine(currentScript->GetAnimArrayChecksum(), cs); +#ifdef WEBBAR_SYNC_TRACE + { const uint32_t scs = currentScript->GetAnimArrayChecksum(); CSyncChecker::TraceBytes("S", currentScript->GetUnit() ? currentScript->GetUnit()->id : -1, &scs, sizeof(scs)); for (const auto& raw : currentScript->webbarTraceAnims) CSyncChecker::TraceBytes("A", currentScript->GetUnit() ? currentScript->GetUnit()->id : -1, raw.data(), raw.size()); } +#endif if (!currentScript->TickAnimFinished()) { animating[i] = animating.back(); --- a/rts/System/Sync/SyncChecker.cpp +++ b/rts/System/Sync/SyncChecker.cpp @@ -14,6 +14,31 @@ unsigned CSyncChecker::g_prevChecksum; int CSyncChecker::inSyncedCode; +#ifdef WEBBAR_SYNC_TRACE +#include +#include +#include "Sim/Misc/GlobalSynced.h" +// WebBAR sync trace (diagnostic only): WEBBAR_SYNC_TRACE=from:to logs every checksum input of those frames. +const char* CSyncChecker::traceMsg = ""; +static FILE* webbarTraceFile = nullptr; static int webbarTraceFrom = -1, webbarTraceTo = -1, webbarTraceFrame = -2; static bool webbarTraceInit = false; static unsigned webbarTraceIdx = 0; +void* CSyncChecker::TraceFile() { + if (!webbarTraceInit) { webbarTraceInit = true; const char* r = getenv("WEBBAR_SYNC_TRACE"); if (r && sscanf(r, "%d:%d", &webbarTraceFrom, &webbarTraceTo) == 2) { const char* f = getenv("WEBBAR_SYNC_TRACE_FILE"); webbarTraceFile = fopen(f ? f : "sync-trace.txt", "w"); } } + if (webbarTraceFile == nullptr || gs == nullptr) return nullptr; + const int fr = gs->frameNum; if (fr < webbarTraceFrom || fr > webbarTraceTo) { if (fr > webbarTraceTo) fflush(webbarTraceFile); return nullptr; } + if (fr != webbarTraceFrame) { webbarTraceFrame = fr; webbarTraceIdx = 0; fprintf(webbarTraceFile, "F %d\n", fr); fflush(webbarTraceFile); } + return webbarTraceFile; +} +void CSyncChecker::TraceBytes(const char* tag, int id, const void* p, unsigned size) { + FILE* f = static_cast(TraceFile()); if (f == nullptr) return; + fprintf(f, "%s %d %u ", tag, id, size); for (unsigned i = 0; i < size; i++) fprintf(f, "%02x", static_cast(p)[i]); fprintf(f, "\n"); +} +static void WebbarTraceSync(const void* p, unsigned size, unsigned cs) { + FILE* f = static_cast(CSyncChecker::TraceFile()); if (f == nullptr) return; + fprintf(f, "%u %s %u ", webbarTraceIdx++, CSyncChecker::traceMsg ? CSyncChecker::traceMsg : "?", size); for (unsigned i = 0; i < size; i++) fprintf(f, "%02x", static_cast(p)[i]); fprintf(f, " %08x\n", cs); + CSyncChecker::traceMsg = ""; +} +#endif + void CSyncChecker::NewFrame() { g_checksum = 0xfade1eaf; @@ -34,6 +59,9 @@ debugSyncCheckThreading(); #endif g_checksum = spring::hash_combine(val, g_checksum); +#ifdef WEBBAR_SYNC_TRACE + WebbarTraceSync(&val, sizeof(val), g_checksum); +#endif //LOG("[Sync::Checker] chksum=%u\n", g_checksum); #ifdef SYNC_HISTORY @@ -50,6 +78,9 @@ // most common cases first, make it easy for compiler to optimize for it // simple xor is not enough to detect multiple zeroes, e.g. g_checksum = spring::LiteHash(p, size, g_checksum); +#ifdef WEBBAR_SYNC_TRACE + WebbarTraceSync(p, size, g_checksum); +#endif //LOG("[Sync::Checker] chksum=%u\n", g_checksum); #ifdef SYNC_HISTORY --- a/rts/System/Sync/SyncChecker.h +++ b/rts/System/Sync/SyncChecker.h @@ -37,6 +37,11 @@ static void debugSyncCheckThreading(); static void Sync(uint32_t val); static void Sync(const void* p, unsigned size); + #ifdef WEBBAR_SYNC_TRACE + static const char* traceMsg; + static void* TraceFile(); + static void TraceBytes(const char* tag, int id, const void* p, unsigned size); + #endif #ifdef SYNC_HISTORY static std::tuple GetFrameHistory(unsigned rewindFrames); static std::pair GetHistory() { return std::make_pair(nextHistoryIndex, logs.data()); }; --- a/rts/System/Sync/SyncedPrimitiveBase.h +++ b/rts/System/Sync/SyncedPrimitiveBase.h @@ -45,6 +45,9 @@ AssertDebugger(p, size, msg); #ifdef SYNCCHECK assert(CSyncChecker::InSyncedCode()); + #ifdef WEBBAR_SYNC_TRACE + CSyncChecker::traceMsg = msg; + #endif CSyncChecker::Sync(p, size); #ifdef TRACE_SYNC unsigned int crc = CSyncChecker::GetChecksum(); @@ -57,6 +60,9 @@ AssertDebugger(val, msg); #ifdef SYNCCHECK assert(CSyncChecker::InSyncedCode()); + #ifdef WEBBAR_SYNC_TRACE + CSyncChecker::traceMsg = msg; + #endif CSyncChecker::Sync(val); #ifdef TRACE_SYNC unsigned int crc = CSyncChecker::GetChecksum();