public void AllocateInterrupted(int count, int interruptAfter, bool faults) { using var arena = new Arena <int>(); IEnumerable <int> Interrupted() { for (int i = 0; i < count; i++) { yield return(i); if (interruptAfter == i) { arena.Allocate(1); } } } IEnumerable <int> data = Interrupted(); if (faults) { var ex = Assert.Throws <InvalidOperationException>(() => arena.Allocate(data)); Assert.Equal("Data was allocated while the enumerator was iterating", ex.Message); } else { var seq = arena.Allocate(data); Assert.Equal(count, seq.Length); for (int i = 0; i < count; i++) { Assert.Equal(i, seq[i]); } } }
public void Should_fail_to_allocatebytes_beyond_size() { using var arena = new Arena(1024); var segment1 = arena.Allocate <byte>(1000); var segment2 = arena.Allocate <byte>(24); Assert.Throws <OutOfMemoryException>(() => arena.Allocate <byte>(1)); }
public void Should_fail_to_tryallocate_beyond_size() { using var arena = new Arena(1024); var segment1 = arena.Allocate <byte>(1000); var segment2 = arena.Allocate <byte>(24); Assert.False(arena.TryAllocate <byte>(1, out _)); }
public void TestRecentPolicy() { using (var arena = new Arena <int>(new ArenaOptions( blockSizeBytes: 1024, retentionPolicy: RetentionPolicy.Recent))) { Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(1024, arena.CapacityBytes()); // one page // allocate a big chunk and reset; should keep everything for (int i = 0; i < 10; i++) { arena.Allocate(512); } Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything // allocate another big chunk and reset; should keep everything for (int i = 0; i < 10; i++) { arena.Allocate(512); } Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything // allocate a small chunk and reset; should keep the small size for (int i = 0; i < 5; i++) { arena.Allocate(512); } Assert.Equal(10240, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(11264, arena.CapacityBytes()); // keeps enough for the recent data // allocate another big chunk and reset; should keep everything for (int i = 0; i < 10; i++) { arena.Allocate(512); } Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything } }
public void AllocateFromSequenceUntyped(int count) { using var arena = new Arena(new ArenaOptions(blockSizeBytes: 16 * sizeof(int))); arena.Allocate <int>(13); // just to make it interesting var sequence = arena.Allocate(Enumerable.Range(42, count)); Assert.Equal(count, sequence.Length); for (int i = 0; i < count; i++) { Assert.Equal(42 + i, sequence[i]); } Assert.Equal((13 + count) * sizeof(int), arena.AllocatedBytes()); }
public void TestDefaultPolicy() { using var arena = new Arena <int>(new ArenaOptions( blockSizeBytes: 1024, retentionPolicy: RetentionPolicy.Default)); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(1024, arena.CapacityBytes()); // one page // note that the decay cycle is jagged because of page sizes, but the important // thing is that we don't retain everything, nor do we release everything; // over time, it gets gradually smaller for (int loop = 0; loop < 5; loop++) { // allocate a big chunk and reset; should keep everything for (int i = 0; i < 10; i++) { arena.Allocate(512); } Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // 100% var expectedSizes = new int[] { 21504, 18432, 17408, 15360, 14336, 12288, 11264, 10240, 9216, 8192, 7168, 7168, 6144, 6144, 5120, 5120, 4096, 4096, 3072, 3072, 3072, 3072, 3072, 3072, 3072 }; // can't release the last page, as keep touching it if (IntPtr.Size == 8) // sizeof impact { expectedSizes[1] = 19456; } for (int i = 1; i < expectedSizes.Length; i++) { // allocate a small chunk; decay applies arena.Allocate(512); Assert.Equal(2048, arena.AllocatedBytes()); Assert.Equal(expectedSizes[i - 1], arena.CapacityBytes()); arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(expectedSizes[i], arena.CapacityBytes()); } } }
public void TestFastDecayPolicy() { using var arena = new Arena <int>(new ArenaOptions( blockSizeBytes: 1024, retentionPolicy: RetentionPolicy.Decay(0.5F))); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(1024, arena.CapacityBytes()); // one page // note that the decay cycle is jagged because of page sizes, but the important // thing is that we don't retain everything, nor do we release everything; // over time, it gets gradually smaller for (int loop = 0; loop < 5; loop++) { // allocate a big chunk and reset; should keep everything for (int i = 0; i < 10; i++) { arena.Allocate(512); } Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // 100% Span <int> expectedSizes = stackalloc int[] { 21504, 11264, 6144, 3072, 3072, 3072, 3072, 3072, 3072, 3072 }; // can't release the last page, as keep touching it for (int i = 1; i < expectedSizes.Length; i++) { // allocate a small chunk; decay applies arena.Allocate(512); Assert.Equal(2048, arena.AllocatedBytes()); Assert.Equal(expectedSizes[i - 1], arena.CapacityBytes()); arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(expectedSizes[i], arena.CapacityBytes()); } } } }
public void Copy() { using (Arena <int> from = new Arena <int>(_blockSizeFive), to = new Arena <int>(_blockSizeFive)) { var source = from.Allocate(100); Assert.False(source.IsSingleSegment); Assert.Equal(100, source.Length); var iter = source.GetEnumerator(); int i = 0; while (iter.MoveNext()) { iter.Current = i++; } var doubles = to.Allocate(source, (in int x) => 2 * x); Assert.False(doubles.IsSingleSegment); Assert.Equal(100, doubles.Length); i = 0; iter = doubles.GetEnumerator(); while (iter.MoveNext()) { Assert.Equal(2 * i++, iter.Current); } } }
public void SliceAndDice() { using (var arena = new Arena <int>(new ArenaOptions(blockSizeBytes: 16 * sizeof(int)))) { var alloc = arena.Allocate(2048); int i = 0, spanCount = 0; foreach (var span in alloc.Spans) { spanCount++; for (int j = 0; j < span.Length; j++) { span[j] = i++; } } Assert.True(spanCount >= 10); var all = alloc.Slice(0, (int)alloc.Length); Assert.Equal(2048, all.Length); Check(all, 0); var small = alloc.Slice(8, 4); Assert.Equal(4, small.Length); Check(small, 8); var subSection = alloc.Slice(1250); Assert.Equal(2048 - 1250, subSection.Length); Check(subSection, 1250); Assert.Throws <ArgumentOutOfRangeException>(() => alloc.Slice(1, (int)alloc.Length)); }
public void Should_take_into_account_type_sizes() { using var arena = new Arena(101); //the initial size is in bytes, but memory needed for 100 floats is much more than 101 bytes... Assert.Throws <OutOfMemoryException>(() => arena.Allocate <float>(100)); }
public void Should_fail_to_allocate_on_disposed_allocate() { using var arena = new Arena(); arena.Dispose(); Assert.Throws <ObjectDisposedException>(() => arena.Allocate <float>(100)); }
public void Can_allocate_span_and_use_memory() { using var arena = new Arena(); var array = arena.Allocate <byte>(100); for (byte i = 0; i < array.Length; i++) { array[i] = i; } }
public void Positions() { using (Arena <int> from = new Arena <int>(_blockSizeFive)) { from.Allocate(42); // just want an arbitrary offset here var source = from.Allocate(100); Assert.Throws <IndexOutOfRangeException>(() => source.GetPosition(-1)); Assert.Throws <IndexOutOfRangeException>(() => source.GetPosition(101)); Assert.Equal(source.GetPosition(0), source.Start); Assert.Equal(source.GetPosition(100), source.End); for (int i = 0; i <= 100; i++) { var pos = source.GetPosition(i); var offset = pos.TryGetOffset().Value; Assert.Equal(i + 42, offset); } } }
public void TestEverythingPolicy() { using var arena = new Arena<int>(new ArenaOptions( blockSizeBytes: 1024, retentionPolicy: RetentionPolicy.Everything)); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(1024, arena.CapacityBytes()); // one page // allocate a big chunk and reset; should keep everything for (int i = 0; i < 10; i++) arena.Allocate(512); Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything // allocate another big chunk and reset; should keep everything for (int i = 0; i < 10; i++) arena.Allocate(512); Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything // allocate a small chunk and reset; should keep everything for (int i = 0; i < 5; i++) arena.Allocate(512); Assert.Equal(10240, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything // allocate another big chunk and reset; should keep everything for (int i = 0; i < 10; i++) arena.Allocate(512); Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // keeps everything }
public void Alloc_Arena_NoSharing() { for (int i = 0; i < _sizes.Length; i++) { _arenaAllocs.Clear(); _multiArenaNoSharing.Reset(); var arr = _sizes[i]; for (int j = 0; j < arr.Length; j++) { _arenaAllocs.Add(_multiArenaNoSharing.Allocate <int>(arr[j])); } } }
public void Alloc_ArenaT() { for (int i = 0; i < _sizes.Length; i++) { _arenaAllocs.Clear(); _arena.Reset(); var arr = _sizes[i]; for (int j = 0; j < arr.Length; j++) { _arenaAllocs.Add(_arena.Allocate(arr[j])); } } }
public void ArenaReferenceWorks() { using var arena = new Arena <char>(); var arr = arena.Allocate(5); ReadOnlySpan <char> c = "abcde".AsSpan(); c.CopyTo(arr); var r = arr.GetReference(2); Assert.Equal(5, arr.Length); Assert.Equal('c', r.Value); Assert.Equal('c', (char)r); r.Value = 'q'; Assert.Equal('q', arr.FirstSpan[2]); Assert.Equal("abqde", new string(arr.ToArray())); }
public void TestNothingPolicy() { using var arena = new Arena<int>(new ArenaOptions( blockSizeBytes: 1024, retentionPolicy: RetentionPolicy.Nothing)); for (int loop = 0; loop < 5; loop++) { Assert.Equal(0, arena.AllocatedBytes()); Assert.Equal(1024, arena.CapacityBytes()); // one page for (int i = 0; i < 10; i++) arena.Allocate(512); Assert.Equal(20480, arena.AllocatedBytes()); Assert.Equal(21504, arena.CapacityBytes()); // EOF allocates an extra block arena.Reset(); } }
public void WriteAndRead() { using (var arena = new Arena <int>(new ArenaOptions(blockSizeBytes: 1024 * sizeof(int)))) { var rand = new Random(43134114); var arr = new Sequence <int> [100]; for (int i = 0; i < arr.Length; i++) { arr[i] = arena.Allocate(rand.Next(0, 512)); } long total = Write(arr); Assert.Equal(total, ReadSpans(arr)); Assert.Equal(total, ReadSegments(arr)); Assert.Equal(total, ReadElements(arr)); var singleSegmentCount = arr.Count(x => x.IsSingleSegment); // we expect "some" (not zero, not all) single-segments Assert.NotEqual(0, singleSegmentCount); Assert.NotEqual(arr.Length, singleSegmentCount); } }
public ArenaBenchmarks() { // allocate a uint on all 3 allocators, as // we want to force thunking (we test with int later) // (this actually only impacts "no padding", but ... // let's be fair) _multiArenaPadding.Allocate <uint>(); _multiArenaNoPadding.Allocate <uint>(); _multiArenaNoSharing.Allocate <uint>(); _multiArenaPadding.Reset(); _multiArenaNoPadding.Reset(); _multiArenaNoSharing.Reset(); var rand = new Random(43134114); _sizes = new int[100][]; for (int i = 0; i < _sizes.Length; i++) { int[] arr = _sizes[i] = new int[rand.Next(10, 100)]; for (int j = 0; j < arr.Length; j++) { arr[j] = rand.Next(1024); } } _maxCount = _sizes.Max(x => x.Length); _arenaAllocs = new List <Sequence <int> >(_maxCount); _arrayAllocs = new List <int[]>(_maxCount); _poolAllocs = new List <ArraySegment <int> >(_maxCount); var firstArray = _sizes[0]; _arrayRW = new int[firstArray.Length][]; _arenaRW = new Sequence <int> [firstArray.Length]; _poolRW = new ArraySegment <int> [firstArray.Length]; _rwArena = new Arena <int>(); for (int i = 0; i < firstArray.Length; i++) { int len = firstArray[i]; _arrayRW[i] = new int[len]; _arenaRW[i] = _rwArena.Allocate(len); var rented = ArrayPool <int> .Shared.Rent(len); _poolRW[i] = new ArraySegment <int>(rented, 0, len); } var expected = Write(_arrayRW); WriteSpans(_arenaRW).AssertIs(expected); WriteSegments(_arenaRW).AssertIs(expected); Write(_poolRW).AssertIs(expected); int n = firstArray.Sum(); ReadFor(_arrayRW).AssertIs(expected); ReadSpansFor(_arenaRW).AssertIs(expected); ReadSegmentsFor(_arenaRW).AssertIs(expected); ReadFor(_poolRW).AssertIs(expected); ReadForeach(_arrayRW).AssertIs(expected); ReadForeach(_arenaRW).AssertIs(expected); ReadForeach(_poolRW).AssertIs(expected); }