mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
[Perf] Behavior-preserving hot-path allocation/LINQ wins (#264)
* [Perf] Gate event-flag tracing so it allocates nothing when disabled TraceEventFlag built its interpolated argument (and, on the wait path, FormatFrameChain + a new StringBuilder(256) in FormatGuestWaitObject plus ~12 guest-memory reads) on every call, then checked the env var inside the method — so every sceKernelSetEventFlag/Clear/Poll/Wait paid a string allocation and an Environment.GetEnvironmentVariable P/Invoke even with tracing off. Cache the flag once in a static readonly bool and gate every call site, matching the semaphore/event-queue pattern. Behavior is unchanged when SHARPEMU_LOG_EVENT_FLAG=1. * [Perf] Hoist IsNoBlockLeaf classification to import-stub setup The leaf-dispatch path called IsNoBlockLeafImport(nid) — a ~30-literal string pattern match — on every leaf import. IsLeaf/NidHash were already precomputed on ImportStubEntry at stub setup; add IsNoBlockLeaf alongside them and read the field in the hot path. Behavior unchanged. * [Perf] Cache trace env-var flags read on hot paths Two SHARPEMU_LOG_* env vars were read via Environment.GetEnvironmentVariable (a P/Invoke + transient string) on hot paths: SHARPEMU_LOG_FIBER on every fiber context transfer, and SHARPEMU_LOG_DIRECT_MEMORY on every direct-memory op (~8 sites). Cache both once — _logFiber alongside the other backend _log* flags, and _traceDirectMemory behind the existing ShouldTraceDirectMemory helper. Behavior unchanged. * [Perf] Avoid per-iteration thread snapshot in the idle pump loop PumpUntilGuestThreadsIdle allocated a full GuestThreadState[] snapshot (via LINQ Values.ToArray()) on every spin just to tally three run-state booleans. Tally them under the lock with an allocation-free helper, and only materialize the snapshot inside the gated (default-off) diagnostic dump. SnapshotGuestThreads now uses Values.CopyTo instead of LINQ. Behavior unchanged. * [Perf] De-LINQ GetPixelColorExportMask on the per-draw path GetPixelColorExportMask ran a Select/OfType/Where/Aggregate chain over all shader instructions, allocating iterators + closures, and is called per render target (twice per draw via CreateRenderState and HasPixelColorExport). Replace with a manual scan producing the identical mask — no allocation, and it removes an authored-LINQ use the repo bans. * [Perf] De-LINQ per-draw render-target selection in AgcExports The bound-render-target selection used Where(...).OrderBy(...).ToArray() (plus a second Where/ToArray fallback) on every translated draw, allocating LINQ iterators + closures. Replace with an explicit filter into a pre-sized list + List.Sort by slot; slots are distinct so this matches the stable OrderBy. Same result, no per-draw LINQ allocations. * [Perf] De-LINQ per-draw render-target validation in the Vulkan presenter SubmitOffscreenTranslatedDraw validated its render targets with targets.Any(...) twice plus targets.Select(a=>a.Address).Distinct().Count() (a per-draw HashSet), and broadcast a single blend with Enumerable.Repeat(...).ToArray(). Targets are <= 8, so replace with manual scans (invalid-target check; combined dimension-mismatch + pairwise aliasing check) and Array.Fill. Same results, no per-draw LINQ allocations. * [Perf] Binary-search VirtualQuery region lookup (SortedList) _mappedRegions was an unordered Dictionary, so TryFindVirtualQueryRegionLocked scanned every region for containment/next — O(n) per sceKernelVirtualQuery and O(n^2) when an allocator walks the address space with the findNext flag. Store regions in a SortedList keyed by base address (every write already uses the region's own address as the key) and find the containing/next region with a binary search over the sorted keys. Also drops a now-redundant Values.OrderBy. Non-overlapping regions assumed (mmap semantics), so only the floor region can contain the query. Behavior-preserving; worth spot-checking VirtualQuery-heavy titles. * [Perf] Remove stray CLI packages.lock.json committed by mistake git add -A in an earlier commit swept in a regenerated src/SharpEmu.CLI/packages.lock.json. main tracks no lock files (central package management, no RestorePackagesWithLockFile), and REUSE.toml no longer covers packages.lock.json, so the committed file failed the REUSE Compliance check. Remove it.
This commit is contained in:
committed by
GitHub
parent
a8be1daca4
commit
c5a82c1065
@@ -598,7 +598,7 @@ public sealed partial class DirectExecutionBackend
|
||||
}
|
||||
|
||||
*(ulong*)(argPackPtr + 96) = unchecked((ulong)transferStub);
|
||||
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_FIBER"), "1", StringComparison.Ordinal))
|
||||
if (_logFiber)
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] fiber.context-transfer rip=0x{transferTarget.Rip:X16} " +
|
||||
@@ -1292,7 +1292,7 @@ public sealed partial class DirectExecutionBackend
|
||||
}
|
||||
|
||||
int returnValue;
|
||||
if (IsNoBlockLeafImport(importStubEntry.Nid))
|
||||
if (importStubEntry.IsNoBlockLeaf)
|
||||
{
|
||||
cpuContext.ClearRaxWriteFlag();
|
||||
returnValue = export.Function(cpuContext);
|
||||
|
||||
Reference in New Issue
Block a user