[INC] Dynamic memory (Heap)
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
|