Files
fxalloc/includes/FXAlloc.h
T

167 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
/**
* @file neurox/ccpp/fxalloc/includes/FXAlloc.h
* @author felex67 (admin@felexdev.ru)
* @version 1.0.0 dev-in-progress
*
* @brief Публичный интерфейс модуля аллокатора-профилировщика
*
* @details Language: C11 (ISO/IEC 9899:2011).
*
* Теоретический маскимальный размер блока `(1 << 32) - 25 = 4 294 967 271 байт`
*
* При первом вызове `fxalloc()` до `fxalloc_init()` в глобальной облачти будет
* проинициализирован пул с градациями
*
* Первый вызов `fxalloc()`(без предварительного вызова `fxalloc_init()`) в
* потоке/процессе крайне медленный так как происходит инициализация пула,
* последующие вызовы будут работать с инициализированным пулом памяти.
*
* Изначально аллокатор работает в следующем режиме:
* `fxalloc` → выделение блока через `malloc()` с добавлением метаданных,
* `fxfree` → анализ метаданных с последующим вызовом `free()`.
* Такое поведение помогает сборать статистику для профилирования, которые могут
* быть получены переводом аллокатора в режим анализа(выполняется потоком-наблюдателем).
*
* При необходимости выделения отдельного пула для потока используйте `fxalloc_init()`,
* в глобальном пуле(НЕ TLS!!!) будет выделен блок памяти для этого потока, что даст возможность
* передачи данных по очередям между потоками без повторных выделений, функция `fxfree()`
* из любого другого потока вернёт блок владельцу без накладных расходов на TLS, только
* атомарная синхронизация.\
*
* Изменение указателей `fxalloc` и `fxfree` строго запрещено!!!\
*
* Без оперделения макроса `_I_UNDERSTAND_THAT_I_SHOULD_NEVER_CHANGE_THESE_POINTERS_` модуль
* будет работать в режиме "кукурузник", для перехода в режим "3-я космическая", определение
* макроса = подписание контракта о невмешательстве в указатели `void* (*fxalloc)(size_t)` и
* `void (*fxfree)(void* Ptr)`.\
*
* По завершению работы потока/процесса в системах POSIX вся выделенная память
* освобождается автоматически, в Windows необходимо вызвать `fxalloc_cleanup()`.
*
* Подробное описание процесса разработки интерфейса и аллокатора вцелом можно найти в файле:
* `neurox/ccpp/fxalloc/DIARY.md`
* */
#include <stdint.h>
#ifdef _WIN32
// Windows
#include <windows.h>
#define thread_local __declspec(thread)
#else
// Linux
#include <pthread.h>
#define thread_local __thread
#endif //_WIN32
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
/**
* @brief Перечисление режимов работы аллокатора
*/
typedef enum eFXAllocProfile {
FXALLOC_SPEED, ///< Максимальная производительность без статистики
FXALLOC_SUMMARY, ///< Поверхностная статистика
FXALLOC_FULL, ///< Глубокий анализ расхода памяти
FXALLOC_GETPROFILE, ///< Используется для получения текущего профиля
} eFXAllocProfile;
/**
* @brief Задаёт шаг градаций по-умолчанию используемый в изначальной версии
* `fxalloc()`. Градации будут заполнены для блоков с шагом в
* `1 << FXALLOC_DEFAULT_GRADE_STEP_SHIFT` до размера 65 535 байт(~1024 грейда),
* все блоки будут сохраняться в LIFO каждого грейда до конца работы потока.
* Такой режим предусмотрен для профилирования.
* @details Если установить данный параметр 0 будет недоступен режим полного
* профилирования, статистика будет содержать только `malloced = N times`,
* `average_size = N bytes`, `min = N bytes` и `max = N bytes`.
* В случае по-умолчанию можно будет получить более подробную информацию по
* каждому грейду и использованию памяти в нём. Не рекомендуется снижать параметр,
* т.к. это напрямую повлияет на размер метаданных пула.
*/
typedef enum eDefaultGradeStep {
FXALLOC_DEFAULT_GRADE_STEP_SHIFT = 6 ///< left bit shifts (1 << 6) = 64
} eDefaultGradeStep;
/**
* @brief Структура преднастройки аллокатора задающая градации и количество блоков памяти.
* Массив должен быть отсортирован по возрастанию размера блока
* и заканчиваться элементом с `est_size = 0`
* @var +est_size: size_t - Предполагаемый размер блока
* @var +est_count: size_t - Предполагаемое количество блоков
*/
typedef struct FXGrade {
const size_t est_size; ///< Предполагаемый размер блока
const size_t est_count; ///< Предполагаемое количество блоков
} FXGrade;
/**
* @brief Переключает режимы работы алокатора
* `FXALLOC_SPEED` - Максимальная производительность без статистики
* `FXALLOC_SUMMARY` - Поверхностная статистика
* `FXALLOC_FULL` - Глубокий анализ расхода памяти
* @retval `1` при успешном переключении
* @retval `0` при ошибке(не вероятно)
*/
int fxalloc_profile(eFXAllocProfile Profile);
/**
* @brief Инициализирует локальный пулл памяти исходя из заданных параметров блоков
* @param[in] Grades: const FXGrade* - Указатель на массив градаций
* @param[in] ThreadName: const char* - Наименование потока, используется при профилировании
* в следующем виде: `[thread_id] 'thread_name': blocks: total=1024 used=64...`.
* Если передан `NULL` - выводится только ID потока, т.е.: `[thread_id]: ...`
*/
int fxalloc_init(const FXGrade* Grades, const char* ThreadName);
#ifndef _I_UNDERSTAND_THAT_I_SHOULD_NEVER_CHANGE_THESE_POINTERS_
/**
* @brief Указатель на функцию выделения памяти
* @note Ни в коем разе не должен изменяться из вызывающего кода!!!
* @param[in] NBytes: size_t - Количество байт
* @retval `!0` - С адресом кратным размеру `sizeof(size_t)`. Указатель выровненный для любого типа данных
* @retval `NULL` - В случае единственно возможной ошибки `ENOMEM` результат сохранён в `errno`
* подробное описание `strerror(errno)`
*/
extern thread_local void (*const fxalloc)(size_t NBytes);
#else
/**
* @brief Указатель на функцию выделения памяти
* @note Ни в коем разе не должен изменяться из вызывающего кода!!!
* @param[in] NBytes: size_t - Количество байт
* @retval !0 - Кратный размеру(sizeof(size_t)) указатель выровненный для любого типа данных
* @retval NULL - В случае единственно возможной ошибки ENOMEM результат сохранён в errno
*/
extern thread_local void (*fxalloc)(size_t NBytes);
#endif
#ifndef _I_UNDERSTAND_THAT_I_SHOULD_NEVER_CHANGE_THESE_POINTERS_
/**
* @brief Указатель на функцию высвобождения памяти выделенной исключительно fxalloc
* при использовании на любом другом указателе 100% неопределённое поведение
* @note Ни в коем разе не должен изменяться из вызывающего кода!!!
* @param[in] Ptr: void* - Указатель на блок памяти
*/
extern thread_local void (*const fxfree)(void* Ptr);
#else
/**
* @brief Указатель на функцию высвобождения памяти выделенной исключительно fxalloc
* при использовании на любом другом указателе 100% неопределённое поведение
* @note Ни в коем разе не должен изменяться из вызывающего кода!!!
* @param[in] Ptr: void* - Указатель на блок памяти
*/
extern thread_local void (*fxfree)(void* Ptr);
#endif
/**
* @brief Высвобождает ресурсы занятые потоком. Вызывать непосредственно перед выходом
* из потока/процесса, в противном случае - `UB` или `segfault`
*/
void fxalloc_cleanup();
#ifdef __cplusplus
}
#endif //__cplusplus