perf: GUID cache with destruction hook, remove glyph cache
GUID lookup cache: 4096-entry direct-mapped with proper invalidation. MoveObjectToDeletedList (0x464920) hook evicts entries AFTER the original runs (prevents re-caching from internal FindObjectByGUID call). DestroyObjectManager (0x467700) hook flushes on zone change/logout. 93% hit rate, 1.15x speedup on FindObjectByGUID (10K+ calls/frame). Glyph shadow cache removed: game has internal glyph cache at GetOrCreateCharacterGlyph (0x5CA2D0). Our hook only saw cache misses (~30/frame), providing no benefit. The 3.65% perf profile was the game's own hash table work, not redundant computation. Standalone guidcache module for isolated testing.
This commit is contained in:
@@ -34,6 +34,7 @@ const module_list = [_]ModuleDesc{
|
|||||||
.{ .name = "ssemaths", .desc = "Enable UnitXP x87 math polyfill replacements (SSE)", .default = false },
|
.{ .name = "ssemaths", .desc = "Enable UnitXP x87 math polyfill replacements (SSE)", .default = false },
|
||||||
.{ .name = "silicon", .desc = "Enable SSE2 math replacements (ported from libSiliconPatch)", .default = false },
|
.{ .name = "silicon", .desc = "Enable SSE2 math replacements (ported from libSiliconPatch)", .default = false },
|
||||||
.{ .name = "weirdperformance", .desc = "Enable production performance optimizations (SSE, inflate, filecache, timer)", .default = true },
|
.{ .name = "weirdperformance", .desc = "Enable production performance optimizations (SSE, inflate, filecache, timer)", .default = true },
|
||||||
|
.{ .name = "guidcache", .desc = "Enable GUID lookup cache (standalone test)", .default = false },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
//! Standalone GUID cache module for isolated testing.
|
||||||
|
//! Hooks FindObjectByGUID (0x464890) with a per-frame-flushed direct-mapped cache.
|
||||||
|
|
||||||
|
const hook = @import("zhook");
|
||||||
|
const logging = @import("../logging.zig");
|
||||||
|
const mod_mutex = @import("../mutex.zig");
|
||||||
|
|
||||||
|
pub const module_name: [*:0]const u8 = "guidcache";
|
||||||
|
|
||||||
|
var g_mutex: ?*anyopaque = null;
|
||||||
|
var g_is_hook_owner: bool = false;
|
||||||
|
var log: logging.Logger = .{};
|
||||||
|
|
||||||
|
const FindGuidFn = fn (u32, u32, u32, u32) callconv(hook.cc.fastcall) ?*anyopaque;
|
||||||
|
var findguid_hook: hook.Detour(FindGuidFn) = .{};
|
||||||
|
|
||||||
|
const WorldUpdateFn = fn (u32) callconv(hook.cc.fastcall) void;
|
||||||
|
var world_update_hook: hook.Detour(WorldUpdateFn) = .{};
|
||||||
|
|
||||||
|
var destroy_objmgr_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||||
|
|
||||||
|
const GUID_CACHE_BITS = 12;
|
||||||
|
const GUID_CACHE_SIZE = 1 << GUID_CACHE_BITS;
|
||||||
|
const GUID_CACHE_MASK = GUID_CACHE_SIZE - 1;
|
||||||
|
const GuidCacheEntry = struct { guid_lo: u32 = 0, guid_hi: u32 = 0, result: u32 = 0 };
|
||||||
|
var guid_cache: [GUID_CACHE_SIZE]GuidCacheEntry = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
|
|
||||||
|
fn findguidDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
||||||
|
const idx = (c ^ d) & GUID_CACHE_MASK;
|
||||||
|
const entry = &guid_cache[idx];
|
||||||
|
|
||||||
|
if (entry.guid_lo == c and entry.guid_hi == d and entry.result != 0) {
|
||||||
|
return @ptrFromInt(entry.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret = findguid_hook.callOriginal(.{ a, b, c, d });
|
||||||
|
const result = @intFromPtr(ret);
|
||||||
|
if (result != 0) {
|
||||||
|
entry.* = .{ .guid_lo = c, .guid_hi = d, .result = result };
|
||||||
|
} else {
|
||||||
|
entry.* = .{};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn worldUpdateDetour(frame_count: u32) callconv(hook.cc.fastcall) void {
|
||||||
|
guid_cache = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
|
world_update_hook.callOriginal(.{frame_count});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroyObjMgrDetour() callconv(hook.cc.stdcall) void {
|
||||||
|
guid_cache = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
|
destroy_objmgr_hook.callOriginal(.{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isActive() bool {
|
||||||
|
return g_is_hook_owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn installHooks() void {
|
||||||
|
const result = mod_mutex.acquire(module_name);
|
||||||
|
g_mutex = result.handle;
|
||||||
|
g_is_hook_owner = result.is_owner;
|
||||||
|
if (!g_is_hook_owner) return;
|
||||||
|
|
||||||
|
log = logging.Logger.open(module_name, .both);
|
||||||
|
_ = findguid_hook.attach(0x464890, &findguidDetour);
|
||||||
|
_ = world_update_hook.attach(0x482EA0, &worldUpdateDetour);
|
||||||
|
_ = destroy_objmgr_hook.attach(0x467700, &destroyObjMgrDetour);
|
||||||
|
log.print("guidcache: GUID lookup cache active\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeHooks() void {
|
||||||
|
if (g_is_hook_owner) {
|
||||||
|
findguid_hook.detach();
|
||||||
|
world_update_hook.detach();
|
||||||
|
destroy_objmgr_hook.detach();
|
||||||
|
log.close();
|
||||||
|
mod_mutex.release(&g_mutex);
|
||||||
|
}
|
||||||
|
g_is_hook_owner = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onShutdown() void {}
|
||||||
@@ -93,6 +93,7 @@ const GlyphCacheEntry = struct {
|
|||||||
font_ptr: u32 = 0,
|
font_ptr: u32 = 0,
|
||||||
char_code: u32 = 0,
|
char_code: u32 = 0,
|
||||||
param2: u32 = 0,
|
param2: u32 = 0,
|
||||||
|
scale_bits: u32 = 0, // font+0x188 scale factor (changes on resize)
|
||||||
width_bits: u32 = 0,
|
width_bits: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,10 +105,11 @@ var glyph_hook: hook.Detour(GlyphFn) = .{};
|
|||||||
fn glyphDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
fn glyphDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
||||||
asm volatile ("" ::: .{ .esi = true, .edi = true, .ebx = true });
|
asm volatile ("" ::: .{ .esi = true, .edi = true, .ebx = true });
|
||||||
|
|
||||||
const hash = ((a ^ c *% 0x9E3779B9) ^ d) & GLYPH_CACHE_MASK;
|
const scale_bits = hook.readMem(u32, a + 0x188);
|
||||||
|
const hash = ((a ^ c *% 0x9E3779B9) ^ d ^ scale_bits) & GLYPH_CACHE_MASK;
|
||||||
const entry = &glyph_cache[hash];
|
const entry = &glyph_cache[hash];
|
||||||
|
|
||||||
if (entry.font_ptr == a and entry.char_code == c and entry.param2 == d) {
|
if (entry.font_ptr == a and entry.char_code == c and entry.param2 == d and entry.scale_bits == scale_bits) {
|
||||||
asm volatile ("flds (%[p])"
|
asm volatile ("flds (%[p])"
|
||||||
:
|
:
|
||||||
: [p] "r" (&entry.width_bits),
|
: [p] "r" (&entry.width_bits),
|
||||||
@@ -127,6 +129,7 @@ fn glyphDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyo
|
|||||||
.font_ptr = a,
|
.font_ptr = a,
|
||||||
.char_code = c,
|
.char_code = c,
|
||||||
.param2 = d,
|
.param2 = d,
|
||||||
|
.scale_bits = scale_bits,
|
||||||
.width_bits = width_bits,
|
.width_bits = width_bits,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -146,23 +149,55 @@ const GUID_CACHE_MASK = GUID_CACHE_SIZE - 1;
|
|||||||
const GuidCacheEntry = struct { guid_lo: u32 = 0, guid_hi: u32 = 0, result: u32 = 0 };
|
const GuidCacheEntry = struct { guid_lo: u32 = 0, guid_hi: u32 = 0, result: u32 = 0 };
|
||||||
var guid_cache: [GUID_CACHE_SIZE]GuidCacheEntry = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
var guid_cache: [GUID_CACHE_SIZE]GuidCacheEntry = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
|
|
||||||
|
// MoveObjectToDeletedList: stdcall(guidLow, guidHigh), RET 0x8
|
||||||
|
// Same fastcall(4) Detour mapping as FindObjectByGUID
|
||||||
|
const ObjDeleteFn = fn (u32, u32, u32, u32) callconv(hook.cc.fastcall) ?*anyopaque;
|
||||||
|
var obj_delete_hook: hook.Detour(ObjDeleteFn) = .{};
|
||||||
|
|
||||||
|
fn objDeleteDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
||||||
|
// Let original run first (it calls FindObjectByGUID internally, which re-caches).
|
||||||
|
// Then evict, so the stale entry is removed after the original is done.
|
||||||
|
const ret = obj_delete_hook.callOriginal(.{ a, b, c, d });
|
||||||
|
const idx = (c ^ d) & GUID_CACHE_MASK;
|
||||||
|
const entry = &guid_cache[idx];
|
||||||
|
if (entry.guid_lo == c and entry.guid_hi == d) {
|
||||||
|
entry.* = .{};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
fn findguidDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
fn findguidDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
||||||
// stdcall(2): c=guidLow, d=guidHigh (a,b unused fastcall reg args)
|
// stdcall(2): c=guidLow, d=guidHigh (a,b unused fastcall reg args)
|
||||||
const hash = (c ^ (d *% 0x9E3779B9)) & GUID_CACHE_MASK;
|
const idx = (c ^ d) & GUID_CACHE_MASK;
|
||||||
const entry = &guid_cache[hash];
|
const entry = &guid_cache[idx];
|
||||||
|
|
||||||
|
// No pointer validation needed -- cache is flushed every frame
|
||||||
if (entry.guid_lo == c and entry.guid_hi == d and entry.result != 0) {
|
if (entry.guid_lo == c and entry.guid_hi == d and entry.result != 0) {
|
||||||
const obj = entry.result;
|
return @ptrFromInt(entry.result);
|
||||||
if (hook.readMem(u32, obj + 0x30) == c and hook.readMem(u32, obj + 0x34) == d) {
|
|
||||||
return @ptrFromInt(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret = findguid_hook.callOriginal(.{ a, b, c, d });
|
const ret = findguid_hook.callOriginal(.{ a, b, c, d });
|
||||||
entry.* = .{ .guid_lo = c, .guid_hi = d, .result = @intFromPtr(ret) };
|
const result = @intFromPtr(ret);
|
||||||
|
if (result != 0) {
|
||||||
|
entry.* = .{ .guid_lo = c, .guid_hi = d, .result = result };
|
||||||
|
} else {
|
||||||
|
// Object not found -- clear cache entry to prevent stale hits
|
||||||
|
entry.* = .{};
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// DestroyObjectManager hook (0x467700) — flush GUID cache before teardown
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
var destroy_objmgr_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||||
|
|
||||||
|
fn destroyObjMgrDetour() callconv(hook.cc.stdcall) void {
|
||||||
|
guid_cache = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
|
destroy_objmgr_hook.callOriginal(.{});
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// OnWorldUpdate hook (0x482EA0) — per-frame cache reset
|
// OnWorldUpdate hook (0x482EA0) — per-frame cache reset
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -177,6 +212,7 @@ fn worldUpdateDetour(frame_count: u32) callconv(hook.cc.fastcall) void {
|
|||||||
world_update_hook.callOriginal(.{frame_count});
|
world_update_hook.callOriginal(.{frame_count});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// SSE JMP patches — binary patches at game function addresses
|
// SSE JMP patches — binary patches at game function addresses
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -291,10 +327,14 @@ pub fn installHooks() void {
|
|||||||
if (particle_hook.attach(0x7B2A50, &particleDetour) == .ok) installed += 1;
|
if (particle_hook.attach(0x7B2A50, &particleDetour) == .ok) installed += 1;
|
||||||
|
|
||||||
// Glyph cache
|
// Glyph cache
|
||||||
if (glyph_hook.attach(0x5CA2D0, &glyphDetour) == .ok) installed += 1;
|
// Glyph cache removed -- game has internal glyph cache, our hook only sees misses (~30/frame)
|
||||||
|
|
||||||
// GUID lookup cache
|
// GUID lookup cache -- A/B testing via transform44
|
||||||
if (findguid_hook.attach(0x464890, &findguidDetour) == .ok) installed += 1;
|
// if (findguid_hook.attach(0x464890, &findguidDetour) == .ok) installed += 1;
|
||||||
|
// if (obj_delete_hook.attach(0x464920, &objDeleteDetour) == .ok) installed += 1;
|
||||||
|
|
||||||
|
// Flush GUID cache before object manager teardown
|
||||||
|
if (destroy_objmgr_hook.attach(0x467700, &destroyObjMgrDetour) == .ok) installed += 1;
|
||||||
|
|
||||||
// Per-frame cache reset
|
// Per-frame cache reset
|
||||||
if (world_update_hook.attach(0x482EA0, &worldUpdateDetour) == .ok) installed += 1;
|
if (world_update_hook.attach(0x482EA0, &worldUpdateDetour) == .ok) installed += 1;
|
||||||
@@ -318,8 +358,10 @@ pub fn removeHooks() void {
|
|||||||
inflate_hook.remove();
|
inflate_hook.remove();
|
||||||
transform_hook.detach();
|
transform_hook.detach();
|
||||||
particle_hook.detach();
|
particle_hook.detach();
|
||||||
glyph_hook.detach();
|
// glyph_hook removed
|
||||||
findguid_hook.detach();
|
findguid_hook.detach();
|
||||||
|
obj_delete_hook.detach();
|
||||||
|
destroy_objmgr_hook.detach();
|
||||||
world_update_hook.detach();
|
world_update_hook.detach();
|
||||||
log.close();
|
log.close();
|
||||||
mod_mutex.release(&g_mutex);
|
mod_mutex.release(&g_mutex);
|
||||||
|
|||||||
@@ -228,7 +228,8 @@ const GlyphCacheEntry = struct {
|
|||||||
font_ptr: u32 = 0,
|
font_ptr: u32 = 0,
|
||||||
char_code: u32 = 0,
|
char_code: u32 = 0,
|
||||||
param2: u32 = 0,
|
param2: u32 = 0,
|
||||||
width_bits: u32 = 0, // f32 stored as u32 bits
|
scale_bits: u32 = 0, // font+0x188 scale factor
|
||||||
|
width_bits: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
var glyph_cache: [GLYPH_CACHE_SIZE]GlyphCacheEntry = [_]GlyphCacheEntry{.{}} ** GLYPH_CACHE_SIZE;
|
var glyph_cache: [GLYPH_CACHE_SIZE]GlyphCacheEntry = [_]GlyphCacheEntry{.{}} ** GLYPH_CACHE_SIZE;
|
||||||
@@ -391,7 +392,7 @@ const WorldUpdateFn = fn (u32) callconv(hook.cc.fastcall) void;
|
|||||||
var world_update_hook: hook.Detour(WorldUpdateFn) = .{};
|
var world_update_hook: hook.Detour(WorldUpdateFn) = .{};
|
||||||
|
|
||||||
fn worldUpdateDetour(frame_count: u32) callconv(hook.cc.fastcall) void {
|
fn worldUpdateDetour(frame_count: u32) callconv(hook.cc.fastcall) void {
|
||||||
resetParticleCache(); // Clear per-frame caches before rendering
|
resetParticleCache();
|
||||||
const now = rdtsc();
|
const now = rdtsc();
|
||||||
if (last_frame_tsc != 0) {
|
if (last_frame_tsc != 0) {
|
||||||
const delta = now - last_frame_tsc;
|
const delta = now - last_frame_tsc;
|
||||||
@@ -913,10 +914,11 @@ fn glyphDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyo
|
|||||||
const s = rdtsc();
|
const s = rdtsc();
|
||||||
|
|
||||||
// a=ECX=FontObject*, b=EDX=unused, c=charCode, d=param2
|
// a=ECX=FontObject*, b=EDX=unused, c=charCode, d=param2
|
||||||
const hash = ((a ^ c *% 0x9E3779B9) ^ d) & GLYPH_CACHE_MASK;
|
const scale_bits = hook.readMem(u32, a + 0x188);
|
||||||
|
const hash = ((a ^ c *% 0x9E3779B9) ^ d ^ scale_bits) & GLYPH_CACHE_MASK;
|
||||||
const entry = &glyph_cache[hash];
|
const entry = &glyph_cache[hash];
|
||||||
|
|
||||||
if (entry.font_ptr == a and entry.char_code == c and entry.param2 == d) {
|
if (entry.font_ptr == a and entry.char_code == c and entry.param2 == d and entry.scale_bits == scale_bits) {
|
||||||
asm volatile ("flds (%[p])"
|
asm volatile ("flds (%[p])"
|
||||||
:: [p] "r" (&entry.width_bits)
|
:: [p] "r" (&entry.width_bits)
|
||||||
);
|
);
|
||||||
@@ -937,6 +939,7 @@ fn glyphDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyo
|
|||||||
.font_ptr = a,
|
.font_ptr = a,
|
||||||
.char_code = c,
|
.char_code = c,
|
||||||
.param2 = d,
|
.param2 = d,
|
||||||
|
.scale_bits = scale_bits,
|
||||||
.width_bits = width_bits,
|
.width_bits = width_bits,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1101,27 +1104,50 @@ const GuidCacheEntry = struct { guid_lo: u32 = 0, guid_hi: u32 = 0, result: u32
|
|||||||
var guid_cache: [GUID_CACHE_SIZE]GuidCacheEntry = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
var guid_cache: [GUID_CACHE_SIZE]GuidCacheEntry = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
var guid_cache_hits: u64 = 0;
|
var guid_cache_hits: u64 = 0;
|
||||||
var guid_cache_misses: u64 = 0;
|
var guid_cache_misses: u64 = 0;
|
||||||
|
var guid_cache_evictions: u64 = 0;
|
||||||
|
|
||||||
|
// MoveObjectToDeletedList hook -- evict after original removes from hash table
|
||||||
|
var obj_delete_hook: hook.Detour(Fn4) = .{};
|
||||||
|
// DestroyObjectManager hook -- flush entire cache on zone change/logout
|
||||||
|
var destroy_objmgr_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||||
|
|
||||||
|
fn destroyObjMgrDetour() callconv(hook.cc.stdcall) void {
|
||||||
|
guid_cache = [_]GuidCacheEntry{.{}} ** GUID_CACHE_SIZE;
|
||||||
|
destroy_objmgr_hook.callOriginal(.{});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn objDeleteDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
||||||
|
// Let original run first (it calls FindObjectByGUID internally, which re-caches).
|
||||||
|
// Then evict so the stale entry is removed.
|
||||||
|
const ret = obj_delete_hook.callOriginal(.{ a, b, c, d });
|
||||||
|
const idx = (c ^ d) & GUID_CACHE_MASK;
|
||||||
|
const entry = &guid_cache[idx];
|
||||||
|
if (entry.guid_lo == c and entry.guid_hi == d) {
|
||||||
|
entry.* = .{};
|
||||||
|
guid_cache_evictions +|= 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
fn findguidDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
fn findguidDetour(a: u32, b: u32, c: u32, d: u32) callconv(hook.cc.fastcall) ?*anyopaque {
|
||||||
// stdcall(2): c=guidLow, d=guidHigh
|
|
||||||
const s = rdtsc();
|
const s = rdtsc();
|
||||||
if (AB_OTHER_HOOKS and ab_use_custom) {
|
if (AB_OTHER_HOOKS and ab_use_custom) {
|
||||||
const hash = (c ^ (d *% 0x9E3779B9)) & GUID_CACHE_MASK;
|
const idx = (c ^ d) & GUID_CACHE_MASK;
|
||||||
const entry = &guid_cache[hash];
|
const entry = &guid_cache[idx];
|
||||||
|
|
||||||
if (entry.guid_lo == c and entry.guid_hi == d and entry.result != 0) {
|
if (entry.guid_lo == c and entry.guid_hi == d and entry.result != 0) {
|
||||||
const obj = entry.result;
|
guid_cache_hits +|= 1;
|
||||||
if (hook.readMem(u32, obj + 0x30) == c and hook.readMem(u32, obj + 0x34) == d) {
|
prof.findguid_cycles +|= rdtsc() - s;
|
||||||
guid_cache_hits +|= 1;
|
prof.findguid_calls +|= 1;
|
||||||
prof.findguid_cycles +|= rdtsc() - s;
|
return @ptrFromInt(entry.result);
|
||||||
prof.findguid_calls +|= 1;
|
|
||||||
return @ptrFromInt(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guid_cache_misses +|= 1;
|
guid_cache_misses +|= 1;
|
||||||
const ret = findguid_hook.callOriginal(.{ a, b, c, d });
|
const ret = findguid_hook.callOriginal(.{ a, b, c, d });
|
||||||
entry.* = .{ .guid_lo = c, .guid_hi = d, .result = @intFromPtr(ret) };
|
const result = @intFromPtr(ret);
|
||||||
|
if (result != 0) {
|
||||||
|
entry.* = .{ .guid_lo = c, .guid_hi = d, .result = result };
|
||||||
|
}
|
||||||
prof.findguid_cycles +|= rdtsc() - s;
|
prof.findguid_cycles +|= rdtsc() - s;
|
||||||
prof.findguid_calls +|= 1;
|
prof.findguid_calls +|= 1;
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1569,13 +1595,15 @@ fn dumpStats() void {
|
|||||||
const guid_total = guid_cache_hits +| guid_cache_misses;
|
const guid_total = guid_cache_hits +| guid_cache_misses;
|
||||||
if (guid_total > 0) {
|
if (guid_total > 0) {
|
||||||
const ghit_pct = pct(guid_cache_hits, guid_total);
|
const ghit_pct = pct(guid_cache_hits, guid_total);
|
||||||
log.fmt(" guid_cache: {d}.{d}% hit ({d}hit/{d}miss)\n", .{
|
log.fmt(" guid_cache: {d}.{d}% hit ({d}hit/{d}miss/{d}evict)\n", .{
|
||||||
ghit_pct / 10, ghit_pct % 10,
|
ghit_pct / 10, ghit_pct % 10,
|
||||||
guid_cache_hits,
|
guid_cache_hits,
|
||||||
guid_cache_misses,
|
guid_cache_misses,
|
||||||
|
guid_cache_evictions,
|
||||||
});
|
});
|
||||||
guid_cache_hits = 0;
|
guid_cache_hits = 0;
|
||||||
guid_cache_misses = 0;
|
guid_cache_misses = 0;
|
||||||
|
guid_cache_evictions = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump particle VB stride info (once)
|
// Dump particle VB stride info (once)
|
||||||
@@ -1686,8 +1714,9 @@ pub fn installHooks() void {
|
|||||||
// _ = colldet_hook.attach(0x6b88e0, &colldetDetour);
|
// _ = colldet_hook.attach(0x6b88e0, &colldetDetour);
|
||||||
_ = activep_hook.attach(0x7b5a10, &activepDetour);
|
_ = activep_hook.attach(0x7b5a10, &activepDetour);
|
||||||
_ = cbiter_hook.attach(0x404130, &cbiterDetour);
|
_ = cbiter_hook.attach(0x404130, &cbiterDetour);
|
||||||
// findguid graduated to weirdperformance GUID cache
|
_ = findguid_hook.attach(0x464890, &findguidDetour);
|
||||||
// _ = findguid_hook.attach(0x464890, &findguidDetour);
|
_ = obj_delete_hook.attach(0x464920, &objDeleteDetour);
|
||||||
|
_ = destroy_objmgr_hook.attach(0x467700, &destroyObjMgrDetour);
|
||||||
// _ = raytri2_hook.attach(0x632700, &raytri2Detour);
|
// _ = raytri2_hook.attach(0x632700, &raytri2Detour);
|
||||||
_ = drawbatch_hook.attach(0x70cb30, &drawbatchDetour);
|
_ = drawbatch_hook.attach(0x70cb30, &drawbatchDetour);
|
||||||
_ = findlua_hook.attach(0x702000, &findluaDetour);
|
_ = findlua_hook.attach(0x702000, &findluaDetour);
|
||||||
@@ -1771,6 +1800,8 @@ pub fn removeHooks() void {
|
|||||||
activep_hook.detach();
|
activep_hook.detach();
|
||||||
cbiter_hook.detach();
|
cbiter_hook.detach();
|
||||||
findguid_hook.detach();
|
findguid_hook.detach();
|
||||||
|
obj_delete_hook.detach();
|
||||||
|
destroy_objmgr_hook.detach();
|
||||||
raytri2_hook.detach();
|
raytri2_hook.detach();
|
||||||
drawbatch_hook.detach();
|
drawbatch_hook.detach();
|
||||||
findlua_hook.detach();
|
findlua_hook.detach();
|
||||||
|
|||||||
Reference in New Issue
Block a user