Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@
**Context:** Guest MMU / `VirtualMemory.cs` (`CopyFromRegions`, `CopyToRegions`)
**Learning:** Sequential tracking over Spans with an external `copied` counter and range indexer (`span[copied..]`) introduces local bounds check validation overhead. Reassigning the span reference in place via `span = span.Slice(chunkLength)` eliminates this and simplifies hot loops into `!span.IsEmpty` checks.
**Action:** Use idiomatic slice-reassignment (`span = span.Slice(length)`) instead of external integer trackers in loop conditions over `Span<T>` sequential memory operations to reduce arithmetic overhead.

## 2026-10-06 - Zero-Allocation Search in KernelMemoryCompatExports
**Context:** src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs
**Learning:** Found an O(N log N) LINQ-based sorting/filtering bottleneck (`.Values.Where(...).OrderBy(...)`) inside the `KernelDirectMemoryQuery` lock. This was causing GC pressure due to enumerator and delegate allocations on a hot path during kernel HLE queries.
**Action:** Replaced it with an O(N) allocation-free manual search loop using standard variables (`matchStart`, `matchEnd`) to natively handle uniqueness and prioritization.
26 changes: 15 additions & 11 deletions src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3706,19 +3706,23 @@ public static int KernelDirectMemoryQuery(CpuContext ctx)

lock (_memoryGate)
{
var candidates = _directAllocations.Values
.Where(block => findNext
// Performance optimization: Replaced O(N log N) LINQ sorting and allocating Where/OrderBy chain with a single-pass O(N) allocation-free manual search loop.
foreach (var block in _directAllocations.Values)
{
var isMatch = findNext
? block.Start + block.Length > offset
: offset >= block.Start && offset < block.Start + block.Length)
.OrderBy(block => block.Start);
: offset >= block.Start && offset < block.Start + block.Length;

foreach (var block in candidates)
{
found = true;
matchStart = block.Start;
matchEnd = block.Start + block.Length;
matchMemoryType = block.MemoryType;
break;
if (isMatch)
{
if (!found || block.Start < matchStart)
{
found = true;
matchStart = block.Start;
matchEnd = block.Start + block.Length;
matchMemoryType = block.MemoryType;
}
}
}
}

Expand Down
Loading