As SourcePawn not have real heap, i created my one.
This include file provide functions to create and use statically allocated memory heap inside your plugin.
Heap is based on global one-dimensional array.
Doubly linked list projected on array. Free node can be splited to busy and free parts.
When busy node freed, it join with near free.
On left 0-sized busy node as border.
On right reversed array for BST nodes.
Free list nodes cached in BST.
Usage
PHP Code:
// You need to use this defines before including
#define HEAP_SIZE 16384 // optional define, to override heap size; sized in cells
#define BST_ALLOC_COUNT 256 // optional define, to override BST allocation step size; sized in node count (number of objects)
#define FREE_MEM_SLICE_MIN 8 // optional define, to override memory sliceing limitation
#define DEBUG_HEAP_MEMORY_FULL // define it, to turn on all validation checks
#define DEBUG_HEAP_MEMORY_INIT // define it, to turn on heap initialization check
#define DEBUG_HEAP_MEMORY_SIZE // define it, to turn on passed size validation
#define DEBUG_HEAP_MEMORY_BOUNDS // define it, to turn on passed address validation (careful, can increase read/write by 1.5 times)
#define DEBUG_HEAP_MEMORY_MAGIC // define it, to turn on magic value validation
#define DEBUG_HEAP_MEMORY_STATUS // define it, to turn on status validation
// Use 0 as null pointer (address)
// Address represent an integral value above 0 (array cell index, from where allocated memory started)
int memalloc(int size);
void free(int adr);
int realloc(int adr, int size);
void store(int adr, any value);
any load(int adr);
void mempaste(int adr, const any[] array, int size);
void memcopy(int adr, any[] array, int size);
void memmove(int fromadr, int toadr, int size);
void memmover(int fromadr, int toadr, int size);
void mempastestr(int adr, const char[] str, int size);
void memcopystr(int adr, char[] str, int size);
You can wrap address with methodmap to create almost full OOP in SP.
Profiling
Tested on CS:GO server under 2x2.66 GHz CPU
Average of 10
Code:
0.001208 s for first alloc and free with initialization
0.000254 s for allocate 1000 blocks by 64 cells
0.000955 s for read 64000 cells
0.001092 s for write 64000 cells
0.000265 s for free 1000 blocks by 64 cells
PHP Code:
#include <profiler>
#define HEAP_SIZE 131072
#include <memory>
#define OBJECT_NUMBER 1000
#define OBJECT_SIZE 64
Handle prof;
int count = 10;
public void OnPluginStart()
{
prof = CreateProfiler();
StartProfiling(prof);
free(memalloc(10));
StopProfiling(prof);
PrintToServer("%f s", GetProfilerTime(prof));
Frame(0);
}
public void Frame(any data)
{
count--;
MakeProf();
if (count != 0)
RequestFrame(Frame);
}
void MakeProf()
{
int blocks[OBJECT_NUMBER], i;
int n, v;
StartProfiling(prof);
for (i = 0; i < OBJECT_NUMBER; i++)
{
blocks[i] = memalloc(OBJECT_SIZE);
}
StopProfiling(prof);
PrintToServer("%f s for allocate %i blocks by %i cells", GetProfilerTime(prof), OBJECT_NUMBER, OBJECT_SIZE);
StartProfiling(prof);
for (i = 0; i < OBJECT_NUMBER; i++)
{
for (n = 0; n < OBJECT_SIZE; n++)
{
v = load(blocks[i] + n);
}
}
StopProfiling(prof);
PrintToServer("%f s for read %i cells", GetProfilerTime(prof), OBJECT_NUMBER * OBJECT_SIZE);
StartProfiling(prof);
for (i = 0; i < OBJECT_NUMBER; i++)
{
for (n = 0; n < OBJECT_SIZE; n++)
{
store(blocks[i] + n, v);
}
}
StopProfiling(prof);
PrintToServer("%f s for write %i cells", GetProfilerTime(prof), OBJECT_NUMBER * OBJECT_SIZE);
StartProfiling(prof);
for (i = 0; i < OBJECT_NUMBER; i++)
{
free(blocks[i]);
}
StopProfiling(prof);
PrintToServer("%f s for free %i blocks by %i cells", GetProfilerTime(prof), OBJECT_NUMBER, OBJECT_SIZE);
}
Download from GitHub
__________________