Сохранёнки программиста
6.54K subscribers
1.18K photos
59 videos
10 files
1.88K links
Заметки и ссылки на будущее, чтобы изучить когда будет время.

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/med
Download Telegram
Конкурентность в стиле Go, собранная поверх pthreads

Автор собрал на C знакомые по Go примитивы: мьютексы, condition variables, атомики, ограниченный пул воркеров и buffered/unbuffered channels. Затем сравнил их стоимость с реализацией Go.

🔘 атомики и свободные мьютексы работают на уровне Go или быстрее благодаря тонкой обёртке;
🔘 парковка потока и системные пробуждения замедляют condition variables в 7–10 раз;
🔘 на крупных задачах worker pool укладывается примерно в 10% от результата Go;
🔘 мелкая передача работы лучше даётся дешёвым goroutines.

Преимущество pthreads сохраняется на крупных задачах с редкой синхронизацией. Частые переключения быстро съедают выигрыш и оставляют системные потоки далеко позади runtime scheduler.

Полная статья: https://antonz.org/concurrency-in-c/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Нормальные TLS-сертификаты для внутренних сервисов

Автор настроил внутренние сервисы с сертификатами публичного ACME CA. Схема использует собственный домен, split-horizon DNS, VPN и nginx.

🔘 внешний и внутренний DNS возвращают разные адреса одного имени;
🔘 acme.sh получает сертификат и обновляет его по расписанию;
🔘 nginx слушает VPN-интерфейс и закрывает сервис от внешней сети;
🔘 SAN, CNAME и wildcard-сертификаты дают разные варианты организации имён.

Критичное место схемы — bind nginx: ошибка в адресе откроет сервис наружу. При наличии API у DNS-провайдера выпуск сертификата через DNS-01 часто требует меньше настроек, чем описанный HTTP-01.

Полная статья: https://tuxnet.dev/posts/tls-for-internal-services/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
Задержка в Linux: X11, Wayland, VRR и DXVK в миллисекундах

Марко Нетт собрал прибор для измерения задержки от клика до появления кадра. RP2040 эмулирует мышь с частотой опроса 1000 Гц, а фотодиод считывает яркость экрана примерно каждые 24 микросекунды. Для каждой конфигурации автор провёл три серии по сто кликов.

🔘 медианы восьми основных конфигураций уложились в 4,21–4,93 мс;
🔘 нативный X11 опередил нативный Wayland на 0,14–0,22 мс;
🔘 VRR снял 0,26–0,45 мс и уменьшил разброс результатов;
🔘 самый заметный штраф принёс XWayland: до 3,13 мс;
🔘 dxvk-low-latency дал до 0,84 мс в тесте без ограничения FPS.

Измерения сделаны на одном компьютере с RTX 4070 Super, монитором 500 Гц и KDE Plasma. На другом железе соотношение может измениться. Схемы прибора, прошивка, анализатор и сырые CSV опубликованы вместе со статьёй.

Полная статья: https://marco-nett.de/blog/measuring-input-latency-on-linux-x11-vs-wayland-vrr-dxvk/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
На Tproger вышел материал о «Точке сборки» — серии открытых вебинаров кафедры техпреда МФТИ, где основатели ИИ-стартапов делятся практикой вместо прогнозов.

О чём: почему опыт того, кто прямо сейчас собирает продукт на агентах, актуальнее любых аналитических материалов; как вайб-кодинг стал рабочим подходом в командах; что происходит с экономикой проверки гипотез, когда MVP собирается за выходные; кто выступал на первой встрече и как попасть на следующие.

Полная статья: https://tproger.ru/articles/pochemu-opyt-razrabotchikov-luchwe-prognozov-pro-ii

@prog_stuff
👍1
Тензорная библиотека на C, которую можно прочитать целиком

Большие ML-фреймворки прячут за одной строкой целую машину: раскладку данных в памяти, передачу буферов на GPU, матричное умножение, градиенты и обновление весов. Сергей Зайцев разобрал этот слой до деталей и собрал Utensil — компактную single-header-библиотеку на C.

🔘 тензор хранится как плоский массив float вместе с shape и strides, а представления разделяют данные через owner и счётчик ссылок;
🔘 каждая операция имеет CPU-реализацию и Metal kernel, состояние буферов отслеживается dirty-флагами;
🔘 матричное умножение на CPU уходит в cblas_sgemm, на GPU — в собственный kernel;
🔘 backward pass написан вручную для каждого слоя, cross-entropy считает loss и gradient за один проход;
🔘 сеть 784 → 128 → 10 на MNIST достигает примерно 97% точности на тестовой выборке.

В авторском сравнении на MacBook M1 эпоха обучения заняла 0,8 секунды, у PyTorch — около двух секунд. Этот результат относится к одной небольшой модели и конкретному компьютеру. Библиотека пока обходится без broadcasting, autograd и CUDA, а Metal привязывает ускорение к устройствам Apple. Весь путь от массива чисел до обученной сети остаётся достаточно компактным для вдумчивого чтения.

Полная статья: https://zserge.com/posts/tensor/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Типичный программист
Команда Roc переписала 300 000 строк Rust на Zig и достигла паритета

Разработчики языка Roc полтора года переносили компилятор с Rust на Zig, и недавно новый догнал оригинал по возможностям. Проверка прошла на игре Rocci Bird: меньше тысячи строк на Roc теперь собирается в 31-килобайтный WebAssembly-бинарник. Старый компилятор выдавал файл более чем вдвое больше.

Забавно, что параллельно проект Bun недавно поделился опытом обратной переписи с Zig на Rust. Так что это не история «какой язык круче», а скорее редкий случай, когда две команды демонстрируют единственно правильную логику — для разных целей нужны разные инструменты. Официальный релиз Roc 0.1.0 пока не вышел. Обещают позже в этом году.

Разбор — в статье.
💊2🤪1
$ORIGIN для загрузчика ELF — без правки ядра

Динамический загрузчик в ELF прописан абсолютным путём, поэтому relocatable-бинарники для Nix, Buck и Bazel приходится собирать с костылями. Фарид Закария показал, как научить Linux подставлять интерпретатор относительно расположения самого бинарника — связкой eBPF и binfmt_misc, не трогая VFS.

🔘 программа eBPF проверяет ELF magic, берёт путь исполняемого файла и вызывает bpf_binprm_set_interp до запуска процесса;
🔘 регистрация — struct_ops плюс запись в /proc/sys/fs/binfmt_misc/register;
🔘 при обычной передаче управления через exec могут измениться argv[0], /proc/<pid>/cmdline и /proc/self/exe — здесь этих артефактов нет;
🔘 отдельный сегмент PT_INTERP_NIX включает новую механику только для явно помеченных файлов, старые бинарники работают как раньше.

Полная статья: https://fzakaria.com/2026/07/20/linux-kernel-will-support-origin-sort-of

Сохранять тем, кто собирает relocatable-бинарники и хочет увидеть, на что ещё способен eBPF.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Postgres 19 меняет сжатие по умолчанию: с pglz на LZ4

В PostgreSQL 19 планируется смена алгоритма сжатия TOAST, который четверть века по умолчанию был pglz. Разбор от Crunchy Data объясняет, что именно поменяется для TEXT, VARCHAR, BYTEA и JSONB.

🔘 в тесте автора 2000 строк по ~10 КБ сжались за 6 мс с LZ4 против 50 мс с pglz — примерно в 8 раз быстрее, распаковка близка по времени;
🔘 на одном наборе данных LZ4 дал 111 байт из 10 400 исходных (98,9% сокращения) против 186 байт у pglz, но на других данных pglz может выигрывать по размеру;
🔘 статья подробно разбирает порог TOAST около 2040 байт и порядок «сначала сжать, потом вынести наружу», наружу уходит 18-байтовый указатель;
🔘 для индексов есть практический предел: строка длиннее ~2704 байт после сжатия в индекс не помещается — повторяющаяся строка на 5000 символов ужимается до 38 байт и проходит, случайная строка на 2816 символов уже нет.

Полная статья: https://www.crunchydata.com/blog/postgres-19-compression-from-pglz-to-lz4

Сохранять тем, кто хранит в Postgres большие JSONB и ни разу не думал, каким алгоритмом они сжаты.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥2
Сервис на виртуальных потоках упёрся в 420 запросов в секунду при 9% CPU

Полевой гайд на Foojay разбирает типичный инцидент с виртуальными потоками Java: сервис перестал масштабироваться на ~420 запросах в секунду, хотя процессор загружен на 9%. Арифметика сходится точно: 8 CPU × (1000 / 19 мс внешнего HTTP-вызова) ≈ 421.

Причина — pinning: виртуальный поток занимает carrier thread, и приложение незаметно превращается обратно в ограниченный пул платформенных потоков. До JDK 24 pinning часто вызывают блоки synchronized, ещё один источник — native-код.

🔘 для диагностики в JDK 21–23 есть флаг jdk.tracePinnedThreads, в JFR — событие jdk.VirtualThreadPinned;
🔘 лечение — ReentrantLock вместо synchronized, обновление JDK и отказ от удержания блокировки на время медленных сетевых вызовов.

Полная статья: https://foojay.io/today/virtual-thread-pinning-field-guide/

Сохранять тем, у кого Loom в проде и график RPS выходит на плато задолго до загрузки CPU.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
SIMD стоит знать не только авторам simdjson

Митчелл Хашимото, автор Vagrant, Terraform и терминала Ghostty, разобрал бытовой SIMD на живом коде своего терминала и свёл его к одной схеме из пяти шагов. Примеры на Zig, но идея общая для любого языка с поддержкой векторов.

Задача такая: найти конец очередного печатаемого куска текста, то есть первый кодпоинт со значением 0xF или ниже. Скалярный вариант укладывается в одну строку цикла, векторный добавляет к нему двенадцать строк без единого интринсика под конкретный процессор.

🔘 порог сравнения размножается по всем линиям через @splat, а ширину вектора отдаёт хелпер: 4 значения u32 на ARM NEON, 8 на AVX2, 16 на AVX-512;
🔘 цикл шагает сразу на целый вектор, а не на одно значение;
🔘 сравнение values > threshold выполняется для всех линий одной инструкцией процессора;
🔘 свёртка @reduce(.And, ...) отвечает, прошли ли все линии, а @bitCast и @ctz показывают номер первой упавшей;
🔘 остаток данных и процессоры без нужной ширины вектора обслуживает тот же скалярный цикл, с которого всё начиналось.

Потолок ускорения равен числу линий: в 4, 8 или 16 раз. В сквозном замере от программы до готового состояния терминала на десктопе с AVX2 вышло примерно в 5 раз. Автор отдельно объясняет, зачем писать это руками: компиляторы векторизуют мало и непредсказуемо, а неявная оптимизация может тихо исчезнуть после правки соседнего кода или обновления компилятора.

Полная статья: https://mitchellh.com/writing/everyone-should-know-simd

Сохранять тем, кто видит в профайлере горячий цикл по большому массиву и до сих пор считает SIMD чужой территорией.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Postgres упирался в 2900 записей в секунду, не нагружая при этом ничего

Команда DBOS разобрала, откуда у LISTEN/NOTIFY репутация нерабочего при нагрузке механизма, и переписала свой стриминг до 60 тысяч записей в секунду на одном сервере.

Исходная схема обычная: каждый кусок потока, например токен ответа модели, становится строкой в таблице, а триггер на вставку шлёт NOTIFY, чтобы читатели просыпались вместо опроса. Дальше 2900 записей в секунду эта конструкция не шла, причём ни процессор, ни диск, ни память базы заняты не были.

Причина в том, что коммит транзакции с NOTIFY берёт глобальный эксклюзивный лок и держит его до конца коммита вместе с fsync. Postgres обещает доставлять уведомления в порядке коммитов, а сам порядок известен только когда коммит завершён: лок решает это противоречие ценой полной сериализации. Групповой коммит при этом отключается, и записи идут строго по одной.

🔘 патч, который ждут в Postgres 19, глобальный лок не убирает. Он оптимизирует более узкий случай, когда каналов много и каждый слушатель ждёт свой;
🔘 обход: копить уведомления в памяти и сбрасывать пачкой одной транзакцией, тогда лок берётся раз на пачку, а не на каждую запись;
🔘 плата за это — уведомления, потерянные при падении процесса, поэтому читатели вдобавок редко опрашивают таблицу как запасной путь;
🔘 после переделки упор идёт уже в процессор базы, а не в блокировку.

Про задержку авторы пишут 15–100 мс, но по их же графику это диапазон для нагрузки до 40 тысяч записей в секунду. Ближе к 60 тысячам медиана уходит примерно к 0,5 с, а 99-й перцентиль к секунде. Код бенчмарка выложен, конкретный инстанс базы в статье не назван.

Полная статья: https://www.dbos.dev/blog/postgres-listen-notify-scalability

Сохранять тем, кто держит очередь или пуш-уведомления прямо в Postgres и однажды упрётся в потолок, которого не видно ни в одном мониторинге.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Админский токен GitHub уехал в прошивку камеры вместе со сборкой веб-интерфейса

Автор блога разобрал прошивку камеры видеонаблюдения Hanwha Vision, бывшей Samsung Techwin, и нашёл внутри токен GitHub с правами администратора на сотни репозиториев компании.

Путь до находки:

🔘 внешний архив прошивки открывается паролем HTW плюс номер модели, внутри лежит ещё один зашифрованный fwimage.tgz;
🔘 ключ AES-256-CBC собирается в момент запуска из XOR-таблицы внутри бинарника fwupgrader, вектор инициализации лежит там же открытым текстом, а сам fwupgrader просто вызывает консольный openssl;
🔘 распакованный rootfs автор прогнал через trufflehog, и токен нашёлся примерно в тридцати файлах;
🔘 попал он туда из-за сборки интерфейса на Vite: одной переменной при сборке присвоили целиком process.env, поэтому окружение CI-задачи целиком записалось в файлы интерфейса вместе с токеном npm, служебными переменными Kubernetes и внутренними адресами.

Значит, токен с большой вероятностью уходил по сети каждому, кто открывал админку камеры.

Чтобы понять масштаб, автор скачал около 500 прошивок примерно из 600 моделей, расшифровал тем же способом 62% и нашёл токен только в трёх, причём везде один и тот же. Hanwha ответили на письмо за 12 часов и отозвали токен.

Отдельная деталь: среди служебных переменных оказались адреса из диапазона 55.101.x.x, который принадлежит Министерству обороны США. Компания ответила, что не знала об этом и унаследовала схему адресации от Samsung Techwin, а теперь собирается её менять.

Полная статья: https://hhh.hn/hanwha-github-token/

Сохранять тем, кто прокидывает переменные окружения в сборку фронтенда и ни разу не смотрел, что в итоге лежит в собранном бандле.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯4
Потребитель получил ответ 204, закоммитил offset, а задачу через миллисекунды отклонили

Сахан Серасингхе 12 июля разобрал класс потерь в событийных системах, где сообщение пропадает без исключения, без строчки в логе и без попадания в очередь недоставленных. Он называет это разрывом подтверждения: приём запроса подтверждён, а работа так и не началась.

Доставка at-least-once держится на повторах и идемпотентных потребителях, и оба механизма опираются на одно допущение: если обработка не удалась, потребитель об этом узнает. Но ответ 202 Accepted значит «запрос принят», а не «работа выполнена», и даже 204 No Content бывает двусмысленным. Коммит offset при этом означает куда более сильное: все сообщения до N обработаны полностью и повторять их нельзя.

🔘 типичный сценарий: потребитель отправляет задачу, получает 204, коммитит offset, а управляющий слой через миллисекунды отклоняет её из-за квоты, admission control или переполнения внутренней очереди;
🔘 проверка только на err != nil опасна, потому что самый разрушительный исход выглядит как nil;
🔘 граница может быть любой асинхронной: брокер очередей, workflow engine, фоновый обработчик, HTTP-диспетчер;
🔘 повторы, идемпотентность и транзакция брокера тут не спасают, раз подтверждается только приём задачи;
🔘 надёжнее подтверждать запуск отдельно: чтение после записи или опрос по correlation ID, а явный отказ считать ошибкой;
🔘 повторы ограничивают бюджетом, а после его исчерпания шлют алерт или отправляют сообщение в очередь недоставленных.

Автор отдельно оговаривает обратный риск. Ошибка самой проверки состояния не должна автоматически порождать новую отправку, иначе вместо потерянного сообщения появится дубликат, и вся идемпотентность на стороне обработчика уедет в мусор.

Полная статья: https://sahansera.dev/the-acknowledgment-gap/

Сохранять тем, кто отлаживает пропажу заказов или платежей, которые в логах отправителя выглядят успешно обработанными.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
Первый открытый файл обычно получает дескриптор 3, потому что ядро выдаёт минимальный свободный номер в таблице процесса

Хесус Эспино 13 июля объяснил виртуальную файловую систему Linux, тот слой, из-за которого одни и те же вызовы одинаково работают с ext4, с /proc и с примонтированной по сети NFS. Устроен он на C-структурах с указателями на функции: каждая файловая система подставляет свои реализации, а ядро вызывает их через общие имена.

Объектов в этой модели четыре, и разделение между ними отвечает на бытовые вопросы вроде «почему у файла может быть два имени».

🔘 superblock представляет конкретную смонтированную файловую систему;
🔘 inode хранит сам файл, каталог или ссылку вместе с метаданными, но собственного имени не знает;
🔘 dentry связывает имя внутри родительского каталога с inode, и ядро кэширует в том числе отрицательные dentry для отсутствующих файлов;
🔘 struct file создаётся на каждое открытие, поэтому два открытия одного inode имеют независимые позиции чтения;
🔘 набор file_operations даёт принцип «всё является файлом»: сокеты, устройства, epoll и таймеры живут за дескрипторами с совершенно разным поведением;
🔘 дескриптор — это просто индекс в таблице указателей struct file *, а номера 0, 1 и 2 обычно уже заняты стандартными потоками ввода, вывода и ошибок.

Открытие /etc/hostname идёт компонент за компонентом, и при попадании в кэш каталогов до самой файловой системы дело не доходит. Режим RCU-walk позволяет читателям обходить закэшированные пути почти без блокировок, переключаясь на обычные блокировки, когда путь меняют. Чтение потом проходит через страничный кэш: первый cat поднимает страницу с диска, а следующие обслуживаются из оперативной памяти.

Полная статья: https://internals-for-interns.com/posts/linux-kernel-vfs/

Сохранять тем, кто разбирает странности с I/O: файл удалён, а место не освободилось, или две ручки на один файл почему-то читают из разных мест.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
После 243 одинаковых блоков узлы разошлись, итоговые хеши 0xfaf6ba1e и 0xdab0977c

Antithesis 27 июля рассказала, как прогнала через свой фаззинг четыре реализации Raft: HashiCorp Raft, Aeron Cluster, OpenRaft и MicroRaft. Ошибки нашлись во всех четырёх. Авторы сразу оговариваются, что это не претензия к протоколу и не претензия к командам: Raft тяжело реализовать без ошибок в принципе.

Raft отвечает за согласие узлов в распределённой системе, и у него есть формальная спецификация на TLA+. Но спецификация описывает не всю реализацию: снапшоты, замена реплик и повреждение пакетов в неё не входят, а живут именно в коде.

🔘 стенд собран из трёх узлов и машины состояний Chain of Blocks, которая просто хеширует случайные байтовые команды;
🔘 инвариант тривиальный: у всех узлов на одной позиции цепочки должен совпадать хеш;
🔘 сбои вносились детерминированно, без убийства узлов, рестартов и порчи диска, хватило сетевых разделений и помех;
🔘 до блока 243 хеши совпадали, на 244 узлы применили разные данные, дальше расхождение только копилось;
🔘 в HashiCorp Raft нашли три ошибки, одну на безопасность и две на живучесть, причём часа тестирования хватило на отчёт;
🔘 асинхронные heartbeats обрабатывались вне основного цикла протокола, и гонка со сменой term могла затронуть четыре из пяти свойств безопасности.

Две другие ошибки бытовые по последствиям. Передача лидерства оставляла goroutine заблокированной, а флаг передачи поднятым, и переизбранный узел переставал принимать клиентов до перезагрузки. Обработка InstallSnapshot не отбрасывала расходящийся неподтверждённый лог, отсюда повторные снапшоты, livelock и потенциально неограниченный рост временных файлов.

Вывод авторов: формальная модель и тестирование со сбоями закрывают разные дыры, спецификация не заменяет проверку живого кода.

Полная статья: https://antithesis.com/blog/2026/finding-bugs-in-raft-implementations/

Сохранять тем, кто выбирает библиотеку консенсуса под свой сервис и собирается верить ей на слово, потому что «протокол доказан».

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
На одних и тех же данных среднее выросло на 9 процентов, а медиана упала на 46

По одному и тому же набору замеров агрегаты latency расходятся в разные стороны, и понять по ним, стало быстрее или медленнее, невозможно. Фарид Закария показал 27 июля, почему так выходит и какими графиками это разбирать. Мотивация прикладная: ускорения линкера lld видны в бенчмарках, но тонут в шуме продакшен-дашбордов.

Сценарий: за неделю выкатывают кэширующий слой. Один и тот же набор замеров даёт среднее плюс 9 процентов, со 112 до 122 мс, медиану минус 46 процентов, с 99 до 54 мс, p95 плюс 103 процента и p99 плюс 119 процентов.

🔘 плотность распределения объясняет противоречие: до выката один пик, после два;
🔘 кривые CDF до и после пересекаются около 140 мс, ниже этой границы запросы ускорились, выше замедлились, поэтому ни один перцентиль не описывает эффект целиком;
🔘 shift function, то есть разность по каждому перцентилю, показывает и величину, и знак эффекта по всему распределению сразу;
🔘 ridgeline по дням раскатки с логарифмической осью X ловит, как быстрый пик уезжает влево, а медленный растёт справа, при том что heatmap новую популяцию почти не показывает;
🔘 разрез по попаданию в кэш возвращает унимодальность: попадания быстрее базовой линии, промахи медленнее из-за лишнего сетевого хопа;
🔘 совместный график latency и размера ответа даёт причину: большие объекты не влезают в кэш, бимодальность размера порождает бимодальность времени.

Починить можно двумя способами: поднять максимальный размер объекта в кэше или резать большие ответы на части. В рабочей практике автор режет по размеру бинарников, порог 50 MiB. Оговорки самого автора: датасет синтетический с фиксированным seed, данные и графики сделаны с помощью ИИ, а KDE чувствительна к параметру сглаживания.

Полная статья: https://fzakaria.com/2026/07/27/the-mean-means-nothing

Сохранять тем, кому после выката приносят дашборд, где среднее, медиана и p99 указывают в разные стороны, и просят сказать, стало лучше или хуже.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
PostgreSQL нарисовали как 3D-город: буферный пул отражающим бассейном, WAL янтарным районом, грязные страницы красными плитками

Николай Самохвалов выложил PGSimCity, браузерную модель кластера PostgreSQL в виде города. Репозиторий создан 25 июля. Кластер показан целиком: 16 backend-процессов с подсветкой состояния, включая idle in transaction, буферный пул, показанный выборкой из 1024 кадров, кварталы WAL, обслуживания, реплик и восстановления.

Хранилище доведено до уровня heap-файлов, страницы по 8 КиБ лежат полями, B-деревья нарисованы деревьями, рядом TOAST, FSM, visibility map и страничный кэш ОС. Цвета несут смысл: чистые страницы синие, vacuum фиолетовый, чекпоинты розовые, репликация оранжевая.

🔘 сценарий Cache thrash ставит shared_buffers в 16 МиБ, и clock sweep начинает гонку, а бэкенды сами вытесняют грязные страницы;
🔘 сценарий Checkpoint storm, или шторм контрольных точек, показывает стену full-page writes после каждого чекпоинта;
🔘 сценарий с долгой транзакцией: горизонт xmin тонет, autovacuum до таблиц доезжает, но сообщает ноль удаляемых строк, а таблица продолжает раздуваться;
🔘 Query lab показывает стадии разбора, переписывания, планирования и выполнения запроса, а по желанию запускает PGlite, настоящий PostgreSQL, собранный в WebAssembly;
🔘 модель привязана к PostgreSQL 18: значения по умолчанию сверены с релизом 18.3 и исходниками ветки REL_18_STABLE, прошли три раунда ревью;
🔘 детерминированные тесты падают в CI при расхождении и фиксируют формулы, например долю попаданий в кэш как blks_hit, делённое на сумму blks_hit и blks_read.

Автор оговаривает, что это модель, а не эмулятор: код Postgres в городе не исполняется, числа масштабированы, чтобы их можно было разглядеть. Анимация буферов использует фиксированное кольцо из 32 кадров вместо реального правила PostgreSQL 18 для массового чтения. Управление касанием проверялось только в мобильной эмуляции Chrome.

Полная статья: https://github.com/NikolayS/PGSimCity#readme

Сохранять тем, кому нужно объяснить коллеге или себе, что происходит между чекпоинтом, autovacuum и буферным пулом, когда база вдруг начинает тормозить.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
💯1
Цикл ускорился с 3,1 до 45 гигабайт в секунду после того, как из него убрали ранний выход

Александр Нойбек и Грег Орцелл из GitHub рассказали 31 июля, как в поиске по коду приводят текст к одному регистру. Операция простая, но Blackbird, поисковый движок GitHub, прогоняет через неё каждый байт: 180 миллионов репозиториев, больше 480 ТБ исходного кода, и для каждого потенциального результата запроса свёртка регистра нужна снова.

Привычный приём выглядит разумно: идти по байтам, а на первом не-ASCII прерваться и отдать остаток полноценному Unicode-пути. На Apple M4 это даёт 3,1 ГиБ/с. Оказалось, что тормозит именно ранний выход: пока условие выхода из цикла зависит от данных, компилятор не может его векторизовать.

🔘 если убрать break, но оставить ветвление в теле, LLVM векторизует наполовину: 7,6 ГиБ/с и 25 векторных инструкций;
🔘 полностью безветвевой проход даёт больше 45 ГиБ/с и 41 векторную инструкцию, это уже пропускная способность памяти;
🔘 безветвевое тело с сохранённым break медленнее наивного варианта, 2,6 против 3,1 ГиБ/с: безусловная запись каждого байта обходится дороже редкой хорошо предсказанной ветки;
🔘 компромисс из стандартных библиотек, когда сначала сканируют машинными словами по 16 байт, а потом сворачивают регистр, читает данные дважды и упирается в 23 ГиБ/с;
🔘 попытка слить эти два прохода в один даёт 8,7 ГиБ/с: ветка, зависящая от данных, возвращается каждые 16 байт, и цикл снова обрабатывает по одному блоку без разворачивания;
🔘 таблица для редкого пути ужата до 1776 байт: 1484 отображения Unicode 16.0 уложились в 238 диапазонов на 59 страницах из примерно 1960, и свёртка идёт арифметикой прямо над байтами UTF-8, без декодирования символа.

Авторы оговариваются, что замеры иллюстративны и сильно зависят от микроархитектуры. Библиотека покрывает только простые отображения регистра: немецкое ß в ss и турецкие правила в неё не входят. Арифметика над байтами требует корректного UTF-8 в кратчайшей форме записи.

Полная статья: https://github.blog/engineering/architecture-optimization/dont-stop-early-case-folding-source-code-at-memory-speed/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👏1
Тот же файл, разложенный с 17 155 строк до 3 695, снизил стоимость одной правки со 159 564 входных токенов до 27 360

Мартин Фаулер опубликовал 30 июля эксперимент: можно ли измерить выгоду рефакторинга, если код правит агент. Приложение примерно на 150 тысяч строк, из них около 120 тысяч на Rust. Слой доступа к данным разросся в один файл на 17 155 строк, без выделенных функций, без внутреннего языка и почти без классов, зато с чистой границей и интерфейсом наружу.

Замер устроен так: берётся одна показательная правка, описанная одним запросом. Её выполняет свежий подагент и сообщает израсходованные токены, изменения выбрасываются. Дальше применяется один шаг рефакторинга, и та же правка выполняется заново. Агент ничему не учится между шагами, поэтому эксперимент не портится накопленным опытом, как испортился бы с живым инженером.

🔘 базовый замер: 159 564 входных токена, 1705 выходных, 342 секунды на правку;
🔘 после пятнадцати шагов рефакторинга самый большой файл ужался до 3 695 строк, а входные токены упали до 27 360, то есть на 83 процента;
🔘 объём всего слоя почти не изменился: 17 155 строк превратились в 16 608 строк в 19 файлах, так что экономия идёт не от количества кода;
🔘 расход держался ровно, пока падал только общий объём, и обвалился ровно тогда, когда начал уменьшаться самый большой файл;
🔘 по логам видно, что агент с каждым шагом читал всё меньшие куски кода: выигрыш в том, что он стал находить нужный файл, а не перебирать весь слой;
🔘 при цене Sonnet 5 в три доллара за миллион токенов экономия на одной правке составляет 39,7 цента, зато повторяется при каждом следующем изменении в этом слое.

Фаулер отдельно оговаривает, что случайная нарезка большого файла на мелкие так не сработает: агенту пришлось бы читать много файлов подряд в поисках нужного места. Счёт токенов приблизительный, Claude не отдаёт надёжный способ считать их на лету, поэтому подагент считал символы и делил на четыре. Эксперимент идёт на одном приложении, написанном агентами с нуля, а стоимость самого рефакторинга в эти 39,7 цента не входит.

Полная статья: https://martinfowler.com/articles/exploring-gen-ai/refactoring-economic-benefit.html

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
1🤯1
Время до первого ревью выросло с 3,5 часа до 16, хотя кода стали писать больше

Джон Ван, технический директор Assembled, разобрал 7 августа, что случилось с их разработкой после перехода на агентов. Инженеры чувствовали, что стали быстрее, а метрики поставки почти не двигались: пул-реквестов заводили больше, а вливали ненамного больше прежнего.

В данных нашлось объяснение. Открытых пул-реквестов стало заметно больше, стопки выросли до двадцати штук на одну задачу, размер одной правки увеличился в 2,5 раза, потому что агент пишет более объёмный дифф на то же изменение. Время до первого ревью поднялось с медианных 3,5 часа в декабре 2025 до 16 с лишним часов в мае 2026. Узким местом оказалось человеческое ревью, а число ревьюеров осталось прежним.

В ответ собрали автоматического ревьюера для малорисковых правок:

🔘 каждый пул-реквест независимо смотрят два агента в отдельных песочницах, а третий сводит оба отзыва и применяет политику одобрения;
🔘 в политике есть жёсткие правила, например не одобрять правки больше тысячи изменённых строк, и содержательные: не трогать аутентификацию, биллинг, права доступа, работу с секретами и ключами, не вводить новых архитектурных приёмов;
🔘 первая версия политики оказалась слишком строгой: она отклоняла столько, что люди переставали ею пользоваться, а отключённым ревьюером ничего не ускоришь;
🔘 обратная крайность опаснее: слишком мягкая политика превращается в канал, через который сознательно проводят то, что не хочется показывать человеку;
🔘 после полного запуска автоодобрения дали 43 процента всех влитых правок, а медиана такого ревью — восемь минут;
🔘 инженеры начали подгонять пул-реквесты под критерии политики, так что она работает как система стимулов: чего требуешь, того и становится больше.

По результатам за три недели влитых правок стало в 2,4 раза больше, чем до агентов, строк кода в 2,8 раза, то есть работу не просто нарезали мельче. Пропускная способность больших правок от 600 строк выросла в 3,5 раза, хотя их автоматический ревьюер обычно не одобряет. Рефакторинг вырос в 7,5 раза, работа над тестами в 3,4. Сообщений о багах стало на 27 процентов меньше, доля откатов держится на 0,8 процента.

Автор сам оговаривает, что это наблюдение за раскаткой, а не контролируемый эксперимент, и окно слишком короткое: баги приходят с задержкой, поэтому по долгосрочному качеству выводов пока нет.

Полная статья: https://www.assembled.com/blog/code-review-bottlenecks-how-we-hill-climbed-our-way-to-higher-pr-throughput

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1