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); }
/// <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_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); }
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 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); }