public unsafe void TestAllocPages() // ensure that we fail gracefully when memory gets full { var xRAM = new byte[10 * RAT.PageSize]; // 10 Pages - 1 for RAT and 9 for values fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); Assert.AreEqual((uint)1, RAT.GetPageCount(RAT.PageType.RAT)); try { for (int i = 0; i < 10000; i++) { byte *ptr = Heap.Alloc(40); FillRandom(ptr, 40); if (ptr == null) { Assert.Fail(); } Assert.AreEqual((uint)1, RAT.GetPageCount(RAT.PageType.RAT)); } } catch (Exception e) { Assert.AreEqual("289", e.Message); } } }
public unsafe void RATTest() { var xRAM = new byte[128 * 1024 * 1024]; // 128 MB xRAM[0] = 1; fixed(byte *xPtr = xRAM) { RAT.Debug = true; //RAT.Init(xPtr, (Native)xRAM.LongLength); RAT.Init(xPtr, (Native)xRAM.Length); Native xRatPages = RAT.GetPageCount(RAT.PageType.RAT); Assert.IsTrue(xRatPages > 0); var xFreePages = RAT.GetPageCount(RAT.PageType.Empty); Assert.IsTrue(xFreePages > 0); var x1 = (Int32 *)Heap.Alloc(sizeof(Int32)); var xFreePages2 = RAT.GetPageCount(RAT.PageType.Empty); Assert.IsTrue(xFreePages - xFreePages2 == 1); // Heap.Free(x1); var xFreePages3 = RAT.GetPageCount(RAT.PageType.Empty); Assert.IsTrue(xFreePages3 == xFreePages2 + 1); } }
public unsafe void InitTest() { var xRAM = new byte[128 * 1024 * 1024]; // 128 MB fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); Assert.IsTrue(HeapSmall.mMaxItemSize > 512); uint xRatPages = RAT.GetPageCount(RAT.PageType.RAT); Assert.IsTrue(xRatPages > 0); var xFreePages = RAT.GetPageCount(RAT.PageType.Empty); Assert.IsTrue(xFreePages > 0); Assert.IsTrue(RAT.GetPageCount(RAT.PageType.HeapSmall) > 0); Assert.AreEqual(0, HeapSmall.GetAllocatedObjectCount()); Assert.AreEqual((uint)8, RAT.GetPageCount(RAT.PageType.RAT)); } }
static void CreatePage(Native aItemSize) { if (aItemSize == 0) { throw new Exception("ItemSize cannot be 0."); } else if (aItemSize % sizeof(Native) != 0) { throw new Exception("Item size must be word aligned."); } else if (mMaxItemSize == 0) { throw new Exception("SMT is not initialized."); } else if (aItemSize > mMaxItemSize) { throw new Exception("Cannot allocate more than MaxItemSize in SmallHeap."); } var xPtr = (Native *)RAT.Alloc(RAT.PageType.HeapSmall); *xPtr = 0; for (void **p = mSMT + aItemSize; ; p--) { // TODO - Make a free list, put a ptr in item header and first page header - how to keep compact? } // Header // Ptr to next page of same size // Each Item //xPtr[0] = aSize; // Actual data size //xPtr[1] = 0; // Ref count //xPtr[2] = 0; // Ptr to first }
static void InitSMT(Native aMaxItemSize) { mMaxItemSize = aMaxItemSize; Native xPageCount = mMaxItemSize * (Native)sizeof(void *) / RAT.PageSize; mSMT = (void **)RAT.Alloc(RAT.PageType.HeapSmall, xPageCount); }
static public void Free(void *aPtr) { // TODO - Should check the page type before freeing to make sure it is a Large? // or just trust the caller to avoid adding overhead? var xPageIdx = RAT.GetFirstRAT(aPtr); RAT.Free(xPageIdx); }
static public byte *Alloc(Native aSize) { Native xPages = (Native)((aSize + PrefixBytes) / RAT.PageSize) + 1; var xPtr = (Native *)RAT.Alloc(RAT.PageType.HeapLarge, xPages); xPtr[0] = xPages * RAT.PageSize - PrefixBytes; // Allocated data size xPtr[1] = aSize; // Actual data size xPtr[2] = 0; // Ref count xPtr[3] = 0; // Ptr to first return((byte *)xPtr + PrefixBytes); }
// Keep as void* and not byte* or other. Reduces typecasting from callers // who may have typed the pointer to their own needs. static public void Free(void *aPtr) { //TODO find a better way to remove the double look up here for GetPageType and then again in the // .Free methods which actually free the entries in the RAT. var xType = RAT.GetPageType(aPtr); switch (xType) { case RAT.PageType.HeapLarge: HeapLarge.Free(aPtr); break; default: throw new Exception("Heap item not found in RAT."); } }
public unsafe void RATMethods() { var xRAM = new byte[1024 * 1024]; fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); var largePage = RAT.AllocPages(RAT.PageType.HeapLarge, 3); Assert.AreEqual(RAT.PageType.HeapLarge, RAT.GetPageType(largePage)); Assert.AreEqual(RAT.GetFirstRATIndex(largePage), RAT.GetFirstRATIndex((byte *)largePage + 20)); Assert.AreEqual(RAT.PageType.HeapLarge, RAT.GetPageType((byte *)largePage + RAT.PageSize)); } }
unsafe public void TestMethod1() { var xRAM = new byte[128 * 1024 * 1024]; xRAM[0] = 1; fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (UInt32)xRAM.LongLength); Native xRatPages = RAT.GetPageCount(RAT.PageType.RAT); Assert.IsTrue(xRatPages > 0); Native xFreePages = RAT.GetPageCount(RAT.PageType.Empty); } }
public unsafe void SmallHeapMultiPageAllocationTest() { var xRAM = new byte[1024 * 1024]; // 4 MB fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); uint smallPages = RAT.GetPageCount(RAT.PageType.HeapSmall); var ptr1 = Heap.Alloc(HeapSmall.mMaxItemSize); // 4 of them should fit on one page var ptr2 = Heap.Alloc(HeapSmall.mMaxItemSize); var ptr3 = Heap.Alloc(HeapSmall.mMaxItemSize); var ptr4 = Heap.Alloc(HeapSmall.mMaxItemSize); Assert.AreEqual((uint)ptr2 - (uint)ptr1, (uint)ptr4 - (uint)ptr3); Assert.AreEqual((uint)RAT.GetPagePtr(ptr1), (uint)RAT.GetPagePtr(ptr2)); Assert.AreEqual(4, HeapSmall.GetAllocatedObjectCount()); Heap.Free(ptr4); var nptr4 = Heap.Alloc(HeapSmall.mMaxItemSize); Assert.AreEqual((uint)RAT.GetPagePtr(ptr1), (uint)RAT.GetPagePtr(ptr4)); var ptr5 = Heap.Alloc(HeapSmall.mMaxItemSize); // this should cause a new page to have to be created uint largePages = RAT.GetPageCount(RAT.PageType.HeapLarge); Assert.AreEqual((uint)0, largePages); Assert.AreEqual(smallPages + 1, RAT.GetPageCount(RAT.PageType.HeapSmall)); Assert.AreNotEqual((uint)ptr1, (uint)ptr5); Assert.IsTrue(((uint)ptr5 - (uint)ptr1) % RAT.PageSize == 0); Assert.AreEqual(5, HeapSmall.GetAllocatedObjectCount()); // now lets force them to allocate 2 more pages for (int i = 0; i < 8; i++) { Heap.Alloc(HeapSmall.mMaxItemSize - 2); } Assert.AreEqual(smallPages + 3, RAT.GetPageCount(RAT.PageType.HeapSmall)); Assert.AreEqual(13, HeapSmall.GetAllocatedObjectCount()); } }
public unsafe void SmallHeapTestExpansion() { var xRAM = new byte[1024 * 1024]; // 4 MB fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); uint smallPages = RAT.GetPageCount(RAT.PageType.HeapSmall); for (int i = 0; i < 9; i++) { Heap.Alloc(600); } Assert.AreEqual(smallPages + 2, RAT.GetPageCount(RAT.PageType.HeapSmall)); } }
public unsafe void SmallAllocTest() { var xRAM = new byte[32 * 1024 * 1024]; // 32 MB fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); uint smallPages = RAT.GetPageCount(RAT.PageType.HeapSmall); uint largePages = RAT.GetPageCount(RAT.PageType.HeapLarge); // the following allocations should all go on the same page var ptr1 = Heap.Alloc(8); var ptr2 = Heap.Alloc(3); ptr2[0] = 12; ptr2[1] = 101; var ptr3 = Heap.Alloc(8); var ptr4 = Heap.Alloc(20); var ptr5 = Heap.Alloc(22); Assert.AreNotEqual((uint)ptr1, (uint)ptr2); Assert.AreEqual((uint)ptr2 - (uint)ptr1, (uint)ptr3 - (uint)ptr2); Assert.AreEqual(24 + HeapSmall.PrefixItemBytes, (uint)ptr5 - (uint)ptr4); Assert.AreEqual(RAT.PageSize, (uint)ptr4 - (uint)ptr1); Assert.AreEqual(12, ptr2[0]); Assert.AreEqual(smallPages, RAT.GetPageCount(RAT.PageType.HeapSmall)); Assert.AreEqual(largePages, RAT.GetPageCount(RAT.PageType.HeapLarge)); Assert.AreEqual(5, HeapSmall.GetAllocatedObjectCount()); Heap.Free(ptr2); Assert.AreEqual(4, HeapSmall.GetAllocatedObjectCount()); Assert.AreEqual(0, ptr2[0]); var nptr2 = Heap.Alloc(10); Heap.Alloc(10); Assert.AreEqual((uint)ptr2, (uint)nptr2); // we use the earliest free position Assert.AreEqual(6, HeapSmall.GetAllocatedObjectCount()); } }
public unsafe void TestRATHeapMethods() { var xRAM = new byte[10 * RAT.PageSize]; // 10 Pages - 1 for RAT and 9 for values fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); var ptr1 = Heap.Alloc(10); var ptr2 = Heap.Alloc(10); var ptr3 = Heap.Alloc(10); Assert.AreNotEqual((uint)ptr1, (uint)ptr2); Assert.AreNotEqual((uint)ptr1, (uint)ptr3); Assert.AreNotEqual((uint)ptr2, (uint)ptr3); Assert.AreEqual(RAT.GetFirstRATIndex(ptr1), RAT.GetFirstRATIndex(ptr2)); Assert.AreEqual(RAT.GetFirstRATIndex(ptr1), RAT.GetFirstRATIndex(ptr3)); Assert.AreEqual((uint)RAT.GetPagePtr(ptr1), (uint)RAT.GetPagePtr(ptr2)); Assert.AreEqual((uint)RAT.GetPagePtr(ptr1), (uint)RAT.GetPagePtr(ptr3)); } }
public unsafe void SmallHeapStressTest() // this test is important since it tests that the SMT table can grow to multiple pages { var xRAM = new byte[1024 * 1024]; // 4 MB fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); Random random = new Random(); for (int i = 0; i < 1000; i++) { if (Heap.Alloc((uint)random.Next(4, (int)HeapSmall.mMaxItemSize)) == null) { Assert.Fail(); } } Assert.AreEqual(1000, HeapSmall.GetAllocatedObjectCount()); } }
public unsafe void MediumLargeHeapTest() // as long as medium just does the same as the large heap, we can test them together { var xRAM = new byte[1024 * 1024]; // 4 MB fixed(byte *xPtr = xRAM) { RAT.Debug = true; RAT.Init(xPtr, (uint)xRAM.Length); var largeCount = RAT.GetPageCount(RAT.PageType.HeapLarge); var mediumCount = RAT.GetPageCount(RAT.PageType.HeapMedium); var ptr1 = Heap.Alloc(HeapMedium.MaxItemSize); // this will allocate two pages, // since we simplify the math by assuming we never want only one full page var ptr2 = Heap.Alloc(HeapMedium.MaxItemSize - 10); var ptr3 = Heap.Alloc(HeapMedium.MaxItemSize + 10); Assert.AreEqual(largeCount + 2, RAT.GetPageCount(RAT.PageType.HeapLarge)); Assert.AreEqual(mediumCount + 3, RAT.GetPageCount(RAT.PageType.HeapMedium)); var ptr4 = Heap.Alloc(RAT.PageSize * 5 - HeapLarge.PrefixBytes - 1); Assert.AreEqual(largeCount + 7, RAT.GetPageCount(RAT.PageType.HeapLarge)); Assert.AreEqual(6, (int)RAT.GetPageCount(RAT.PageType.Extension)); Heap.Free(ptr4); Assert.AreEqual(largeCount + 2, RAT.GetPageCount(RAT.PageType.HeapLarge)); Assert.AreEqual(2, (int)RAT.GetPageCount(RAT.PageType.Extension)); Heap.Free(ptr1); Heap.Free(ptr2); Assert.AreEqual(mediumCount, RAT.GetPageCount(RAT.PageType.HeapMedium)); Assert.AreEqual(largeCount + 2, RAT.GetPageCount(RAT.PageType.HeapLarge)); } }