diff --git a/.vs/CMake Overview b/.vs/CMake Overview new file mode 100644 index 0000000..e69de29 diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..8f0d733 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": "x64-Debug" +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..c141193 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,15 @@ +{ + "OutputFoldersPerTargetSystem": { + "Local Machine": [ + "out\\build\\x64-Debug", + "out\\install\\x64-Debug" + ] + }, + "ExpandedNodes": [ + "", + "\\includes", + "\\src" + ], + "SelectedNode": "\\src\\FXAlloc.c", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/fxalloc.slnx/FileContentIndex/a2e3e4bc-8599-4af9-a20e-df25e9747ced.vsidx b/.vs/fxalloc.slnx/FileContentIndex/a2e3e4bc-8599-4af9-a20e-df25e9747ced.vsidx new file mode 100644 index 0000000..9d3eb68 Binary files /dev/null and b/.vs/fxalloc.slnx/FileContentIndex/a2e3e4bc-8599-4af9-a20e-df25e9747ced.vsidx differ diff --git a/.vs/fxalloc.slnx/v18/.wsuo b/.vs/fxalloc.slnx/v18/.wsuo new file mode 100644 index 0000000..cbfc194 Binary files /dev/null and b/.vs/fxalloc.slnx/v18/.wsuo differ diff --git a/.vs/fxalloc.slnx/v18/Browse.VC.db b/.vs/fxalloc.slnx/v18/Browse.VC.db new file mode 100644 index 0000000..b34e063 Binary files /dev/null and b/.vs/fxalloc.slnx/v18/Browse.VC.db differ diff --git a/.vs/fxalloc.slnx/v18/DocumentLayout.json b/.vs/fxalloc.slnx/v18/DocumentLayout.json new file mode 100644 index 0000000..56f038c --- /dev/null +++ b/.vs/fxalloc.slnx/v18/DocumentLayout.json @@ -0,0 +1,12 @@ +{ + "Version": 1, + "WorkspaceRootPath": "C:\\projects\\fullstack\\neurox\\ccpp\\fxalloc\\", + "Documents": [], + "DocumentGroupContainers": [ + { + "Orientation": 0, + "VerticalTabListWidth": 256, + "DocumentGroups": [] + } + ] +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..b9f9921 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/CMakeLists.txt b/CMakeLists.txt index ae602a1..71d5773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimal_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) project(neurox) set(SOURCES src/FXAlloc.c) set(HEADERS headers/_FXAlloc.h) diff --git a/DIARY.md b/DIARY.md index 8bf0baa..9f0f919 100644 --- a/DIARY.md +++ b/DIARY.md @@ -1100,6 +1100,25 @@ thread_local void* (*fxalloc)(size_t _NBytes); thread_local void (*fxfree)(void* _Ptr); ``` +Единственным узким местом остаётся переключение режимов, как это сделать расмотрим немного позже. +# 04.05.2026 -Единственным узким местом остаётся переключение режимов, как это сделать расмотрим далее +## Переключение режимов работы: + +Существенным недостатком использования TLS-указателей на функции является сложность их изменения во время работы из глобальной области. Но, опять таки, мы же пишем на С, будем использовать всю его мощь! Затратив памяти на 2 указателя в каждом отдельном пуле мы сможем обойти сложность TLS и спокойненько менять их по желанию, что имеется в виду: +```C +/* TLS-указатели на функции выделения и высвобождения памяти */ +thread_local void* (*fxalloc)(size_t NBytes); +thread_local void (*fxfree)(void* Ptr); + +/* Блок выделенный для конкретного потока в глобальном пуле */ +typedef struct ThreadMemoryBlock { + void*(**fxalloc)(size_t); ///< Указатель на fxalloc потока + void(**fxfree)(void*); ///< Указатель на fxree потока + /* Остальные поля */ +} ThreadMemoryBlock; +/* Управляющий поток-наблютель */ +*(globalPoll.threads[tid].fxalloc) = fxalloc_summary; +*(globalPoll.threads[tid].fxfree) = fxfree_summary; +``` \ No newline at end of file diff --git a/includes/FXAlloc.h b/includes/FXAlloc.h index 3516047..8bbbc15 100644 --- a/includes/FXAlloc.h +++ b/includes/FXAlloc.h @@ -1,47 +1,110 @@ #pragma once - +/** + * @file neurox/ccpp/fxalloc/includes/FXAlloc.h + * @author felex67 (admin@felexdev.ru) + * @version 1.0.0 beta + * @brief Публичный интерфейс модуля-аллокатора fxalloc(includes/FXAlloc.h) + * + * @details Language: C11 (ISO/IEC 9899:2011). + * Изначально аллокатор работает в следующем режиме: + * `fxalloc → выделение блока через malloc() с добавлением метаданных`, + * `fxfree → анализ метаданных с последующим вызовом free()`. Такое поведение + * помогает сборать статистику для профилирования, которые могут быть получены + * переводом аллокатора в режим анализа(выполняется потоком-наблюдателем). + * При необходимости выделения отдельного пула для потока используйте `fxalloc_init()`, + * в глобальном пуле(НЕ TLS!!!) будет выделен блок памяти для этого потока, что даст возможность + * передачи данных по очередям между потоками без повторных выделений, функция `fxfree()` + * из любого другого потока вернёт блок владельцу без накладных расходов на TLS, только + * атомарная синхронизация.\ + * Изменение указателей `fxalloc` и `fxfree` строго запрещено! Без оперделения макроса + * `_I_UNDERSTAND_THE_RISKS_AND_ASSUME_RESPONSIBILITY_` возникнет ошибка компиляции.\ + * По завершению работы потока/процесса в системах POSIX вся выделенная память + * освобождается автоматически, в Windows необходимо вызвать `fxalloc_cleanup()`. + * */ #include +#include -#ifndef _WIN32 - #include +#ifdef _WIN32 // Windows + #define thread_local __declspec(thread) +#else // Linux + #define thread_local __thread #endif //_WIN32 #ifdef __cplusplus extern "C" { #endif //__cplusplus -/** - * @brief Структура преднастройки аллокатора задающая градации и количество блоков памяти - * - * @property +est_size: size_t - Предполагаемый размер блока - * @property +est_count: size_t - Предполагаемое количество блоков - */ -typedef struct FXGrade { - /// Предполагаемый размер блока - const size_t est_size; - /// Предполагаемое количество блоков - const size_t est_count; -} FXGrade; + /** + * @brief Перечисление режимов работы аллокатора + */ + typedef enum { + FXALLOC_SPEED, ///< Максимальная производительность без статистики + FXALLOC_SUMMARY, ///< Поверхностная статистика + FXALLOC_FULL ///< Глубокий анализ расхода памяти + } eFXAllocProfile; -/** - * @brief Переменная для сохранения преднастроек пула памяти с ноль-терминантом - * Определена в src/FXAlloc.c - */ -extern const FXGrade* grades; + /** + * @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 Функция выделения памяти - * @param[in] _NBytes: size_t - Количество байт - * @retval !0 - Кратный size_t указатель выровненный для любого типа данных - * @retval NULL - В случае единственно возможной ошибки EBADALLOC результат сохранён в errno - */ -void* fxalloc(size_t _NBytes); + /** + * @brief Переключает режимы работы алокатора + * FXALLOC_SPEED, ///< Максимальная производительность без статистики + * FXALLOC_SUMMARY, ///< Поверхностная статистика + * FXALLOC_FULL ///< Глубокий анализ расхода памяти + * @retval !0 при успешном переключении + * @retval 0 при ошибке(не вероятно) + */ + int fxalloc_profile(eFXAllocProfile Profile); -/** - * @brief Высвобождает память выделенную исключительно fxalloc - * @param[in] _Ptr: void* - */ -void fxfree(void* _Ptr); + /** + * @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); + /** + * @brief Указатель на функцию выделения памяти + * @note Ни в коем разе не должен изменяться из вызывающего кода!!! + * @param[in] NBytes: size_t - Количество байт + * @retval !0 - Кратный размеру(sizeof(size_t)) указатель выровненный для любого типа данных + * @retval NULL - В случае единственно возможной ошибки ENOMEM результат сохранён в errno + */ +#ifndef _I_UNDERSTAND_THE_RISKS_AND_ASSUME_RESPONSIBILITY_ + extern thread_local void (*const fxalloc)(size_t NBytes); +#else + extern thread_local void (*fxalloc)(size_t NBytes); +#endif + + /** + * @brief Указатель на функцию высвобождения памяти выделенной исключительно fxalloc + * при использовании на любом другом указателе 100% неопределённое поведение + * @note Ни в коем разе не должен изменяться из вызывающего кода!!! + * @param[in] _Ptr: void* - Указатель на блок памяти + */ +#ifndef _I_UNDERSTAND_THE_RISKS_AND_ASSUME_RESPONSIBILITY_ + extern thread_local void (*const fxfree)(void* Ptr); +#else + extern thread_local void (*fxfree)(void* Ptr); +#endif + + /** + * @brief Высвобождает ресурсы занятые потоком Вызывать непосредственно перед выходом, + * в противном случае UB или segfault + */ + void fxalloc_cleanup(); #ifdef __cplusplus } diff --git a/src/FXAlloc.c b/src/FXAlloc.c index b2250c2..feca8a0 100644 --- a/src/FXAlloc.c +++ b/src/FXAlloc.c @@ -1,36 +1,15 @@ +#include +#include + #include "FXAlloc.h" -#include +void* fxalloc_local_init(size_t _NBytes); -// В этой переменной настраиваем градации и предположительное количесвто блоков -static const FXGrade grades[] = { - { 32, 200 }, { 64, 200 }, { 128, 8000 }, - { 256, 4000 }, { 512, 2000 }, { 1024, 1200 }, - { 4096, 200 }, { 0x10000, 4 }, - { 0 } // Ноль-терминант -}; +void fxfree_prod(void* _Ptr); +void fxfree_summ(void* _Ptr); +void fxfree_prof(void* _Ptr); - - -#ifdef _WIN32 - // Windows-версия -__declspec(thread) extern void* (*fxalloc)(size_t _NBytes); -__declspec(thread) extern void (*fxfree)(void* _Ptr); -#else - // POSIX-версия - extern static pthread_key_t thread_key; - - extern void* (*fxalloc)(size_t _NBytes); - extern void (*fxfree)(void* _Ptr); -#endif - - -extern static pthread_key_t thread_key; +thread_local void* (*fxalloc)(size_t _NBytes) = fxalloc_local_init; +void (*fxfree)(void* _Ptr) = fxfree_prod; void* fastalloc(); - -void init_tls() { - pthread_setspecific(thread_key, (void*)fxalloc); - fxalloc = fastalloc; - // или более сложный вариант с хранением структуры -} \ No newline at end of file