public void ReclaimedBlockShouldReinitializeToDefault() { using var memory = new HeapAllocator(_logFactory); var handle_50331651_48 = Take(memory, 9150); memory.Validate("1"); memory.Free(ref handle_50331651_48); memory.Validate("2"); var handle_16777217_18 = Take(memory, 33831); memory.Validate("3"); memory.Free(ref handle_16777217_18); memory.Validate("4"); var handle_67108866_64 = Take(memory, 22); memory.Validate("5"); memory.Free(ref handle_67108866_64); memory.Validate("6"); }
private void CheckCapacity() { if (_queues[0].Count <= 5) { // -------- Multiply by 2 the capacity LinkedIndexPoolEntry *olds = _entries; int newCapacity = _capacity * 2; _entries = (LinkedIndexPoolEntry *)HeapAllocator.New(sizeof(LinkedIndexPoolEntry) * newCapacity); MemoryHelper.Copy((byte *)olds, (byte *)_entries, sizeof(LinkedIndexPoolEntry) * _capacity); for (int i = _capacity; i < newCapacity; i++) { _entries[i].Previous = i - 1; _entries[i].Next = i + 1; _entries[i].Index = i; _entries[i].Queue = 0; } _entries[newCapacity - 1].Next = -1; // -------- Fix 0 queue : _entries[_queues[0].Last].Next = _capacity; _entries[_capacity].Previous = _queues[0].Last; _queues[0].Last = newCapacity - 1; _queues[0].Count += _capacity; // -------- _capacity = newCapacity; HeapAllocator.Free((byte *)olds); CheckCoherency(); } }
public void ShouldAssignManyWithOne() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Velocity> .Type); var position = new Position(10, 10); const int samples = 32; var ids = new uint[samples]; em.Create(spec, ids); buffer.Assign(ids, position); buffer.Execute(); em.EntityCount.ShouldBe(32); em.EntityArrays.Count.ShouldBe(2); em.EntityArrays[0].EntityCount.ShouldBe(0); em.EntityArrays[1].EntityCount.ShouldBe(32); var positions = ids.Select(id => em.Get <Position>(id)).ToArray(); positions.ShouldAllBe(x => x == position); }
public void ShouldReplaceManyWithMany() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Position> .Type, ComponentType <Velocity> .Type); const int samples = 32; var positions = Enumerable.Range(0, samples).Select(x => new Position(x, 10)).ToArray(); var ids = new uint[samples]; em.Create(spec, ids); buffer.Replace(ids, positions.AsSpan()); buffer.Execute(); em.EntityCount.ShouldBe(32); em.EntityArrays[0].EntityCount.ShouldBe(32); var positionResults = ids.Select(id => em.Get <Position>(id)).ToArray(); positionResults.ShouldBe(positions); }
public void BasicTests() { var allocator = new HeapAllocator(1000); allocator.DebugValidateInternalState(); Assert.AreEqual(allocator.FreeSpace, 1000); HeapBlock b10 = allocator.Allocate(10); allocator.DebugValidateInternalState(); HeapBlock b100 = allocator.Allocate(100); allocator.DebugValidateInternalState(); // Check that the allocations have sufficient size. Assert.GreaterOrEqual(b10.Length, 10); Assert.GreaterOrEqual(b100.Length, 100); // Check that the amount of free space has decreased accordingly. Assert.LessOrEqual(allocator.FreeSpace, 1000 - 100 - 10); allocator.Release(b10); allocator.DebugValidateInternalState(); allocator.Release(b100); allocator.DebugValidateInternalState(); // Everything should now be freed. Assert.AreEqual(allocator.FreeSpace, 1000); allocator.Dispose(); }
public void ShouldDeleteManyEntities() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Position> .Type, ComponentType <Velocity> .Type); const int samples = 32; var ids = new uint[samples]; em.Create(spec, ids); var idsToDelete = new[] { ids[0], ids[11], ids[22], ids[23], ids[3], ids[2], ids[15], ids[17], ids[29], ids[21] }; buffer.Delete(idsToDelete); buffer.Execute(); em.EntityCount.ShouldBe(samples - idsToDelete.Length); em.EntityArrays[0].EntityCount.ShouldBe(samples - idsToDelete.Length); var entities = em.EntityArrays[0].AllChunks[0].Entities.ToArray(); var remainingIds = entities.Select(x => x.ID).ToArray(); remainingIds.Any(x => idsToDelete.Contains(x)).ShouldBe(false); var otherIds = ids.Where(x => !idsToDelete.Contains(x)).ToArray(); remainingIds.All(x => otherIds.Contains(x)).ShouldBe(true); }
public void Coalescing() { var allocator = new HeapAllocator(100); allocator.DebugValidateInternalState(); // Try to allocate ten blocks. These should succeed, because the heap should not be fragmented yet. var blocks10 = Enumerable.Range(0, 10).Select(x => allocator.Allocate(10)).ToArray(); allocator.DebugValidateInternalState(); Assert.IsTrue(blocks10.All(b => b.Length == 10)); Assert.IsTrue(allocator.Full); // Release all of them. foreach (var b in blocks10) { allocator.Release(b); allocator.DebugValidateInternalState(); } // Now try to allocate the entire heap. It should succeed, because everything has been freed. Assert.AreEqual(allocator.Allocate(100).Length, 100); allocator.DebugValidateInternalState(); allocator.Dispose(); }
public void Release() { if (_entries != null) { HeapAllocator.Free((byte *)_entries); _entries = null; } }
public void EntityPoolNewMemoryFailure() { using var heap = new HeapAllocator(_logFactory); using var arr = new NativeArray <Entity>(heap, 4096); using var arr1 = new NativeArray <Entity>(heap, 4096); using var arr2 = new NativeArray <Entity>(heap, 4096); using var arr3 = new NativeArray <Entity>(heap, 4096); }
public void AllocateEntireHeap() { var allocator = new HeapAllocator(100); // Check that it's possible to allocate the entire heap. Assert.AreEqual(allocator.Allocate(100).Length, 100); allocator.Dispose(); }
public void Release() { if (_capacity > 0) { HeapAllocator.Free((byte *)_entries); HeapAllocator.Free((byte *)_queues); _queueStack.Release(); _capacity = -1; } }
public void HeapShouldAllocate() { //arrange using var memory = new HeapAllocator(_logFactory); //act var handle = memory.Take(1024); //assert handle.Address.ShouldNotBe(IntPtr.Zero); }
public StackedIndexPoolUnsafe(int capacity, int idOffset) { _idOffset = idOffset; _entries = (int *)HeapAllocator.New(capacity * sizeof(int)); for (int i = 0; i < capacity; i++) { _entries[i] = i + idOffset; } _bottom = 0; _capacity = capacity; }
public void ShouldRemoveManyWithMany() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Velocity> .Type, ComponentType <Position> .Type, ComponentType <Filler> .Type); const int samples = 32; var ids = new uint[samples]; em.Create(spec, ids); var idsToChange = new[] { ids[0], ids[11], ids[22], ids[23], ids[3], ids[2], ids[15], ids[17], ids[29], ids[21] }; var remainingIds = ids.Where(x => !idsToChange.Contains(x)).ToArray(); var typesToRemove = new[] { spec.ComponentTypes[1], spec.ComponentTypes[2] }; buffer.Remove(idsToChange, typesToRemove); buffer.Execute(); em.EntityCount.ShouldBe(samples); em.EntityArrays.Count.ShouldBe(2); em.EntityArrays[0].EntityCount.ShouldBe(samples - idsToChange.Length); em.EntityArrays[1].EntityCount.ShouldBe(idsToChange.Length); var entities0 = em.EntityArrays[0].AllChunks[0].Entities.ToArray(); entities0.Any(x => idsToChange.Contains(x.ID)).ShouldBe(false); entities0.All(x => remainingIds.Contains(x.ID)).ShouldBe(true); var entities1 = em.EntityArrays[1].AllChunks[0].Entities.ToArray(); entities1.Any(x => remainingIds.Contains(x.ID)).ShouldBe(false); entities1.All(x => idsToChange.Contains(x.ID)).ShouldBe(true); var positionResults = idsToChange.Select(id => em.Has <Position>(id)).ToArray(); positionResults.ShouldAllBe(x => x == false); var fillerResults = idsToChange.Select(id => em.Has <Filler>(id)).ToArray(); fillerResults.ShouldAllBe(x => x == false); var velocityResults = idsToChange.Select(id => em.Has <Velocity>(id)).ToArray(); velocityResults.ShouldAllBe(x => x == true); }
public void ShouldCreateManyEntity() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory, 8); var spec = new EntitySpec(ComponentType <Position> .Type, ComponentType <Velocity> .Type); buffer.Create(spec, 16384); buffer.Execute(); em.EntityCount.ShouldBe(16384); em.EntityArrays[0].EntityCount.ShouldBe(16384); }
private void EnsureCpacity(int n) { if (n >= _capacity) { int newCapacity = _capacity * 2; int *newEntries = (int *)HeapAllocator.New(newCapacity * sizeof(int)); MemoryHelper.Copy((byte *)_entries, (byte *)newEntries, _capacity * sizeof(int)); HeapAllocator.Free((byte *)_entries); for (int i = _capacity; i < newCapacity; i++) { newEntries[i] = i + _idOffset; } _entries = newEntries; _capacity = newCapacity; } }
public void ShouldReplaceOne() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Position> .Type, ComponentType <Velocity> .Type); var id = em.Create(spec); buffer.Replace(id, new Position(10, 10)); buffer.Execute(); em.EntityCount.ShouldBe(1); em.EntityArrays[0].EntityCount.ShouldBe(1); em.Get <Position>(id).ShouldBe(new Position(10, 10)); }
public void ShouldRemoveOne() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Velocity> .Type, ComponentType <Position> .Type); var id = em.Create(spec); buffer.Remove <Position>(id); buffer.Execute(); em.EntityCount.ShouldBe(1); em.EntityArrays.Count.ShouldBe(2); em.EntityArrays[0].EntityCount.ShouldBe(0); em.EntityArrays[1].EntityCount.ShouldBe(1); em.Has <Position>(id).ShouldBe(false); }
public void OrphanBlockWithSizeZeroShouldReclaim() { using var memory = new HeapAllocator(_logFactory); var handle0 = memory.Take(24); //memory.Validate(); var handle1 = memory.Take(24); //memory.Validate(); var handle2 = memory.Take(24); //memory.Validate(); var handle4 = memory.Take(24); //memory.Validate(); memory.Free(ref handle1); //memory.Validate(); memory.Free(ref handle0); //memory.Validate(); var handle5 = memory.Take(24); //memory.Validate(); var handle6 = memory.Take(24); //memory.Validate(); memory.Free(ref handle4); //memory.Validate(); memory.Free(ref handle2); //memory.Validate(); memory.Free(ref handle6); //memory.Validate(); memory.Free(ref handle5); //memory.Validate(); }
public void ShouldDeleteEntityOnLastComponentOne() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Position> .Type, ComponentType <Velocity> .Type); const int samples = 32; var ids = new uint[samples]; em.Create(spec, ids); buffer.Remove(ids, spec.ComponentTypes); buffer.Execute(); em.EntityCount.ShouldBe(0); em.EntityArrays.Count.ShouldBe(1); em.EntityArrays[0].EntityCount.ShouldBe(0); }
public void ShouldUpdateManyWithMany() { using var memory = new HeapAllocator(_logFactory); using var em = new EntityManager(_logFactory, memory); using var buffer = new EntityCommandBuffer(em, memory); var spec = new EntitySpec(ComponentType <Velocity> .Type); const int samples = 32; var ids = new uint[samples]; em.Create(spec, ids); var idsToChange = new[] { ids[0], ids[11], ids[22], ids[23], ids[3], ids[2], ids[15], ids[17], ids[29], ids[21] }; var remainingIds = ids.Where(x => !idsToChange.Contains(x)).ToArray(); var positions = idsToChange.Select(x => new Position((int)x, 10)).ToArray(); buffer.Update(idsToChange, positions.AsSpan()); buffer.Execute(); em.EntityCount.ShouldBe(samples); em.EntityArrays.Count.ShouldBe(2); em.EntityArrays[0].EntityCount.ShouldBe(samples - idsToChange.Length); em.EntityArrays[1].EntityCount.ShouldBe(idsToChange.Length); var entities0 = em.EntityArrays[0].AllChunks[0].Entities.ToArray(); entities0.Any(x => idsToChange.Contains(x.ID)).ShouldBe(false); entities0.All(x => remainingIds.Contains(x.ID)).ShouldBe(true); var entities1 = em.EntityArrays[1].AllChunks[0].Entities.ToArray(); entities1.Any(x => remainingIds.Contains(x.ID)).ShouldBe(false); entities1.All(x => idsToChange.Contains(x.ID)).ShouldBe(true); var positionResults = idsToChange.Select(id => em.Get <Position>(id)).ToArray(); positionResults.ShouldBe(positions); }
/********************************************************************************/ // -------- Queues public int GetFreeQueue() { int tmp = _queueStack.Pop(); if (_queueStack.Capacity > _queueCount) { int newQueueCount = _queueStack.Capacity; LinkedIndexPoolQueue *_oldQueues = _queues; _queues = (LinkedIndexPoolQueue *)HeapAllocator.New(sizeof(LinkedIndexPoolQueue) * newQueueCount); for (int i = 0; i < _queueCount; i++) { _queues[i] = _oldQueues[i]; } for (int i = _queueCount; i < newQueueCount; i++) { _queues[i].First = _queues[i].Last = -1; _queues[i].Index = i; _queues[i].Count = 0; } } return(tmp); }
public LinkedIndexPool(int capacity, int queueCount, bool check = false) { if (capacity < 8) { capacity = 8; } if (queueCount < 2) { queueCount = 2; } // -------- Initialize entries _entries = (LinkedIndexPoolEntry *)HeapAllocator.New(sizeof(LinkedIndexPoolEntry) * capacity); _capacity = capacity; for (int i = 0; i < capacity; i++) { _entries[i].Previous = i - 1; _entries[i].Next = i + 1; _entries[i].Index = i; _entries[i].Queue = 0; } _entries[0].Previous = -1; _entries[capacity - 1].Next = -1; // -------- Initialize queues _queues = (LinkedIndexPoolQueue *)HeapAllocator.New(sizeof(LinkedIndexPoolQueue) * queueCount); _queueCount = queueCount; for (int i = 0; i < queueCount; i++) { _queues[i].First = _queues[i].Last = -1; _queues[i].Index = i; _queues[i].Count = 0; } _queues[0].First = 0; _queues[0].Last = capacity - 1; _queues[0].Count = capacity; // -------- Initialize queues stack _queueStack = new StackedIndexPoolUnsafe(queueCount, 2); // -------- All is ok... _checkIt = check; }
private void LoadFromStream(Stream stream) { Quetzal quetzal = Quetzal.FromStream(stream); // make sure the save file matches the game file byte[] ifhd1 = quetzal["IFhd"]; byte[] ifhd2 = image.GetOriginalIFHD(); if (ifhd1 == null || ifhd1.Length != ifhd2.Length) throw new ArgumentException("Missing or invalid IFhd block"); for (int i = 0; i < ifhd1.Length; i++) if (ifhd1[i] != ifhd2[i]) throw new ArgumentException("Saved game doesn't match this story file"); // load the stack byte[] newStack = quetzal["Stks"]; if (newStack == null) throw new ArgumentException("Missing Stks block"); Array.Copy(newStack, stack, newStack.Length); sp = (uint)newStack.Length; // save the protected area of RAM byte[] protectedRam = new byte[protectionLength]; image.ReadRAM(protectionStart, protectionLength, protectedRam); // load the contents of RAM, preferring a compressed chunk byte[] origRam = image.GetOriginalRAM(); byte[] delta = quetzal["CMem"]; if (delta != null) { byte[] newRam = Quetzal.DecompressMemory(origRam, delta); image.SetRAM(newRam, false); } else { // look for an uncompressed chunk byte[] newRam = quetzal["UMem"]; if (newRam == null) throw new ArgumentException("Missing CMem/UMem blocks"); else image.SetRAM(newRam, true); } // restore protected RAM image.WriteRAM(protectionStart, protectedRam); // pop a call stub to restore registers CallStub stub = PopCallStub(); pc = stub.PC; fp = stub.FramePtr; frameLen = ReadFromStack(fp); localsPos = ReadFromStack(fp + 4); execMode = ExecutionMode.Code; // restore the heap if available if (quetzal.Contains("MAll")) { heap = new HeapAllocator(quetzal["MAll"], HandleHeapMemoryRequest); if (heap.BlockCount == 0) heap = null; else heap.MaxSize = maxHeapSize; } // give the original save opcode a result of -1 to show that it's been restored PerformDelayedStore(stub.DestType, stub.DestAddr, 0xFFFFFFFF); }
private void op_malloc(uint[] args) { uint size = args[0]; if ((int)size <= 0) { args[1] = 0; return; } if (heap == null) { uint oldEndMem = image.EndMem; heap = new HeapAllocator(oldEndMem, HandleHeapMemoryRequest); heap.MaxSize = maxHeapSize; args[1] = heap.Alloc(size); if (args[1] == 0) { heap = null; image.EndMem = oldEndMem; } } else { args[1] = heap.Alloc(size); } }
public void RandomStressTest() { const int HeapSize = 1_000_000; const int NumBlocks = 1_000; const int NumRounds = 20; const int MaxAlloc = 10_000; const int OperationsPerRound = 10_000; int numAllocs = 0; int numReleases = 0; int numFailed = 0; var rnd = new System.Random(293875); var allocator = new HeapAllocator(HeapSize); var blocks = Enumerable.Range(0, NumBlocks).Select(x => new HeapBlock()).ToArray(); // Stress test the allocator by doing a bunch of random allocs and deallocs and // try to verify that allocator internal asserts don't fire, and free space behaves // as expected. for (int i = 0; i < NumRounds; ++i) { Assert.IsTrue(allocator.Empty); // Perform random alloc/dealloc operations for (int j = 0; j < OperationsPerRound; ++j) { ulong before = allocator.FreeSpace; int b = rnd.Next(NumBlocks); int size = 0; if (blocks[b].Empty) { size = rnd.Next(1, MaxAlloc); blocks[b] = allocator.Allocate((ulong)size); if (blocks[b].Empty) { size = 0; ++numFailed; } else { size = (int)blocks[b].Length; } ++numAllocs; } else { size = -(int)blocks[b].Length; allocator.Release(blocks[b]); blocks[b] = new HeapBlock(); ++numReleases; } ulong after = allocator.FreeSpace; Assert.AreEqual((long)after, (long)before - size); } for (int b = 0; b < NumBlocks; ++b) { if (!blocks[b].Empty) { allocator.Release(blocks[b]); blocks[b] = new HeapBlock(); } } Assert.IsTrue(allocator.Empty); } Debug.Log($"Allocs: {numAllocs}, Releases: {numReleases}, Failed: {numFailed}"); allocator.Dispose(); }
public void AllocationsDontOverlap() { // Make sure that allocations given by the allocator are disjoint (i.e. don't alias). const int HeapSize = 1_000_000; const int NumBlocks = 1_000; const int MaxAlloc = 10_000; const int OperationsPerRound = 10_000; var rnd = new System.Random(9283572); var allocator = new HeapAllocator(HeapSize); var blocks = Enumerable.Range(0, NumBlocks).Select(x => new HeapBlock()).ToArray(); var inUse = new ulong[HeapSize / 8 + 1]; Func <ulong, (ulong, int)> qword = (ulong i) => (i / 64, (int)(i % 64)); // Perform random alloc/dealloc operations for (int i = 0; i < OperationsPerRound; ++i) { int b = rnd.Next(NumBlocks); const ulong kAllOnes = ~0UL; int size = 0; if (blocks[b].Empty) { size = rnd.Next(1, MaxAlloc); blocks[b] = allocator.Allocate((ulong)size); // Mark the block as allocated, and check that it wasn't allocated. // Do tests and sets entire qwords at a time so it's fast var begin = qword(blocks[b].begin); var end = qword(blocks[b].end); if (begin.Item1 == end.Item1) { ulong qw = begin.Item1; ulong mask = kAllOnes << begin.Item2; mask &= ~(kAllOnes << end.Item2); Assert.IsTrue((inUse[qw] & mask) == 0, "Elements were already allocated"); inUse[qw] |= mask; } else { ulong qw = begin.Item1; ulong mask = kAllOnes << begin.Item2; Assert.IsTrue((inUse[qw] & mask) == 0, "Elements were already allocated"); inUse[qw] |= mask; for (qw = begin.Item1 + 1; qw < end.Item1; ++qw) { mask = kAllOnes; Assert.IsTrue((inUse[qw] & mask) == 0, "Elements were already allocated"); inUse[qw] |= mask; } qw = end.Item1; mask = ~(kAllOnes << end.Item2); Assert.IsTrue((inUse[qw] & mask) == 0, "Elements were already allocated"); inUse[qw] |= mask; } } else { allocator.Release(blocks[b]); // Mark the block as not allocated, and check that it was allocated. var begin = qword(blocks[b].begin); var end = qword(blocks[b].end); if (begin.Item1 == end.Item1) { ulong qw = begin.Item1; ulong mask = kAllOnes << begin.Item2; mask &= ~(kAllOnes << end.Item2); Assert.IsTrue((inUse[qw] & mask) == mask, "Elements were not allocated"); inUse[qw] &= ~mask; } else { ulong qw = begin.Item1; ulong mask = kAllOnes << begin.Item2; Assert.IsTrue((inUse[qw] & mask) == mask, "Elements were not allocated"); inUse[qw] &= ~mask; for (qw = begin.Item1 + 1; qw < end.Item1; ++qw) { mask = kAllOnes; Assert.IsTrue((inUse[qw] & mask) == mask, "Elements were not allocated"); inUse[qw] &= ~mask; } qw = end.Item1; mask = ~(kAllOnes << end.Item2); Assert.IsTrue((inUse[qw] & mask) == mask, "Elements were not allocated"); inUse[qw] &= ~mask; } blocks[b] = new HeapBlock(); } } allocator.Dispose(); }