Skip to content

Commit

Permalink
Heap
Browse files Browse the repository at this point in the history
  • Loading branch information
Kudzu committed Jun 13, 2016
1 parent 12f4bd3 commit 5c59665
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 80 deletions.
2 changes: 2 additions & 0 deletions Docs/Kernel/Memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ Heap items can grow by adding pages, extending size, or expanding into the slot.
DATA less likely to fragment much becuase the various container sizes aggregate and collect smaller items
together.
Code can be relocated and even split into various blocks.
Is portable and simple. Can even be used without VirtMem, but increases time during page moves.
```

Expand Down
79 changes: 2 additions & 77 deletions source/Cosmos.Core.Memory.Test/Heap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,85 +6,10 @@
using Native = System.UInt32;

namespace Cosmos.Core.Memory.Test {
// TODO Does more than just Heap. Separate out RAT etc later.
unsafe static public class Heap {
static private Native PtrSize = sizeof(Native);
// Native Intel page size
// x86 Page Size: 4k, 2m (PAE only), 4m
// x64 Page Size: 4k, 2m
static private Native PageSize = 4096;

// Start of area usable for heap, and also start of heap.
static private byte* mStartPtr;
// Size of heap
static private Native mSize;
// Calculated from mSize
static private Native mPageCount;

// RAT - RAM Allocation Table (Covers Data area only)
// We need a pointer as the RAT can move around in future with dynamic RAM etc.
static private byte* mRatPtr;
static public class PageType {
public const byte Empty = 0;
// Extension of previous page.
public const byte Extension = 1;
public const byte RAT = 2;
}

static public void Init(byte* aStartPtr, Native aSize) {
if (aSize % PageSize != 0) {
throw new Exception("Heap size must be page aligned.");
}

mStartPtr = aStartPtr;
mSize = aSize;
mPageCount = aSize / PageSize;

InitRAT();
}
static private void InitRAT() {
mRatPtr = mStartPtr;

// Clear RAT
for (Native i = 0; i < mPageCount; i++) {
mRatPtr[i] = PageType.Empty;
}

// We need one status byte for each block.
// Intel blocks are 4k (10 bits). So for 4GB, this means
// 32 - 12 = 20 bits, 1 MB for a RAT for 4GB. 0.025%
Native xRatPageCount = mPageCount / PageSize;
ReservePages(xRatPageCount);
}

static public Native GetPageCount(byte aType = 0) {
Native xResult = 0;
for (Native i = 0; i < mPageCount; i++) {
if (mRatPtr[i] == aType) {
xResult++;
}
}
return xResult;
}

static private byte* ReservePages(Native aCount = 1) {
Native xCount = 0;
byte* xResult = null;
for (Native i = 0; i < mPageCount; i++) {
if (mRatPtr[i] == 0) {
if (xCount == 0) {
xResult = mRatPtr + i * PageSize;
}
unsafe static public class Heap {
static public void Init() {

xCount++;
if (xCount == aCount) {
return xResult;
}
} else {
xCount = 0;
}
}
return null;
}

static public void* New(Native aSize) {
Expand Down
122 changes: 121 additions & 1 deletion source/Cosmos.Core.Memory.Test/RAT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,128 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Native = System.UInt32;

namespace Cosmos.Core.Memory.Test {
static public class RAT {
unsafe static public class RAT {
static public class PageType {
public const byte Empty = 0;
public const byte RAT = 1;
// Data Types from 1, special meanings from 255 down.
// Extension of previous page.
public const byte Extension = 255;
}

// Used to bypass certain checks that will fail during tests and debugging.
static public bool Debug = false;

static private Native PtrSize = sizeof(Native);
// Native Intel page size
// x86 Page Size: 4k, 2m (PAE only), 4m
// x64 Page Size: 4k, 2m
static public readonly Native PageSize = 4096;

// Start of area usable for heap, and also start of heap.
static private byte* mRamStart;
// Size of heap
static private Native mRamSize;
// Calculated from mSize
static private Native mPageCount;

// RAT - RAM Allocation Table (Covers Data area only)
// We need a pointer as the RAT can move around in future with dynamic RAM etc.
static private byte* mRAT;

static public void Init(byte* aStartPtr, Native aSize) {
if ((Native)aStartPtr % PageSize != 0 && !Debug) {
throw new Exception("RAM start must be page aligned.");
} else if (aSize % PageSize != 0) {
throw new Exception("RAM size must be page aligned.");
}

mRamStart = aStartPtr;
mRamSize = aSize;
mPageCount = aSize / PageSize;

mRAT = mRamStart;
// Clear RAT
for (Native i = 0; i < mPageCount; i++) {
mRAT[i] = PageType.Empty;
}

// We need one status byte for each block.
// Intel blocks are 4k (10 bits). So for 4GB, this means
// 32 - 12 = 20 bits, 1 MB for a RAT for 4GB. 0.025%
Native xRatPageCount = mPageCount / PageSize;
Alloc(PageType.RAT, xRatPageCount);

Heap.Init();
}

static public Native GetPageCount(byte aType = 0) {
Native xResult = 0;
bool xCounting = false;
for (Native i = 0; i < mPageCount; i++) {
byte xType = mRAT[i];
if (xType == aType) {
xResult++;
xCounting = true;
} else if (xCounting) {
if (xType == PageType.Extension) {
xResult++;
} else {
xCounting = false;
}
}
}
return xResult;
}

static private byte* Alloc(byte aType, Native aCount = 1) {
Native? xPos = null;

// Could combine with an external method or delegate, but will slow things down
// unless we can force it to be inlined.
//
// Alloc single blocks at bottom, larger blocks at top to help reduce fragmentation.
Native xCount = 0;
if (aCount == 1) {
for (Native i = 0; i < mPageCount; i++) {
if (mRAT[i] == PageType.Empty) {
xCount++;
if (xCount == aCount) {
xPos = i - xCount - 1;
break;
}
} else {
xCount = 0;
}
}
} else {
for (Native i = mPageCount - 1; i >= 0; i--) {
if (mRAT[i] == PageType.Empty) {
xCount++;
if (xCount == aCount) {
xPos = i;
break;
}
} else {
xCount = 0;
}
}
}

// If we found enough space, mark it as used.
if (xPos.HasValue) {
byte* xResult = mRamStart + xPos.Value * PageSize;
mRAT[xPos.Value] = aType;
for (Native i = xPos.Value + 1; i < xPos.Value + xCount; i++) {
mRAT[i] = PageType.Extension;
}
return xResult;
}

return null;
}
}
}
9 changes: 7 additions & 2 deletions source/Cosmos.Core.Memory.Test/UnitTest1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ unsafe public void TestMethod1() {
var xRAM = new byte[128 * 1024 * 1024];
xRAM[0] = 1;
fixed (byte* xPtr = xRAM) {
Heap.Init(xPtr, (UInt32)xRAM.LongLength);
Native xFreePages = Heap.GetPageCount(Heap.PageType.Empty);
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);
}
}
}
Expand Down

0 comments on commit 5c59665

Please sign in to comment.