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

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

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

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

Другие наши проекты: https://tprg.ru/med
Download Telegram
Прототип Cloudflare ужал текст в кэше в 2,8 раза, потратив на это несколько процентов CPU

Казалось бы, текст в интернете и так сжат. Но по замерам Cloudflare около 71% текстовых ответов приходят от origin-серверов без Content-Encoding: сжимает уже edge, а на диск кэша объект ложится сырым. При этом HTML, JSON, CSS и JS дают 67,3% запросов и 22,3% байтов, а картинки и видео 21,4% запросов и 63,3% байтов, их пересжимать бессмысленно.

Прототип Cache Transcoding внутри Pingora сжимает подходящие ответы zstd уровня 3 при записи в кэш, между дата-центрами гоняет их сжатыми и распаковывает перед клиентом. Кодирование стоит 4,31 нс на байт, декодирование 1,56 нс, коэффициент 2,834x на двух тестовых объектах, а не на всём кэше. Порог 4 КиБ отсёк мелочь и потерял всего 1% выигрыша.

Главная фраза статьи: стоимость кодирования платится один раз, когда объект попадает в кэш. Приём переносится на nginx с proxy_cache и Varnish без изменений в идее; порядок действий и где считать CPU разобрали на сайте.

@prog_stuff
Один младший бит: как реализация FMA вскрыла одинаковую ошибку в Rust std, std::simd и musl

Shnatsel переносил формально верифицированный алгоритм fused multiply-add в библиотеку fearless_simd, добавил тесты на миллион субнормальных значений и получил расхождение. Дальше оказалось, что f32::mul_add в стандартной библиотеке Rust ошибается ровно так же, как и fmaf() в musl, а контрпример к первой версии патча нашла языковая модель.

Ошибка живёт в программной эмуляции FMA, на железе с аппаратной инструкцией её нет: затронуты старые Intel без AVX2, Hygon и 32-битный ARM. Автор не берётся оценить практический ущерб, но называет сценарий, где это больно: детерминированные симуляции, которые обязаны давать одинаковые биты на разных машинах. Проверка из трёх hex-чисел и состояние патчей на сайте.

@prog_stuff
👍2
Разработчик сделал бэкенд компилятора, чтобы написать игру для Game Boy на чистом Rust

Game Boy не является целью Rust даже на уровне Tier 3: процессор SM83 не поддерживается LLVM. Автор под ником zlfn начинал с SDCC и библиотеки GBDK, а закончил собственным форком LLVM с бэкендом Z80/SM83 и форком rustc с целью sm83. Теперь cargo-gb build собирает crate в ROM, а cargo-gb run сразу запускает эмулятор.

Внутри есть Rust-библиотеки для графики, звука, ввода и консоли, упаковка кода в банки по 16 КиБ и собственный линкер. Готовый ROM sprite.gb можно скачать и запустить в любом эмуляторе; исходник примера лежит в examples/sprite.

Автор предупреждает, что проект не тестировался вне его машины и это ранняя стадия. Но это редкий пример, когда «Rust везде» доказано не докладом, а бэкендом компилятора под восьмибитную приставку. Репозиторий на GitHub.

@prog_stuff
❤‍🔥3
Стековый байткод против регистрового: замер на одном языке, одном железе и честной методике

Максим Шевалье-Буавер, в прошлом автор YJIT для Ruby, переписала VM своего языка Plush с стековой модели на регистровую и разложила, откуда взялось ускорение. Инструкция стала 64-битным словом с тремя операндами; a + b из трёх диспетчеризаций превратилось в одну. Сама смена модели дала 1,55 раза по геометрическому среднему, слитые сравнения-переходы, непосредственные операнды и свёртка констант добавили ещё 25%.

Методика: 11 чередующихся запусков на тест, медиана, повтор всего набора. Медиана ускорения 2,07 раза, максимум 3,37, тесты GC не сдвинулись. Против Lua 5.5.1 на fib быстрее на 24%. Главный урок автора: в интерпретаторе считайте инструкции, а не такты. Полный разбор на сайте.

@prog_stuff
Модуль std ускорил сборку Seastar на 22% без единой правки в исходниках

Чуаньцы Сюй из команды Clang показал два способа подключить import std; к проекту, который об этом не знает. Preload заставляет компилятор загружать BMI модуля std перед каждой единицей трансляции через -fmodule-file. Module Map идёт дальше: файл std.modulemap подменяет #include <vector> и остальные STL-заголовки на import std; автоматически.

Замер на Seastar, Clang и libc++ из ветки 24, -j8, медиана из трёх прогонов. Wall-time: 92,21 с с заголовками, 81,09 с с Preload, 71,55 с с Module Map, то есть минус 12% и минус 22%. Пользовательское CPU-время упало с 655,7 до 497,5 с. Память при Preload выросла на 2,7%, при Module Map снизилась на 3,3%.

Из ограничений: нужен Clang 24 (в 23 автор ловил зависание), в module map нельзя включать заголовки с макросами вроде cassert, а заголовки пришлось пробросить симлинками. Полный патч к CMake лежит в ветке автора, разбор в блоге.

@prog_stuff
Двухчасовое расследование о том, откуда взялась фраза про преждевременную оптимизацию

Её полвека цитируют то как Кнута, то как Хоара, чаще всего чтобы осадить желание написать код побыстрее. Кейси Муратори собрал больше 200 исторических документов, от переписки Дейкстры времён «GOTO considered harmful» до отчётов конференций NATO 1968 года, и показал, при каких обстоятельствах фраза родилась и к чему её на самом деле применяли.

Попутно у Хоара в 1965 году нашлась конструкция, похожая на SSA-форму, а у Страуструпа в 1979-м приём, который сегодня называют dependency injection. В нашем канале Tproger разобрали подробнее.

@prog_stuff
Выделите всю память при старте и никогда больше: как TigerBeetle защищается от перегрузки

Алексей Кладов (matklad) отвечает на письмо читателя, который получил use-after-free в матчере ордеров с пулом объектов, и выводит из этого два приёма из TigerStyle. Первый: никакой динамической аллокации после инициализации. Программа запускается с --orders-max=1_000_000, выделяет массив под миллион ордеров одной строкой и всё, что сверх лимита, отклоняет.

На возражение «а вдруг память ещё есть» ответ: а вдруг нет? Попытка выделить ещё один объект под нагрузкой заканчивается OOM-киллером, который снимает весь процесс с миллионом ордеров внутри, а то и супервизор. Со статическим лимитом система может не стартовать без памяти, но если стартовала, деградирует предсказуемо. По дороге разбирается, почему пул объектов одного типа превращает опасный use-after-free в скучный детерминированный баг.

@prog_stuff
Сколько знаков в 52 факториала и как прикинуть это без калькулятора

Началось с бытового вопроса: насколько велико число перестановок колоды карт. Дальше Эли Бендерски задумался, как оценивать такие величины, не имея под рукой ни калькулятора, ни компьютера.

Оказалось, что за оценкой количества знаков в факториале стоит вполне занятная математика, и разбор разворачивает её шаг за шагом, без предварительных знаний сверх школьных.

Жанр здесь не прикладной, а тот, ради которого такие блоги и читают: короткое погружение в тему, которая на работе не понадобится, но перестраивает интуицию про рост чисел.
«Zero-cost» compile-time информация о типах стоит экспоненциально, а runtime-таблица линейно

Джинджер Билл, автор языка Odin, объясняет, почему Odin форматирует вывод через RTTI, а не через генерацию кода на этапе компиляции. Таблица типов растёт линейно: N типов, N записей, одна процедура печати на все, ноль дополнительной работы у семантического анализатора. Её размер можно прочитать в бинарнике в байтах.

CTTI специализирует код под каждый тип и каждую комбинацию: сериализатор N типов в K форматов даёт N на K инстанциаций, и это повторяется в проверке типов, кодогенерации и размере бинарника. Цену этого никто не может назвать в цифрах, потому что она размазана по компилятору, зато её называют «бесплатной». Автор аккуратно разводит «известно на этапе компиляции» и «бесплатно перечислить на этапе компиляции»: это разные вещи.

@prog_stuff
Задержка, пропускная способность или цена токена: карта компромиссов инференса LLM

Филип Кили из Baseten раскладывает все приёмы ускорения инференса на две группы. Одни двигают развёртывание вдоль кривой компромисса: размер батча (маленький даёт низкую задержку и дорогой токен, большой наоборот), tensor parallelism с дорогой all-to-all коммуникацией ради задержки, expert parallelism, который на широких MoE может занимать целую стойку. Другие сдвигают саму кривую: квантизация в MXFP4 и NVFP4, оптимизация ядер, speculative decoding (EAGLE-3, DSpark, DFlash), разнесение prefill и decode по разным воркерам.

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

@prog_stuff
WhatsApp* классифицирует мошеннические сообщения на устройстве, не нарушая сквозное шифрование

Задача с виду противоречивая: распознать мошенническое сообщение и не прочитать переписку. Meta* публикует технический обзор Scam Alert до массового выката, вместе с ограниченной бетой, и приглашает исследователей безопасности его ломать.

Решение целиком на устройстве: содержимое сообщений не покидает телефон ради классификации и не отправляется автоматически ни в WhatsApp*, ни в Meta*, ни кому-либо ещё. Функция опциональна и включается пользователем.

Принципы названы прямо: модель достаточно мала, чтобы работать на мобильном железе, достаточно проста, чтобы её опубликовать для независимой проверки, и достаточно эффективна без серверной части. Недавние успехи в моделях на устройстве как раз и сделали такой размен возможным.

*Компания Meta и её продукты признаны экстремистскими, их деятельность запрещена на территории РФ.
1🤯1