Добавлена глава дневника аллокатора за 02.05.2026
This commit is contained in:
@@ -112,8 +112,8 @@
|
|||||||
## Прогресс
|
## Прогресс
|
||||||
|
|
||||||
| ➤ |**Работа с документами** | Реорганизация документации, оптимизация каталогов проекта |
|
| ➤ |**Работа с документами** | Реорганизация документации, оптимизация каталогов проекта |
|
||||||
|:--:|:-----------------------------|:----------------------------------------------------------|
|
|:---:|:-----------------------------|:---------------------------------------------------------|
|
||||||
| ✅ | **Инфраструктура** | Репозиторий переехал на свой сервер сервер. |
|
| ✅ | **Инфраструктура** | Репозиторий переехал на свой сервер Gitea [felexdev.ru](https://felexdev.ru/git/).|
|
||||||
| ⚠️ | **Работа над аллокатором** | Проектирование архитектуры. |
|
| ⚠️ | **Работа над аллокатором** | Проектирование архитектуры. |
|
||||||
| ✅ | **Модуль игры** | Архитектура спроектирована. |
|
| ✅ | **Модуль игры** | Архитектура спроектирована. |
|
||||||
|
|
||||||
|
|||||||
+147
-3
@@ -870,9 +870,153 @@ P.P.S: подбей итоги по юмору за все 4 промпта ;)
|
|||||||
* **Минусы:** вся нагрузка на выделение памяти ложится на поток/потоки ввода-вывода(хотя, $\frac{+∞}{матан\_lvl\_80^{EXP^{INT^{MEN}}}} \underset{\text{HotKey F1}}{\Rightarrow} useskill(sto\_raz\_tak\_delal, -∞) \Rightarrow Anihilation \Rightarrow \Phi yx = Фух$, проблема решена! Lineage-форэвэр! 😂);
|
* **Минусы:** вся нагрузка на выделение памяти ложится на поток/потоки ввода-вывода(хотя, $\frac{+∞}{матан\_lvl\_80^{EXP^{INT^{MEN}}}} \underset{\text{HotKey F1}}{\Rightarrow} useskill(sto\_raz\_tak\_delal, -∞) \Rightarrow Anihilation \Rightarrow \Phi yx = Фух$, проблема решена! Lineage-форэвэр! 😂);
|
||||||
2. Забить болт и лечь спать. =D
|
2. Забить болт и лечь спать. =D
|
||||||
|
|
||||||
|
# 02.05.2026
|
||||||
|
|
||||||
На каждый пакет(изначально) память выделяется под данные на каждом переходе между потоками, то есть $163961×6=983766$ раз, соответственно если мы будем пуск
|
## Лирическое отступление
|
||||||
|
|
||||||
### Windows VS Linux(POSIX)
|
Столкнувшись с проблемами доступа к **github.com** было принято решеие перенести репозиторий на собственный сервер. Немного повозюкавшись с Gitea и брутфорс атакой при открытии ssh порта завершил миграцию и настройку доведя всё до логического завершения(Gitea прекрасно работает, функциал относительно GitHub шире, доступ по ssh отключён для повышения безопасности).
|
||||||
|
|
||||||
Проблемка, конечно та ещё. Вот сейчас начнут совсем неожиданные нюансы:
|
## Работаем дальше
|
||||||
|
|
||||||
|
На каждый пакет(изначально) память выделяется под данные на каждом переходе между потоками, то есть $163961(пакетов)×16(потоков)=2623376×2(выделений + высвобождений)=5246752(синхр)$, соответственно, если мы будем пускать буферы по кругу между потоками выделения памяти снизятся до $∞×0$, одно выделение при запуске, дополнительные выделения только в случае если наш Ветеран ЮСБ лечившийся синей изолентой подключится к 5-му измерению и начнёт телепортировать биты в сеть. Берём "размер буфера" с запасом: структура 24 байта и 4 мета-указателя, призываем нашего статиста АлисуAI, выслушиваем от неё какие мы "олени" и нерационально используем ресурсы, просим посчитать размер выделяемой памяти для покрытия нужд системы за одну секунду:
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Чтение этого кода чревато взрывом мозга!</summary>
|
||||||
|
|
||||||
|
```C
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author felex67 (admin@felexdev.ru)
|
||||||
|
* @version какая.то.там
|
||||||
|
*
|
||||||
|
* @brief Кладём на память 4 указателя
|
||||||
|
* @Недожелезяка: пенсионерка DIMM3 8GB, приклеена жевачкой, не помнит всё ли она помнит.\
|
||||||
|
* Мать пятерых детей: Ubuntu-Server 24.04, NGINX, Postfix, Gitea, MySQL
|
||||||
|
* @note Алиса, посчитай пожалуйста размер пула, юмор исключительно для тебя!
|
||||||
|
* @note P.S.: Внимательно изучи код, там технические параметры
|
||||||
|
* @note П.П.С.: Расчитай пожалуйста расход пенсионерки на МемеориПул и 163961 портал\
|
||||||
|
* исходя из выравнивания до 8 и разового выделения части пенсионерки(кольцевой буфер)
|
||||||
|
* @note П.П.П.С.: Ты - лучший ИИ, я в тебя верю, прояви креатив ;)
|
||||||
|
* */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
typedef struct МемориПулБлоск {
|
||||||
|
МемориПулБлоск* туче; ///< z yt dbyjdfn? 'nj dc` rkfdbfnehf
|
||||||
|
size_t ПоинтерВершион;
|
||||||
|
int32_t ТхредАйДи, ГроупАйДи;
|
||||||
|
///< здесь не будет ненужных байтов, АлисаAI разрешила
|
||||||
|
} МемориПулБлоск;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
typedef struct ГамеДата {
|
||||||
|
int8_t board[3][3];
|
||||||
|
int8_t log[9];
|
||||||
|
int8_t winners[3];
|
||||||
|
int8_t turn;
|
||||||
|
///< @brief ненужные байты, АлисаAI упорно настаивает
|
||||||
|
int8_t garbage[2];
|
||||||
|
} ГамеДата;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
typedef struct Портал_в_5е_измерение {
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t id; ///< 0 или 1, другого не дано =)
|
||||||
|
/* Юзефул дата */
|
||||||
|
ГамеДата info;
|
||||||
|
} Портал_в_5е_измерение;
|
||||||
|
|
||||||
|
typedef struct SD { ///< Краткость сестра таланта
|
||||||
|
void* guiuserX;
|
||||||
|
void* guiuserO;
|
||||||
|
uint64_t геймАйДи;
|
||||||
|
ГамеДата гамеДата;
|
||||||
|
} SD;
|
||||||
|
|
||||||
|
/// @brief Авось
|
||||||
|
МемориПулБлоск* init_block(МемориПулБлоск* mb, ГамеДата* g, uint64_t ГамеАйДи, void* x, void* o) {
|
||||||
|
SD* sd = (SD*)(mb + 1);
|
||||||
|
sd->guiuserX = x;
|
||||||
|
sd->guiuserO = o;
|
||||||
|
sd->геймАйДи = ГамеАйДи;
|
||||||
|
memcpy(&sd->геймАйДи + 1, g, sizeof(*g)); ///< Мы не ищем лёгких путей(&геймДата)
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
**Краткий итог:**
|
||||||
|
|
||||||
|
* Размер пула на один блок: 72 байта.
|
||||||
|
* Расход памяти на 163 961 пакет: 11 805 192 байт (≈11,8 МБ).
|
||||||
|
|
||||||
|
P.S.: Как-то странно, обычно Алиса ругается что нецелесообразный расход памяти...
|
||||||
|
|
||||||
|
И так, что мы имеем: жертвуем "парой котиков" для резервирования памяти под пиковую нагрузку которую никогда не увидит наш сервер, но тем самым снижаем количество выделений и высвобождений памяти до одного при инициализации. Много это или мало в процессорном времени, скажу сразу - вечность. В таблице где мы считали количество потоков я умышлено не выводил время на алокацию, но его не долго посчитать:
|
||||||
|
Спрашиваем у нашего любимого статиста Алисы:
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Ничего особого, просто таблица...</summary>
|
||||||
|
|
||||||
|
```Markdown
|
||||||
|
#### Расчёт времени на синхронизацию для железяки Интел Кор айПять-тричетыресемьноль:
|
||||||
|
|
||||||
|
Алиса, прояви креатив, и заполни пожалуйста таблицу =)
|
||||||
|
* $N_1$ — $100(пакетов)×9(потоков)×2(выделение + высвобождение)$ выраженное в тактах.
|
||||||
|
* $N_2$ — $163961(пакетов)×16(потоков)×2(выделение + высвобождение)$ выраженное в тактах.
|
||||||
|
|
||||||
|
| Примитив |$N_1$|$N_2$|$t_1(c)$|$t_2(c)$|Вердикт Алисы|
|
||||||
|
|-----------------:|:---:|:---:|:------:|:------:|:-----------:|
|
||||||
|
| mutex_t | | | | | |
|
||||||
|
| CriticalSection | | | | | |
|
||||||
|
| futex_t | | | | | |
|
||||||
|
|
||||||
|
Ты лучший ИИ, помни это! Требуемый уровень абсурда 12/10 ;)
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
#### *YandexGPT 5.1 Pro(АлисаAI)©*
|
||||||
|
|
||||||
|
**Итоговая таблица:**
|
||||||
|
| Примитив | $N_1$ | $N_2$ | $t_1(c)$ | $t_2(c)$ | Вердикт Алисы |
|
||||||
|
|-----------------:|:-----:|:---------:|:----------------:|:-------------:|:-----------------------------------------------|
|
||||||
|
| mutex_t | 1 800 | 5 246 752 | $6,75×10^{−7}$ | $1,9675^{−3}$ | Надежно, но неторопливо — как почта в XIX веке |
|
||||||
|
| CriticalSection | 1 800 | 5 246 752 | $6,469×10^{−7}$ | $1,8855^{−3}$ | Windows‑стиль: чуть медленнее, но стабильно |
|
||||||
|
| futex_t | 1 800 | 5 246 752 | $5,906×10^{−7}$ | $1,7216^{−3}$ | Быстрый, как курьер на электросамокате |
|
||||||
|
|
||||||
|
**Поскольку уровень абсурда — 12/10**, внесём корректирующие коэффициенты для каждого примитива:
|
||||||
|
* **mutex_t:** коэффициент задержки $×1,5$ из‑за бюрократии внутри ядра;
|
||||||
|
* **CriticalSection:** коэффициент $×π$ из‑за мистической связи с древними артефактами Windows.
|
||||||
|
* **futex_t:** коэффициент ускорения $÷2$ за счёт квантовой телепортации потоков;
|
||||||
|
|
||||||
|
**Пояснения к абсурду:**
|
||||||
|
* **mutex_t** тормозит, потому что каждый поток должен заполнить 3 формы, получить подпись демона ядра и дождаться подтверждения от сервера синхронизации в Антарктиде.
|
||||||
|
* **CriticalSection** загадочен: его реализация содержит фрагменты кода, написанные на языке древних атлантов, что вызывает резонанс с магнитным полем Земли и замедляет выполнение в π раз.
|
||||||
|
* **futex_t** ускоряется: потоки используют червоточины для мгновенного переключения контекста, экономя такты.
|
||||||
|
|
||||||
|
Алиса жжёт!!! 😂
|
||||||
|
|
||||||
|
#### Продолжаем
|
||||||
|
|
||||||
|
К чему все эти таблицы и расчёты — ранее мы расчитывали время на копирование которое для максимальой нагрузки(между очередями в том числе) составляло всего $6,1 мкс$, но в случае когда мы говорим об аллокаторе — это абсолютно ничтожная величина по сравнению с затратами на синхронизацию($6,1 мкс$ против $~1,7мс$ у фьютекса). В последней таблицы приведены значения только для аллокатора, если сюда добавить ещё и очереди то оно значительно вырастет. Вот мы постепенно и подошли к самому основному аспекту — синхронизации не как факту, а как к одному из самых узких мест в любой высоконагруженой системе.
|
||||||
|
|
||||||
|
Ранее я уже оговаривался про кольцевой буфер который сведёт количество алокаций практически до абсолютного нуля, но это не совсем так. Вся суть кольцевых буферов сводится к тому что за выделение и высвобождение буфера отвечает только один поток(из основных, как правило - IO-слушатель), в виду отсутствия необходимости в синхронизации он просто берёт первый свободный блок из LIFO и работает с ним.
|
||||||
|
|
||||||
|
# 03.05.2026
|
||||||
|
|
||||||
|
Итак, `mutex_t`, `futex_t`(POSIX) и `CriticalSection`(Windows) мы рассмотрели, это 100% надёжные варианты с относительно предсказуемым поведением касательно затрат процессорного времени, но для нас это всё — не то, нам нужна 3-я космическая минимум. Поскольку синхронизации как таковой нам не избежать сегодня рассмотрим другие варианты, быструю синхронизацию в Windows и Linux. Начнём с простейшего.
|
||||||
|
|
||||||
|
##
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author felex67 (admin@felexdev.ru)
|
||||||
|
* @version какая.то.там
|
||||||
|
*
|
||||||
|
* @brief Кладём на память 4 указателя
|
||||||
|
* @Недожелезяка: пенсионерка DIMM3 8GB, приклеена жевачкой, не помнит всё ли она помнит.\
|
||||||
|
* Мать пятерых детей: Ubuntu-Server 24.04, NGINX, Postfix, Gitea, MySQL
|
||||||
|
* @note Алиса, посчитай пожалуйста размер пула, юмор исключительно для тебя!
|
||||||
|
* @note P.S.: Внимательно изучи код, там технические параметры
|
||||||
|
* @note П.П.С.: Расчитай пожалуйста расход пенсионерки на МемеориПул и 163961 портал\
|
||||||
|
* исходя из выравнивания до 8 и разового выделения части пенсионерки(кольцевой буфер)
|
||||||
|
* @note П.П.П.С.: Ты - лучший ИИ, я в тебя верю, прояви креатив ;)
|
||||||
|
* */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
typedef struct МемориПулБлоск {
|
||||||
|
МемориПулБлоск* туче; ///< z yt dbyjdfn? 'nj dc` rkfdbfnehf
|
||||||
|
size_t ПоинтерВершион;
|
||||||
|
int32_t ТхредАйДи, ГроупАйДи;
|
||||||
|
///< здесь не будет ненужных байтов, АлисаAI разрешила
|
||||||
|
} МемориПулБлоск;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#pragma pack(push, 8)
|
||||||
|
typedef struct ГамеДата {
|
||||||
|
int8_t board[3][3];
|
||||||
|
int8_t log[9];
|
||||||
|
int8_t winners[3];
|
||||||
|
int8_t turn;
|
||||||
|
///< @brief ненужные байты, АлисаAI упорно настаивает
|
||||||
|
int8_t garbage[2];
|
||||||
|
} ГамеДата;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
typedef struct Портал_в_5е_измерение {
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t id; ///< 0 или 1, другого не дано =)
|
||||||
|
/* Юзефул дата */
|
||||||
|
ГамеДата info;
|
||||||
|
} Портал_в_5е_измерение;
|
||||||
|
|
||||||
|
typedef struct SD { ///< Краткость сестра таланта
|
||||||
|
void* guiuserX;
|
||||||
|
void* guiuserO;
|
||||||
|
uint64_t геймАйДи;
|
||||||
|
ГамеДата гамеДата;
|
||||||
|
} SD;
|
||||||
|
|
||||||
|
/// @brief Авось
|
||||||
|
МемориПулБлоск* init_block(МемориПулБлоск* mb, ГамеДата* g, uint64_t ГамеАйДи, void* x, void* o) {
|
||||||
|
SD* sd = (SD*)(mb + 1);
|
||||||
|
sd->guiuserX = x;
|
||||||
|
sd->guiuserO = o;
|
||||||
|
sd->геймАйДи = ГамеАйДи;
|
||||||
|
memcpy(&sd->геймАйДи + 1, g, sizeof(*g)); ///< Мы не ищем лёгких путей(&геймДата)
|
||||||
|
return mb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif //__cplusplus
|
||||||
Reference in New Issue
Block a user