Exemple #1
0
 public unsafe void Resize(ref RawBuffer buffer, int targetSize, int copyCount)
 {
     Debug.Assert(copyCount <= buffer.Length, "Can't copy more than the capacity of the buffer.");
     Debug.Assert(copyCount <= targetSize, "Can't copy more than the target size.");
     //Only do anything if the new size is actually different from the current size.
     targetSize = 1 << (SpanHelper.GetContainingPowerOf2(targetSize));
     if (buffer.Allocated)
     {
         DecomposeId(buffer.Id, out var powerIndex, out var slotIndex);
         var currentSize = 1 << powerIndex;
         if (currentSize != targetSize)
         {
             Take(targetSize, out var newBuffer);
             Unsafe.CopyBlockUnaligned(newBuffer.Memory, buffer.Memory, (uint)copyCount);
             pools[powerIndex].Return(slotIndex);
             buffer = newBuffer;
         }
         else
         {
             //While the allocation size is equal to the target size, the buffer might not be.
             //Fortunately, if the allocation stays the same size, there's no work to be done.
             buffer.Length = targetSize;
         }
     }
     else
     {
         //Nothing to return or copy.
         Take(targetSize, out buffer);
     }
 }
Exemple #2
0
 public unsafe void ResizeToAtLeast(ref RawBuffer buffer, int targetSize, int copyCount)
 {
     Debug.Assert(copyCount <= buffer.Length, "Can't copy more than the capacity of the buffer.");
     Debug.Assert(copyCount <= targetSize, "Can't copy more than the target size.");
     //Only do anything if the new size is actually different from the current size.
     targetSize = 1 << (SpanHelper.GetContainingPowerOf2(targetSize));
     if (buffer.Allocated)
     {
         DecomposeId(buffer.Id, out var powerIndex, out var slotIndex);
         var currentSize = 1 << powerIndex;
         if (currentSize != targetSize || pools[powerIndex].GetStartPointerForSlot(slotIndex) != buffer.Memory)
         {
             TakeAtLeast(targetSize, out var newBuffer);
             Buffer.MemoryCopy(buffer.Memory, newBuffer.Memory, buffer.Length, copyCount);
             pools[powerIndex].Return(slotIndex);
             buffer = newBuffer;
         }
         else
         {
             //While the allocation size is equal to the target size, the buffer might not be.
             //Fortunately, if the allocation stays the same size and the buffer start is at its original location, we can skip doing any work.
             //(With more work, you could expand *backwards*, we just didn't bother since this is exceptionally rare anyway.
             //The typed codepath doesn't bother doing this at all, and that's fine.)
             buffer.Length = targetSize;
         }
     }
     else
     {
         //Nothing to return or copy.
         TakeAtLeast(targetSize, out buffer);
     }
 }
Exemple #3
0
 /// <summary>
 /// Creates a new memory pool.
 /// </summary>
 /// <param name="memoryPoolSize">Size of the pool in elements.</param>
 public Allocator(long memoryPoolSize, int allocationCountEstimate = 128)
 {
     this.Capacity = memoryPoolSize;
     QuickDictionary <ulong, Allocation, Array <ulong>, Array <Allocation>, Array <int>, PrimitiveComparer <ulong> > .Create(
         new PassthroughArrayPool <ulong>(), new PassthroughArrayPool <Allocation>(), new PassthroughArrayPool <int>(),
         SpanHelper.GetContainingPowerOf2(allocationCountEstimate), 3, out allocations);
 }
Exemple #4
0
 public static int GetCapacityForCount <T>(int count)
 {
     if (count == 0)
     {
         count = 1;
     }
     return((1 << SpanHelper.GetContainingPowerOf2(count * Unsafe.SizeOf <T>())) / Unsafe.SizeOf <T>());
 }
        public void Return(ref Array <T> array)
        {
            ValidateCount();
#if DEBUG
            Debug.Assert(outstandingResources.Remove(array.Memory), "The buffer being returned must come from this pool, and buffers should only be returned once.");
#endif
            pools[SpanHelper.GetContainingPowerOf2(array.Length)].Push(array.Memory);
            array = new Array <T>();
        }
Exemple #6
0
            public PowerPool(int power, int minimumBlockSize, int expectedPooledCount)
            {
                Power                       = power;
                SuballocationSize           = 1 << power;
                BlockSize                   = Math.Max(SuballocationSize, minimumBlockSize);
                Slots                       = new ManagedIdPool(expectedPooledCount);
                SuballocationsPerBlock      = BlockSize / SuballocationSize;
                SuballocationsPerBlockShift = SpanHelper.GetContainingPowerOf2(SuballocationsPerBlock);
                SuballocationsPerBlockMask  = (1 << SuballocationsPerBlockShift) - 1;
                Blocks                      = new Block[1];
                BlockCount                  = 0;

#if DEBUG
                outstandingIds = new HashSet <int>();
#if LEAKDEBUG
                outstandingAllocators = new Dictionary <string, HashSet <int> >();
#endif
#endif
            }
Exemple #7
0
            public unsafe void Take(out RawBuffer buffer)
            {
                var slot       = Slots.Take();
                var blockIndex = slot >> SuballocationsPerBlockShift;

                if (blockIndex >= Blocks.Length)
                {
                    Array.Resize(ref Blocks, 1 << SpanHelper.GetContainingPowerOf2(blockIndex + 1));
                }
                if (blockIndex >= BlockCount)
                {
#if DEBUG
                    for (int i = 0; i < blockIndex; ++i)
                    {
                        Debug.Assert(Blocks[i].Allocated, "If a block index is found to exceed the current block count, then every block preceding the index should be allocated.");
                    }
#endif
                    BlockCount = blockIndex + 1;
                    Debug.Assert(!Blocks[blockIndex].Allocated);
                    Blocks[blockIndex] = new Block(BlockSize);
                }

                var indexInBlock = slot & SuballocationsPerBlockMask;
                buffer = new RawBuffer(Blocks[blockIndex].Allocate(indexInBlock, SuballocationSize), SuballocationSize, (Power << IdPowerShift) | slot);
                Debug.Assert(buffer.Id >= 0 && Power >= 0 && Power < 32, "Slot/power should be safely encoded in a 32 bit integer.");
#if DEBUG
                const int maximumOutstandingCapacity = 1 << 29;
                Debug.Assert(outstandingIds.Count * SuballocationSize <= maximumOutstandingCapacity,
                             $"Do you actually truly really need to have {maximumOutstandingCapacity} bytes taken from this power pool, or is this a memory leak?");
                Debug.Assert(outstandingIds.Add(slot), "Should not be able to request the same slot twice.");
#if LEAKDEBUG
                var allocator = new StackTrace().ToString();
                if (!outstandingAllocators.TryGetValue(allocator, out var idsForAllocator))
                {
                    idsForAllocator = new HashSet <int>();
                    outstandingAllocators.Add(allocator, idsForAllocator);
                }
                Debug.Assert(idsForAllocator.Count < (1 << 25), "Do you actually have that many allocations for this one allocator?");
                idsForAllocator.Add(slot);
#endif
#endif
            }
 public unsafe void Resize(ref RawBuffer buffer, int targetSize, int copyCount)
 {
     //Only do anything if the new size is actually different from the current size.
     targetSize = 1 << (SpanHelper.GetContainingPowerOf2(targetSize));
     if (buffer.Length != targetSize) //Note that we don't check for allocated status- for buffers, a length of 0 is the same as being unallocated.
     {
         Take(targetSize, out var newBuffer);
         if (buffer.Length > 0)
         {
             //Don't bother copying from or re-pooling empty buffers. They're uninitialized.
             Debug.Assert(copyCount <= targetSize);
             Unsafe.CopyBlockUnaligned(newBuffer.Memory, buffer.Memory, (uint)copyCount);
             ReturnUnsafely(ref buffer);
         }
         else
         {
             Debug.Assert(copyCount == 0, "Should not be trying to copy elements from an empty span.");
         }
         buffer = newBuffer;
     }
 }
 public unsafe void ReturnUnsafely(ref RawBuffer buffer)
 {
     ValidatePinnedState(true);
     pools[SpanHelper.GetContainingPowerOf2(buffer.Length)].Return(ref buffer);
 }
 public void Take(int count, out RawBuffer buffer)
 {
     TakeForPower(SpanHelper.GetContainingPowerOf2(count), out buffer);
 }
 public void Take(int count, out Array <T> span)
 {
     TakeForPower(SpanHelper.GetContainingPowerOf2(count), out span);;
 }