Добавлена глава дневника аллокатора за 02.05.2026
This commit is contained in:
@@ -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-форэвэр! 😂);
|
||||
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