diff --git a/DIARY.md b/DIARY.md index 467045f..e0e9243 100644 --- a/DIARY.md +++ b/DIARY.md @@ -1154,7 +1154,7 @@ void* fxalloc_proxy(size_t NBytes) { ### CP + proxy -Пожалуй, это самый логичный способ защитить модуль от некоректного использования. При компиляции с `const`-указателями работаем через прокси, в противном случае - включаем 3-ю космическую. Пример реализации такого подхода приведён ниже: +Пожалуй, это самый логичный способ защитить модуль от некоректного использования. При компиляции с `const`-указателями работаем через прокси, в противном случае — включаем 3-ю космическую. Пример реализации такого подхода приведён ниже: ```C /* includes/FXAlloc.h */ #ifndef _I_UNDERSTAND_THAT_I_SHOULD_NEVER_CHANGE_THESE_POINTERS_ @@ -1185,4 +1185,51 @@ void* fxalloc_proxy(size_t NBytes) { void* (*fxalloc)(size_t) = fxalloc_init_malloc; ///< работает прямым вызовом #endif ``` -Рабочие функции(вроде `fxalloc_init_alloc`) не знают о существовании дополнительной переменной, им без разницы кто их вызывает, они выполняют свои прямые обязанности несмотря на контекст. \ No newline at end of file +Рабочие функции(вроде `fxalloc_init_alloc`) не знают о существовании дополнительной переменной, им без разницы кто их вызывает, они выполняют свои прямые обязанности несмотря на контекст. + +### Промежуточный итог + +Не смотря на общую парадигму проекта **KISS+YAGNI** стоит реализовать защиту в виде **proxy + CP** ибо нам самим потом будет гараздо удобнее профилировать и настраивать сервер(на клиентах будет достаточно обычного `malloc/free`). + +# 06.05.2026(Раздел редактируется) + +## Итоговый интерфейс + +### Функции + +#### `fxalloc_profile`: + +```C +int fxalloc_profile(eFXAllocProfile Profile); +``` +Изменяет режим работы аллокатора **для всех потоков** одновременно + +#### Параметры + +* `Profile`(`eFXAllocProfile`) — режим работы аллокатора, см. `eFXAllocProfile` + +#### Возвращаемые значение + +* `eFXAllocProfile` — предыдущий режим работы. +* при `Profile == FXALLOC_GETPROFILE` — текущий режим работы. + + +#### `fxalloc_profile_thread`: + +```C +int fxalloc_profile_thread(eFXAllocProfile Profile); +``` +### Структуры/перечисления + +`enum eFXAllocProfile` — перечисление режимов работы аллокатора, используется как аргумент или возвращаемое значение функций `int fxalloc_profile(eFXAllocProfile Profile)`(глобально) и `int fxalloc_profile_thread(eFXAllocProfile Profile)`(для текущеко потока). + +| Элемент | Описание | +|---------------------:|:------------------------------------------------| +| `FXALLOC_SPEED` | Максимальная производительность без статистики. | +| `FXALLOC_SUMMARY` | Поверхностная статистика: количество выделенных/свободных блоков по грейдам | +| `FXALLOC_FULL` | Глубокий анализ расхода памяти: количество выделенных/свободных блоков по грейдам, средний объём использования, минимальное/максимальное использование | +| `FXALLOC_GETPROFILE` | Используется для получения текущего профиля. | + + + +Итоговый интерфей увековечен в файле [includes/FXAlloc.h](ccpp/fxalloc/includes/FXAlloc.h) \ No newline at end of file diff --git a/includes/FXAlloc.h b/includes/FXAlloc.h index 221acb2..56f3cac 100644 --- a/includes/FXAlloc.h +++ b/includes/FXAlloc.h @@ -2,29 +2,43 @@ /** * @file neurox/ccpp/fxalloc/includes/FXAlloc.h * @author felex67 (admin@felexdev.ru) - * @version 1.0.0 beta + * @version 1.0.0 dev-in-progress * @brief Публичный интерфейс модуля-аллокатора fxalloc(includes/FXAlloc.h) * * @details Language: C11 (ISO/IEC 9899:2011). - * Теоритический маскимальный размер блока `(1 << 32) - 25 = 4 294 967 271 байт` - * Первый вызов `fxalloc()`(без предварительного вызова `fxalloc_init()`) в потоке/процессе крайне медленный - * так как происходит инициализация пула, последующие вызовы будут работать с инициализированным - * пулом памяти. + * Теоретический маскимальный размер блока `(1 << 32) - 25 = 4 294 967 271 байт` + * + * При первом вызове `fxalloc()` до `fxalloc_init()` в глобальной облачти будет + * проинициализирован пул с градациями + * + * Первый вызов `fxalloc()`(без предварительного вызова `fxalloc_init()`) в + * потоке/процессе крайне медленный так как происходит инициализация пула, + * последующие вызовы будут работать с инициализированным пулом памяти. + * * Изначально аллокатор работает в следующем режиме: - * `fxalloc → выделение блока через malloc() с добавлением метаданных`, - * `fxfree → анализ метаданных с последующим вызовом free()`. Такое поведение - * помогает сборать статистику для профилирования, которые могут быть получены - * переводом аллокатора в режим анализа(выполняется потоком-наблюдателем). + * `fxalloc` → выделение блока через `malloc()` с добавлением метаданных, + * `fxfree` → анализ метаданных с последующим вызовом `free()`. + * Такое поведение помогает сборать статистику для профилирования, которые могут + * быть получены переводом аллокатора в режим анализа(выполняется потоком-наблюдателем). + * * При необходимости выделения отдельного пула для потока используйте `fxalloc_init()`, * в глобальном пуле(НЕ TLS!!!) будет выделен блок памяти для этого потока, что даст возможность * передачи данных по очередям между потоками без повторных выделений, функция `fxfree()` * из любого другого потока вернёт блок владельцу без накладных расходов на TLS, только * атомарная синхронизация.\ - * Изменение указателей `fxalloc` и `fxfree` строго запрещено!\ + * + * Изменение указателей `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 @@ -46,9 +60,27 @@ extern "C" { typedef enum eFXAllocProfile { FXALLOC_SPEED, ///< Максимальная производительность без статистики FXALLOC_SUMMARY, ///< Поверхностная статистика - FXALLOC_FULL ///< Глубокий анализ расхода памяти + 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 Структура преднастройки аллокатора задающая градации и количество блоков памяти. * Массив должен быть отсортирован по возрастанию размера блока