diff --git a/DAIRY.md b/DAIRY.md index 1d26f0c..2d40728 100644 --- a/DAIRY.md +++ b/DAIRY.md @@ -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, выслушиваем от неё какие мы "олени" и нерационально используем ресурсы, просим посчитать размер выделяемой памяти для покрытия нужд системы за одну секунду: + +
+ Чтение этого кода чревато взрывом мозга! + +```C +#pragma once + +#include +#include + +/** + * @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 + +``` +
+ +**Краткий итог:** + +* Размер пула на один блок: 72 байта. +* Расход памяти на 163 961 пакет: 11 805 192 байт (≈11,8 МБ). + +P.S.: Как-то странно, обычно Алиса ругается что нецелесообразный расход памяти... + +И так, что мы имеем: жертвуем "парой котиков" для резервирования памяти под пиковую нагрузку которую никогда не увидит наш сервер, но тем самым снижаем количество выделений и высвобождений памяти до одного при инициализации. Много это или мало в процессорном времени, скажу сразу - вечность. В таблице где мы считали количество потоков я умышлено не выводил время на алокацию, но его не долго посчитать: +Спрашиваем у нашего любимого статиста Алисы: + +
+ Ничего особого, просто таблица... + +```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 ;) +``` +
+ +#### *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. Начнём с простейшего. + +## diff --git a/templates/calc_threads.c b/templates/prompts/calc_threads.c similarity index 100% rename from templates/calc_threads.c rename to templates/prompts/calc_threads.c diff --git a/templates/prompts/prealloc_tpl.h b/templates/prompts/prealloc_tpl.h new file mode 100644 index 0000000..b8b1ac1 --- /dev/null +++ b/templates/prompts/prealloc_tpl.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +/** + * @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