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

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

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

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

Другие наши проекты: https://tprg.ru/med
Download Telegram
Почему картинка NES дрожит, хотя кадр статичный

Если подключить NES по композитному видео, изображение заметно «плывёт» даже на неподвижной сцене. Автор блога Nicole Express разобрала по таймингам, откуда берётся эта дрожь и почему она была спроектирована намеренно.

🔘 в стандарте NTSC частота цветовой поднесущей делится на частоту строк с остатком ровно 0,5 — RCA подобрала это полуцелое число специально, чтобы телевизору было проще отделять цвет от яркости;
🔘 кварц NES на 21,47727 МГц — это ровно шесть частот поднесущей, а видеочип PPU использует оба фронта сигнала, отсюда 12 фазовых оттенков в палитре приставки;
🔘 но строка у NES длиннее стандартной: 341 точка. На строку приходится не 227,5, а 227,33 цикла цвета, поэтому фазовый узор повторяется каждые три строки, а не две — картинка и рябит иначе, чем у Apple II или PC Engine;
🔘 инженеры Ricoh намеренно «портят» одну строку кадра: она чередуется между 341 и 340 точками, из-за чего из трёх возможных фазовых выравниваний экран видит только два, сменяющихся через кадр. Автор называет это самой ленивой версией интерлейсинга;
🔘 в PAL-версии приставки этого трюка нет вовсе — там другой кварц и другие делители;
🔘 по шуму на скриншотах Battletoads виден трёхкадровый повторяющийся узор: игра каждый кадр отключает рендеринг на несколько строк ради записи в видеопамять, и «пропавшая точка» проявляется прямо в помехах.

Полная статья: https://nicole.express/2026/phase-altering-by-line.html

Сохранять тем, кто любит, когда странности старого железа объясняются до последнего такта.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
Почему DuckDB обгоняет Spark на одной машине

Разбор от endjin объясняет, как встраиваемая база DuckDB превращает ноутбук в инструмент для аналитики на миллиардах строк: скорость здесь — не в масштабе, а в бережном использовании железа. Колоночное хранилище читает только нужные столбцы, векторизованное выполнение обрабатывает данные пачками по 1024–2048 значений, умещаясь в кэш процессора, а min-max-индексы пропускают целые группы строк по фильтрам. Всё параллелится на все ядра.

В тесте TPC-H DuckDB на одной машине справилась за 1 минуту 16 секунд, Spark на 32 узлах — около 8 минут. Распределённые накладные расходы дороже выигрыша от кластера.

Это не замена PostgreSQL или Kafka: один писатель, одна нода, petabyte уйдут в распределённые системы. Статья полезна тем, кто строит ETL и хочет понять, где сидит производительность.

Сохраните, если выбираете инструменты для аналитики.
👍1
На Tproger вышел разбор о том, чем пет-проект отличается от бизнеса. Разговор с Вячеславом Чикиным — серийным предпринимателем и замзавкафедрой технологического предпринимательства МФТИ.

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

https://tproger.ru/articles/pochemu-vaw-pet-proekt-eshhyo-ne-biznes-a-vy-ne-predprinimatel

Реклама. Рекламодатель: МФТИ, Физтех, ИНН 5008006211, erid:2W5zFK4QUUH

@prog_stuff
«Бесполезный» if ускорил цикл в четыре раза

Автор блога purplesyringa разобрала горячий цикл своего компрессора: j = next_j[i][j], одна инструкция mov. Казалось бы, предел. На деле это pointer chasing — каждая итерация ждёт, пока из памяти придёт результат предыдущей, и весь цикл сидит на латентности, хотя вычислений почти нет.

Трюк: обернуть присваивание в if (j != next_j[i][j]). Предсказатель ветвлений считает тело маловероятным, процессор спекулятивно гонит следующие итерации параллельно, а на редком промахе сам откатывает записи. В бенчмарке 320 мкс превратились в 80.

Отдельная линия сюжета — война с компилятором: с его точки зрения такой if бессмысленен, и оптимизатор его выкидывает. Пришлось имитировать независимость условия через volatile; читатели позже нашли, что LLVM достаточно [[unlikely]]. А «правильный» рефакторинг с битовой маской вышел бы медленнее: тест бита на x86 дороже сравнения.

Полная статья: https://purplesyringa.moe/blog/quadrupling-code-performance-with-a-useless-if/

@prog_stuff
👍2
Forwarded from Веб-страница
UI-паттерны, которые скоро можно делать без JS

Если верстаете интерфейсы каждый день, я бы сохранил этот доклад Уны Кравец с CSS Day 2026 в закладки. Она разобрала, как новые CSS-возможности убирают типичный скриптовый код: sticky-заголовок прячется через scroll-state(stuck: top), а hover-тултипы собираются на атрибутах interesttarget и popover=hint — почти без JavaScript.

Ещё два момента: sibling-index() задаёт staggered-задержки прямо в CSS, а border-shape позволяет рисовать необычные формы границ вместо border-radius. Пока часть фич работает не везде — polyfill для invokers не тянет на мобильные, так что в прод пока не нёс бы. Но следить стоит: платформа берёт на себя то, за что мы раньше тащили библиотеки.

Видео доклада на YouTube.
Баг, который 15 лет жил во всех дистрибутивах Linux

Команда VEGA разобрала use-after-free на стеке ядра (CVE-2026-43499): дефект пролежал в коде с 2011 года и присутствовал в каждом крупном дистрибутиве. Для срабатывания не нужны ни привилегии, ни специальная конфигурация ядра.

Корень — в механике futex с наследованием приоритета. Функция, снимающая поток с ожидания, чистит поле pi_blocked_on у current. На обычном пути это корректно, но на «proxy»-ветке current — уже не тот поток, что спит в ожидании, и у спящего остаётся висячий указатель на фрейм собственного, уже свёрнутого стека.

Дальше — образцовая цепочка эксплуатации: контролируемые байты распыляются на освобождённый стек, подделывается структура ожидателя, обходится KASLR. В итоге — эскалация до root и выход из контейнера со стабильностью 97%. За это Google выплатил команде 92 337 долларов по программе kernelCTF.

Полная статья: https://nebusec.ai/research/ionstack-part-2/

Сохранять тем, кто хочет увидеть, как одно неверное допущение про «кто сейчас current» превращается в root на пятнадцать лет вперёд.

@prog_stuff
1👍1
На Tproger вышел обзор онлайн-магистратуры МФТИ «Технологическое предпринимательство» — глазами разработчика, который пошёл туда после 10 лет в коммерческой разработке.

О чём: почему он не стал запускать стартап без подготовки и бросал онлайн-курсы на середине; как выглядит учёба изнутри: вебинары по выходным, персональный ментор и 1000 часов работы над собственным проектом; где программа слабая (разные стадии проектов в одной группе, неровный фидбек); во сколько магистратура обойдётся в 2026 году и как проверить формат до оплаты.

Полная статья: https://tproger.ru/articles/skolko-stoit-stat-predprinimatelem-obzor-onlajn-magistratury

Реклама. Рекламодатель: МФТИ, Физтех, ИНН 5008006211, erid: 2W5zFHGdLk9

@prog_stuff
2👍1
Как переписывать историю Git без цепочки интерактивных rebase

Автор разобрал экспериментальную команду git history из Git 2.54–2.55. Она меняет старый коммит и сама перестраивает всех его потомков.

🔘 fixup встраивает staged-правку в выбранный коммит;
🔘 reword меняет сообщение, не затрагивая рабочее дерево;
🔘 split делит коммит на части по выбранным hunks.

Операции атомарны. При конфликте Git оставляет историю в исходном состоянии. Merge-коммиты пока не поддерживаются, сохранить конфликт для ручного продолжения тоже нельзя. Поэтому область применения уже, чем у интерактивного rebase.

Полная статья: https://lalitm.com/post/git-history/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Конкурентность в стиле 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
🤯2