fix some bugs in MapHeap that were breaking libsnes savestates

This commit is contained in:
nattthebear 2017-06-10 16:57:57 -04:00
parent baf7a7973b
commit 0bcdeee1e7
1 changed files with 69 additions and 5 deletions

View File

@ -142,13 +142,15 @@ namespace BizHawk.Emulation.Cores.Waterbox
private Bin GetBinForEndPageEnsureAllocated(int page, Bin start) private Bin GetBinForEndPageEnsureAllocated(int page, Bin start)
{ {
Bin curr = start; Bin curr = start;
while (curr != null && curr.StartPage + curr.PageCount < page) while (curr != null)
{ {
if (curr.Free) if (curr.Free)
return null; return null;
if (curr.EndPage >= page)
return curr;
curr = curr.Next; curr = curr.Next;
} }
return curr; return curr; // ran off the end
} }
public ulong Map(ulong size, MemoryBlock.Protection prot) public ulong Map(ulong size, MemoryBlock.Protection prot)
@ -184,6 +186,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
Memory.Protect(ret, totalSize, prot); Memory.Protect(ret, totalSize, prot);
Used += totalSize; Used += totalSize;
Console.WriteLine($"Allocated {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)"); Console.WriteLine($"Allocated {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
//EnsureUsedInternal();
return ret; return ret;
} }
@ -235,6 +238,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
Used += newTotalSize; Used += newTotalSize;
Used -= oldTotalSize; Used -= oldTotalSize;
Console.WriteLine($"Reallocated from {oldTotalSize} bytes to {newTotalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)"); Console.WriteLine($"Reallocated from {oldTotalSize} bytes to {newTotalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
//EnsureUsedInternal();
return start; return start;
} }
// could not increase in place, so move // could not increase in place, so move
@ -260,6 +264,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
ss.CopyTo(ds); ss.CopyTo(ds);
Memory.Protect(ret, oldSize, oldStartBin.Protection); Memory.Protect(ret, oldSize, oldStartBin.Protection);
UnmapPagesInternal(oldStartPage, oldNumPages, oldStartBin); UnmapPagesInternal(oldStartPage, oldNumPages, oldStartBin);
//EnsureUsedInternal();
return ret; return ret;
} }
else else
@ -272,6 +277,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
// shrink in place // shrink in place
var s = GetBinForStartPage(newEndPage); var s = GetBinForStartPage(newEndPage);
UnmapPagesInternal(newEndPage, oldEndPage - newEndPage, s); UnmapPagesInternal(newEndPage, oldEndPage - newEndPage, s);
//EnsureUsedInternal();
return start; return start;
} }
else else
@ -309,12 +315,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
var endPage = startPage + numPages; var endPage = startPage + numPages;
Bin freeBin = startBin; Bin freeBin = startBin;
if (!freeBin.Free && freeBin.StartPage != startPage) if (freeBin.StartPage != startPage)
{ {
freeBin.Cleave(startPage - freeBin.StartPage); freeBin.Cleave(startPage - freeBin.StartPage);
freeBin = freeBin.Next; freeBin = freeBin.Next;
freeBin.Free = true;
} }
freeBin.Free = true;
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None; MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
while (freeBin.EndPage < endPage) while (freeBin.EndPage < endPage)
{ {
@ -322,7 +328,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
lastEaten = freeBin.Next.Protection; lastEaten = freeBin.Next.Protection;
freeBin.Next = freeBin.Next.Next; freeBin.Next = freeBin.Next.Next;
} }
if (freeBin.Cleave(freeBin.EndPage - endPage)) if (freeBin.Cleave(endPage - freeBin.StartPage))
{ {
freeBin.Next.Protection = lastEaten; freeBin.Next.Protection = lastEaten;
} }
@ -331,6 +337,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift; var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
Used -= totalSize; Used -= totalSize;
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)"); Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
//EnsureUsedInternal();
} }
public void Dispose() public void Dispose()
@ -342,6 +349,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
} }
private ulong CalcUsedInternal()
{
ulong ret = 0;
var bin = _root;
while (bin != null)
{
if (!bin.Free)
ret += (ulong)bin.PageCount << WaterboxUtils.PageShift;
bin = bin.Next;
}
return ret;
}
private void EnsureUsedInternal()
{
if (Used != CalcUsedInternal())
throw new Exception();
}
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
bw.Write(Name); bw.Write(Name);
@ -413,5 +439,43 @@ namespace BizHawk.Emulation.Cores.Waterbox
_root = scratch.Next; _root = scratch.Next;
} }
public static void StressTest()
{
var allocs = new Dictionary<ulong, ulong>();
var mmo = new MapHeap(0x36a00000000, 256 * 1024 * 1024, "ballsacks");
var rnd = new Random(12512);
for (int i = 0; i < 40; i++)
{
ulong siz = (ulong)(rnd.Next(256 * 1024) + 384 * 1024);
siz = siz / 4096 * 4096;
var ptr = mmo.Map(siz, Waterbox.MemoryBlock.Protection.RW);
allocs.Add(ptr, siz);
}
for (int i = 0; i < 20; i++)
{
int idx = rnd.Next(allocs.Count);
var elt = allocs.ElementAt(idx);
mmo.Unmap(elt.Key, elt.Value);
allocs.Remove(elt.Key);
}
for (int i = 0; i < 40; i++)
{
ulong siz = (ulong)(rnd.Next(256 * 1024) + 384 * 1024);
siz = siz / 4096 * 4096;
var ptr = mmo.Map(siz, Waterbox.MemoryBlock.Protection.RW);
allocs.Add(ptr, siz);
}
for (int i = 0; i < 20; i++)
{
int idx = rnd.Next(allocs.Count);
var elt = allocs.ElementAt(idx);
mmo.Unmap(elt.Key, elt.Value);
}
}
} }
} }