- Поддерживаемые игры
-
- CS: Source (OrangeBox)
- CS: GO
- Team Fortress 2
- DOD: Source
- L4D 1 & 2
Поскольку SourcePawn не имеет реализации кучи (heap), для динамического выделения памяти, я создал свою.
Этот инклуд добавляет функции для создания и использования динамической памяти выделенной внутри плагина.
Выделение памяти делается на основе глобального одномерного массива.
О том как это работает, вы можете прочитать в соответствующем уроке:
"Организация кучи (динамической памяти) на основе одномерного статического массива"
Используемые понятия:
Двоичное дерево поиска (англ. binary search tree, BST)
Ячейка памяти (англ. cell, 4 байтная переменная любого типа)
Использование
Производительность
Замеры проводились на сервере CS:GO с 2-х ядерном процессором 2.66 ГГц каждое
Результаты представляют собой среднее 10-и замеров
Код для тестирования
Этот инклуд добавляет функции для создания и использования динамической памяти выделенной внутри плагина.
Выделение памяти делается на основе глобального одномерного массива.
О том как это работает, вы можете прочитать в соответствующем уроке:
"Организация кучи (динамической памяти) на основе одномерного статического массива"
Используемые понятия:
Двоичное дерево поиска (англ. binary search tree, BST)
Ячейка памяти (англ. cell, 4 байтная переменная любого типа)
Использование
PHP:
// Используйте эти определения до включения инклуда
#define HEAP_SIZE 16384 // Опциональное определение, переопределяет размер кучи; измеряется в ячейках
#define BST_ALLOC_COUNT 256 // Опциональное определение, переопределяет шаг выделения памяти для BST; измеряется в кол-ве узлов дерева
#define FREE_MEM_SLICE_MIN 8 // Опциональное определение, переопределяет лимит дробления памяти
#define DEBUG_HEAP_MEMORY_FULL // Добавьте это определение для включения всех проверок
#define DEBUG_HEAP_MEMORY_INIT // Добавьте это определение для включения проверки инициализации
#define DEBUG_HEAP_MEMORY_SIZE // Добавьте это определение для включения проверки указанных размеров
#define DEBUG_HEAP_MEMORY_BOUNDS // Добавьте это определение для включения проверки указанных адресов (осторожно, может замедлять работу чтения/записи в 1.5 раза)
#define DEBUG_HEAP_MEMORY_MAGIC // Добавьте это определение для включения проверки магического числа
#define DEBUG_HEAP_MEMORY_STATUS // Добавьте это определение для включения проверки статуса изменяемой памяти
// Используйте 0 в качестве нулевого указателя (адреса)
// Адреса представляют собой число больше нуля (индексы ячеек в массиве, от места где была выделена память)
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);
Производительность
Замеры проводились на сервере CS:GO с 2-х ядерном процессором 2.66 ГГц каждое
Результаты представляют собой среднее 10-и замеров
C-подобный:
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:
#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);
}