Trace GPS resolver during map queries
This commit is contained in:
@@ -160,6 +160,7 @@ constexpr uintptr_t kGpsQuerySubmitRva = 0x070A42C;
|
||||
constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570;
|
||||
constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8;
|
||||
constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704;
|
||||
constexpr uintptr_t kGpsMapRouteSubmitReturnRva = 0x08D20D4;
|
||||
constexpr uintptr_t kGpsDispatchAdvanceRva = 0x08D17D8;
|
||||
constexpr uintptr_t kGpsAsyncWorkerTickRva = 0x0126B28;
|
||||
constexpr uintptr_t kGpsRouteJobStartRva = 0x0818928;
|
||||
@@ -177,6 +178,8 @@ constexpr uintptr_t kGpsFilteredCostProviderVtableRva = 0x2AE60F8;
|
||||
constexpr uintptr_t kGpsAuxMultiplierRva = 0x040BB00;
|
||||
constexpr uintptr_t kGpsNodeMultiplierRva = 0x040BB40;
|
||||
constexpr uintptr_t kGpsCostMultiplierTableRva = 0x3154D28;
|
||||
constexpr uint64_t kGpsResolveTraceWindowMs = 5000;
|
||||
constexpr uint32_t kGpsResolveSelectedRetLogLimit = 4096;
|
||||
constexpr std::array<float, 7> kGpsPatchedCostMultipliers = {
|
||||
12.0f, 7.0f, 2.5f, 0.0f, 3.0f, 2.0f, 1.25f,
|
||||
};
|
||||
@@ -271,6 +274,8 @@ uint32_t gGpsAuxMultiplierLogCount = 0;
|
||||
uint32_t gGpsNodeMultiplierLogCount = 0;
|
||||
uint32_t gGpsCostTablePatchLogCount = 0;
|
||||
uint32_t gGpsProviderClassPatchLogCount = 0;
|
||||
std::array<uint32_t, 4> gGpsResolveHandleRetLogCounts{};
|
||||
uint64_t gGpsResolveTraceWindowUntilMs = 0;
|
||||
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
|
||||
std::mutex gGpsCostLogMutex;
|
||||
std::mutex gGpsAsyncLogMutex;
|
||||
@@ -500,6 +505,18 @@ std::filesystem::path GetLogPath()
|
||||
return std::filesystem::path(L"red4ext") / L"plugins" / L"EdgeWeightGPS" / L"EdgeWeightGPS.log";
|
||||
}
|
||||
|
||||
uint64_t GetElapsedMs()
|
||||
{
|
||||
if (!gLogStartTick || !gLogFrequency)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LARGE_INTEGER counter{};
|
||||
QueryPerformanceCounter(&counter);
|
||||
return static_cast<uint64_t>((counter.QuadPart - gLogStartTick) * 1000 / gLogFrequency);
|
||||
}
|
||||
|
||||
void Log(std::string_view aMessage)
|
||||
{
|
||||
std::lock_guard lock(gLogMutex);
|
||||
@@ -515,13 +532,7 @@ void Log(std::string_view aMessage)
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t elapsedMs = 0;
|
||||
if (gLogStartTick && gLogFrequency)
|
||||
{
|
||||
LARGE_INTEGER counter{};
|
||||
QueryPerformanceCounter(&counter);
|
||||
elapsedMs = static_cast<uint64_t>((counter.QuadPart - gLogStartTick) * 1000 / gLogFrequency);
|
||||
}
|
||||
const auto elapsedMs = GetElapsedMs();
|
||||
|
||||
out << std::put_time(&localTime, "%Y-%m-%d %H:%M:%S") << "." << std::setw(3) << std::setfill('0')
|
||||
<< elapsedMs % 1000 << std::setfill(' ') << " +" << elapsedMs << "ms " << aMessage << "\n";
|
||||
@@ -1072,20 +1083,38 @@ void AppendGpsPackedHandleSummary(std::ostringstream& aLine, const char* aPrefix
|
||||
|
||||
bool IsSelectedGpsResolveReturnRva(uintptr_t aReturnRva)
|
||||
{
|
||||
constexpr std::array<uintptr_t, 7> kSelectedReturnRvas = {
|
||||
0x44D26C,
|
||||
0x44D304,
|
||||
0x44D99F,
|
||||
0x44D9CD,
|
||||
0x44DB50,
|
||||
0x44DB88,
|
||||
0x44DD92,
|
||||
constexpr std::array<uintptr_t, 2> kSelectedReturnRvas = {
|
||||
0x44CB9E,
|
||||
0x44DD97,
|
||||
};
|
||||
|
||||
return std::find(kSelectedReturnRvas.begin(), kSelectedReturnRvas.end(), aReturnRva) !=
|
||||
kSelectedReturnRvas.end();
|
||||
}
|
||||
|
||||
size_t GetGpsResolveReturnBucket(uintptr_t aReturnRva)
|
||||
{
|
||||
switch (aReturnRva)
|
||||
{
|
||||
case 0x44CB9E:
|
||||
return 0;
|
||||
case 0x44DD97:
|
||||
return 1;
|
||||
default:
|
||||
return gGpsResolveHandleRetLogCounts.size();
|
||||
}
|
||||
}
|
||||
|
||||
void ExtendGpsResolveTraceWindow(uint64_t aNowMs)
|
||||
{
|
||||
std::lock_guard lock(gGpsCostLogMutex);
|
||||
const auto untilMs = aNowMs + kGpsResolveTraceWindowMs;
|
||||
if (untilMs > gGpsResolveTraceWindowUntilMs)
|
||||
{
|
||||
gGpsResolveTraceWindowUntilMs = untilMs;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendGpsCostProviderSummary(std::ostringstream& aLine, const char* aPrefix, void* aProvider)
|
||||
{
|
||||
const auto prefix = std::string(aPrefix);
|
||||
@@ -3411,6 +3440,16 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery)
|
||||
|
||||
const auto callCount = gGpsQuerySubmitLogCount;
|
||||
const auto shouldLog = callCount < kMaxCalls;
|
||||
uint32_t queryKind = 0;
|
||||
const auto hasQueryKind = aQuery && TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aQuery) + 0xCC),
|
||||
queryKind);
|
||||
const auto shouldTraceResolver =
|
||||
returnRva == kGpsMapRouteSubmitReturnRva && hasQueryKind && queryKind == 5;
|
||||
if (shouldTraceResolver)
|
||||
{
|
||||
ExtendGpsResolveTraceWindow(GetElapsedMs());
|
||||
}
|
||||
|
||||
if (shouldLog)
|
||||
{
|
||||
std::ostringstream line;
|
||||
@@ -3423,6 +3462,10 @@ int32_t DetourGpsQuerySubmit(void* aManager, void* aQuery)
|
||||
AppendUint32Field(line, "query_f0c", aQuery, 0x0C);
|
||||
AppendUint32Field(line, "query_fcc", aQuery, 0xCC);
|
||||
AppendVector4Field(line, "query_pos58", aQuery, 0x58);
|
||||
if (shouldTraceResolver)
|
||||
{
|
||||
line << " resolveTraceWindowMs=" << kGpsResolveTraceWindowMs;
|
||||
}
|
||||
AppendReturnRva(line, returnAddress);
|
||||
LogRed4ext(line.str());
|
||||
++gGpsQuerySubmitLogCount;
|
||||
@@ -3952,36 +3995,62 @@ int32_t DetourGpsResolveHandle(void* aGraph, uint64_t aHandle, void* aOutSegment
|
||||
const auto hasSegment = aOutSegment && TryReadMemory(aOutSegment, segment);
|
||||
const auto hasPoint = aOutPoint && TryReadMemory(aOutPoint, point);
|
||||
|
||||
const auto pointIndex = aHandle & 0xFFFFF;
|
||||
uint32_t callCount = 0;
|
||||
uint32_t returnCallCount = 0;
|
||||
bool shouldLog = false;
|
||||
{
|
||||
std::lock_guard lock(gGpsCostLogMutex);
|
||||
callCount = gGpsResolveHandleLogCount++;
|
||||
const auto returnBucket = GetGpsResolveReturnBucket(returnRva);
|
||||
if (returnBucket < gGpsResolveHandleRetLogCounts.size())
|
||||
{
|
||||
returnCallCount = gGpsResolveHandleRetLogCounts[returnBucket]++;
|
||||
}
|
||||
const auto inTraceWindow = GetElapsedMs() <= gGpsResolveTraceWindowUntilMs;
|
||||
shouldLog = result >= 0 && hasSegment && hasPoint &&
|
||||
(IsSelectedGpsResolveReturnRva(returnRva) || callCount < 64) && callCount < 512;
|
||||
((IsSelectedGpsResolveReturnRva(returnRva) && inTraceWindow &&
|
||||
returnCallCount < kGpsResolveSelectedRetLogLimit) ||
|
||||
callCount < 32);
|
||||
}
|
||||
|
||||
if (shouldLog)
|
||||
{
|
||||
auto* segmentMeta = ReadPointerField(segment, 0x08);
|
||||
auto* pointArray = ReadPointerField(segment, 0x10);
|
||||
auto* coordArray = ReadPointerField(segment, 0x18);
|
||||
auto* aux20 = ReadPointerField(segment, 0x20);
|
||||
auto* aux28 = ReadPointerField(segment, 0x28);
|
||||
auto* aux30 = ReadPointerField(segment, 0x30);
|
||||
auto* aux38 = ReadPointerField(segment, 0x38);
|
||||
|
||||
const auto auxPointOffset = pointIndex * 12;
|
||||
auto* aux28Point = aux28 ? reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(aux28) + auxPointOffset) : nullptr;
|
||||
|
||||
std::ostringstream line;
|
||||
line << "hook GPSResolveHandle 0x44e1a8 call=" << callCount << " value=0x" << std::hex
|
||||
<< static_cast<uint32_t>(result) << " handle=0x" << aHandle << std::dec;
|
||||
line << "hook GPSResolveHandle 0x44e1a8 call=" << callCount << " retCall=" << returnCallCount
|
||||
<< " value=0x" << std::hex << static_cast<uint32_t>(result) << " handle=0x" << aHandle << std::dec;
|
||||
AppendGpsPackedHandleSummary(line, "handle", aHandle);
|
||||
AppendPointerWithRva(line, "graph", aGraph);
|
||||
AppendPointerWithRva(line, "outSegment", aOutSegment);
|
||||
AppendPointerWithRva(line, "outPoint", aOutPoint);
|
||||
AppendPointerWithRva(line, "segment", segment);
|
||||
AppendPointerWithRva(line, "point", point);
|
||||
AppendPointerField(line, "segment_p08", segment, 0x08);
|
||||
AppendPointerField(line, "segment_p10", segment, 0x10);
|
||||
AppendPointerField(line, "segment_p18", segment, 0x18);
|
||||
AppendPointerField(line, "segment_p20", segment, 0x20);
|
||||
AppendPointerField(line, "segment_p28", segment, 0x28);
|
||||
AppendPointerField(line, "segment_p30", segment, 0x30);
|
||||
AppendPointerField(line, "segment_p38", segment, 0x38);
|
||||
AppendPointerWithRva(line, "segment_p08", segmentMeta);
|
||||
AppendPointerWithRva(line, "segment_p10", pointArray);
|
||||
AppendPointerWithRva(line, "segment_p18", coordArray);
|
||||
AppendPointerWithRva(line, "segment_p20", aux20);
|
||||
AppendPointerWithRva(line, "segment_p28", aux28);
|
||||
AppendPointerWithRva(line, "segment_p30", aux30);
|
||||
AppendPointerWithRva(line, "segment_p38", aux38);
|
||||
AppendGpsPointSummary(line, "pointSummary", point);
|
||||
AppendBytesPointer(line, "segment_raw68", segment, 0x68);
|
||||
AppendBytesPointer(line, "point_raw14", point, 0x14);
|
||||
AppendBytesPointer(line, "segment_p08_raw30", segmentMeta, 0x30);
|
||||
AppendBytesPointer(line, "segment_p20_raw40", aux20, 0x40);
|
||||
AppendBytesPointer(line, "segment_p28_point_raw18", aux28Point, 0x18);
|
||||
AppendBytesPointer(line, "segment_p30_raw40", aux30, 0x40);
|
||||
AppendBytesPointer(line, "segment_p38_raw40", aux38, 0x40);
|
||||
if (gActiveGpsRouteProducerCall != UINT32_MAX)
|
||||
{
|
||||
line << " routeProducerCall=" << gActiveGpsRouteProducerCall;
|
||||
|
||||
Reference in New Issue
Block a user