Example #1
0
            /// <summary>
            /// Allocates an index which corresponds to a buffer.
            /// </summary>
            /// <returns>Allocated index. If allocation fails, returned index is negative.</returns>
            /// <exception cref="InvalidOperationException">Thrown when allocator is exhausted or when buffer cannot be committed.</exception>
            public int Allocate()
            {
                if (FreeList.IsEmpty)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    throw new InvalidOperationException("Cannot allocate, allocator is exhausted.");
#else
                    return(-1);
#endif
                }

                int lastFreeListIndex = FreeList.Length - 1;
                int index             = FreeList.Ptr[lastFreeListIndex];
                BaselibErrorState errorState;
                var range = new VMRange((IntPtr)this[index], (uint)BufferSizeInBytes, VirtualMemoryUtility.DefaultPageSizeInBytes);
                VirtualMemoryUtility.CommitMemory(range, out errorState);

                if (!errorState.Success)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    throw new InvalidOperationException($"Failed to commit address range {range}.");
#else
                    return(-1);
#endif
                }

                FreeList.RemoveAtSwapBack(lastFreeListIndex);

                return(index);
            }
    public unsafe void VirtualMemory_Decommit()
    {
        BaselibErrorState errorState = default;

        // Reserve 4GB
        var addressSpace = VirtualMemoryUtility.ReserveAddressSpace(1024ul * 1024ul, VirtualMemoryUtility.DefaultPageSizeInBytes, out errorState);

        {
            // Commit 4KB for an allocator
            VMRange page = new VMRange {
                ptr = addressSpace.ptr, log2PageSize = addressSpace.log2PageSize, pageCount = 1
            };
            VirtualMemoryUtility.CommitMemory(page, out errorState);
            var allocator = new UnsafeScratchAllocator((void *)page.ptr, 4096);

            var numbers0 = (int *)allocator.Allocate <int>(256);
            for (int i = 0; i < 256; i++)
            {
                numbers0[i] = i;
            }

            // Decommit and try to use
            VirtualMemoryUtility.DecommitMemory(page, out errorState);
            Assert.Throws <NullReferenceException>(() => numbers0[1] = 1);
        }
        VirtualMemoryUtility.FreeAddressSpace(addressSpace, out errorState);
    }
Example #3
0
            /// <summary>
            /// Constructs an allocator.
            /// </summary>
            /// <param name="budgetInBytes">Budget of the allocator in bytes.</param>
            /// <param name="bufferSizeInBytes">Size of each buffer to be allocated in bytes.</param>
            /// <param name="handle">An AllocatorHandle to use for internal bookkeeping structures.</param>
            /// <exception cref="InvalidOperationException">Thrown if the allocator cannot reserve the address range required for the given budget.</exception>
            public BufferAllocator(int budgetInBytes, int bufferSizeInBytes, AllocatorManager.AllocatorHandle handle)
            {
                BufferSizeInBytes = bufferSizeInBytes;

                // Reserve the entire budget's worth of address space. The reserved space may be larger than the budget
                // due to page sizes.
                var pageCount = VirtualMemoryUtility.BytesToPageCount((uint)budgetInBytes, VirtualMemoryUtility.DefaultPageSizeInBytes);
                BaselibErrorState errorState;

                ReservedRange = VirtualMemoryUtility.ReserveAddressSpace(pageCount, VirtualMemoryUtility.DefaultPageSizeInBytes, out errorState);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                if (!errorState.Success)
                {
                    throw new InvalidOperationException($"Failed to reserve address range for {budgetInBytes} bytes");
                }
#endif

                // Init a free list of blocks.
                MaxBufferCount = (int)VirtualMemoryUtility.BytesToPageCount((uint)budgetInBytes, (uint)bufferSizeInBytes);
                FreeList       = new UnsafeIntList(MaxBufferCount, handle);

                for (int i = MaxBufferCount - 1; i >= 0; --i)
                {
                    FreeList.Add(i);
                }
            }
    public unsafe void VirtualMemory_Allocate()
    {
        BaselibErrorState errorState = default;

        // Reserve 4GB
        var addressSpace = VirtualMemoryUtility.ReserveAddressSpace(1024ul * 1024ul, VirtualMemoryUtility.DefaultPageSizeInBytes, out errorState);

        {
            // Commit 1 page for an allocator
            VMRange page = new VMRange {
                ptr = addressSpace.ptr, log2PageSize = addressSpace.log2PageSize, pageCount = 1
            };
            VirtualMemoryUtility.CommitMemory(page, out errorState);

            // 1KB allocator
            var allocator = new UnsafeScratchAllocator((void *)page.ptr, 1024);

            var numbers0 = (int *)allocator.Allocate <int>(256);
            for (int i = 0; i < 256; i++)
            {
                numbers0[i] = i;
            }

            var anotherAllocator = new UnsafeScratchAllocator((void *)((IntPtr)page.ptr + 1024), 1024);
            var numbers1         = (int *)anotherAllocator.Allocate <int>(256);
            for (int i = 0; i < 256; i++)
            {
                numbers1[i] = numbers0[i];
            }
        }
        VirtualMemoryUtility.FreeAddressSpace(addressSpace, out errorState);
    }
    public void VirtualMemory_Reserve1Page()
    {
        // Reserve 1 page
        BaselibErrorState errorState = default;
        var addressSpace             = VirtualMemoryUtility.ReserveAddressSpace(1, VirtualMemoryUtility.DefaultPageSizeInBytes, out errorState);

        Assert.AreEqual(addressSpace.pageCount, 1);
        VirtualMemoryUtility.FreeAddressSpace(addressSpace, out errorState);
    }
    public void VirtualMemory_TryToReserveInvalidPageSize()
    {
        // Reserve 1 page with invalid page size
        BaselibErrorState errorState = default;
        var addressSpace             = VirtualMemoryUtility.ReserveAddressSpace(1, 69420, out errorState);

        VirtualMemoryUtility.ReportWrappedBaselibError(errorState);
        LogAssert.Expect(LogType.Error, new Regex("Baselib error:*"));
        VirtualMemoryUtility.FreeAddressSpace(addressSpace, out errorState);
    }
        public void Execute(int index)
        {
            BaselibErrorState errorState   = default;
            VMRange           addressRange = new VMRange {
                ptr = jobAddressRangePtr + index, log2PageSize = jobLog2PageSize, pageCount = jobPageCount
            };

            VirtualMemoryUtility.DecommitMemory(addressRange, out errorState);
            jobErrorStates[index] = errorState;
        }
Example #8
0
            /// <summary>
            /// Disposes the allocator and frees the reserved address range.
            /// </summary>
            /// <exception cref="InvalidOperationException">Thrown if the reserved address range cannot be freed.</exception>
            public void Dispose()
            {
                FreeList.Dispose();

                BaselibErrorState errorState;

                VirtualMemoryUtility.FreeAddressSpace(ReservedRange, out errorState);

                if (!errorState.Success)
                {
                    throw new InvalidOperationException($"Failed to free the reserved address range {ReservedRange}.");
                }
            }
        public void Execute(int index)
        {
            BaselibErrorState errorState = default;
            VMRange           allocation = new VMRange {
                ptr = jobAddressRangePtr + index * (int)VirtualMemoryUtility.DefaultPageSizeInBytes, log2PageSize = jobLog2PageSize, pageCount = jobPageCount
            };

            // Commit a page from the address range
            VirtualMemoryUtility.CommitMemory(allocation, out errorState);
            jobErrorStates[index] = errorState;

            // 1 page of ints
            var allocator = new UnsafeScratchAllocator((void *)allocation.ptr, (int)VirtualMemoryUtility.DefaultPageSizeInBytes);
            var numbers0  = (int *)allocator.Allocate <int>((int)VirtualMemoryUtility.DefaultPageSizeInBytes / sizeof(int));

            for (int i = 0; i < (int)VirtualMemoryUtility.DefaultPageSizeInBytes / sizeof(int); i++)
            {
                numbers0[i] = i;
            }
        }
Example #10
0
            /// <summary>
            /// Frees the buffer represented by the given index.
            /// </summary>
            /// <param name="index">Index to buffer.</param>
            /// <exception cref="ArgumentException">Thrown when index is less than zero or when greater than or equal to BufferCapacity</exception>
            /// <exception cref="InvalidOperationException">Thrown if the buffer cannot be decommitted.</exception>
            public void Free(int index)
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                if (index < 0 || index >= BufferCapacity)
                {
                    throw new ArgumentException($"Cannot free index {index}, it is outside the expected range [0, {BufferCapacity}).");
                }
#endif
                BaselibErrorState errorState;
                var range = new VMRange((IntPtr)this[index], (uint)BufferSizeInBytes, VirtualMemoryUtility.DefaultPageSizeInBytes);
                VirtualMemoryUtility.DecommitMemory(range, out errorState);

                if (!errorState.Success)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    throw new InvalidOperationException($"Failed to decommit address range {range}.");
#endif
                }

                FreeList.Add(index);
            }
    public unsafe void VirtualMemory_OvercommitReservedMemory()
    {
        BaselibErrorState errorState = default;

        // Reserve 1 page
        var addressSpace = VirtualMemoryUtility.ReserveAddressSpace(1, VirtualMemoryUtility.DefaultPageSizeInBytes, out errorState);

        {
            // Try to commit 2 pages (will fail).
            VMRange pages = new VMRange {
                ptr = addressSpace.ptr, log2PageSize = addressSpace.log2PageSize, pageCount = 2
            };
            VirtualMemoryUtility.CommitMemory(pages, out errorState);
            VirtualMemoryUtility.ReportWrappedBaselibError(errorState);
            LogAssert.Expect(LogType.Error, new Regex("Baselib error:*"));

            var coolByte = (byte *)pages.ptr;

            // Try to write to uncommitted memory (will fail and throw an exception).
            Assert.Throws <NullReferenceException>(() => *coolByte = 0);
        }
        VirtualMemoryUtility.FreeAddressSpace(addressSpace, out errorState);
    }
    public unsafe void VirtualMemory_AllocateAndFreeFromBurst()
    {
        BaselibErrorState errorState = default;

        // Reserve 1GB
        var addressSpace = VirtualMemoryUtility.ReserveAddressSpace(1024ul * 256ul, VirtualMemoryUtility.DefaultPageSizeInBytes, out errorState);

        {
            // 100 pages of ints
            const int allocationCount = 100;

            var errorStates = new NativeArray <BaselibErrorState>(allocationCount, Allocator.Persistent);
            {
                for (int i = 0; i < allocationCount; i++)
                {
                    errorStates[i] = default;
                }

                var commitJob = new CommitJob
                {
                    jobAddressRangePtr = addressSpace.ptr,
                    jobLog2PageSize    = addressSpace.log2PageSize,
                    jobPageCount       = 1,
                    jobErrorStates     = errorStates
                };
                commitJob.Schedule(allocationCount, 1).Complete();

                for (int i = 0; i < allocationCount; i++)
                {
                    VirtualMemoryUtility.ReportWrappedBaselibError(errorStates[i]);
                }

                // for each page allocated
                for (int i = 0; i < allocationCount; i++)
                {
                    var page      = (void *)((ulong)addressSpace.ptr + (ulong)i * VirtualMemoryUtility.DefaultPageSizeInBytes);
                    var allocator = new UnsafeScratchAllocator((void *)addressSpace.ptr, (int)VirtualMemoryUtility.DefaultPageSizeInBytes * allocationCount);

                    var intCount      = ((int)VirtualMemoryUtility.DefaultPageSizeInBytes / sizeof(int));
                    var numbersInPage = (int *)allocator.Allocate <int>(intCount);
                    // for each int in the allocated page
                    for (int j = 0; j < intCount; j++)
                    {
                        Assert.AreEqual(j, numbersInPage[j]);
                    }
                }

                var decommitJob = new DecommitJob
                {
                    jobAddressRangePtr = addressSpace.ptr,
                    jobLog2PageSize    = addressSpace.log2PageSize,
                    jobPageCount       = 1,
                    jobErrorStates     = errorStates
                };
                decommitJob.Schedule(allocationCount, 1).Complete();
            }
            errorStates.Dispose();
        }

        VirtualMemoryUtility.FreeAddressSpace(addressSpace, out errorState);
    }