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]);
                }
            }
        }
Example #2
0
        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));
        }
Example #3
0
        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 _));
        }
Example #4
0
        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());
        }
Example #6
0
        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());
                }
            }
        }
Example #7
0
        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());
                }
            }
        }
    }
Example #8
0
        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));
            }
Example #10
0
        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));
        }
Example #11
0
        public void Should_fail_to_allocate_on_disposed_allocate()
        {
            using var arena = new Arena();

            arena.Dispose();

            Assert.Throws <ObjectDisposedException>(() => arena.Allocate <float>(100));
        }
Example #12
0
        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;
            }
        }
Example #13
0
        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
        }
Example #15
0
 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]));
         }
     }
 }
Example #16
0
 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();
            }
        }
Example #19
0
        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);
            }
        }
Example #20
0
        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);
        }