We rewrote the Ghostty GTK application 🔥 Горячее 💬 Длинная дискуссия
Ghostty GTK-часть переписана с нуля
Проект завершён: Linux/BSD-версия теперь полностью использует GObject из Zig и проверена Valgrind.
Что изменилось
- Zig-структуры обёрнуты в GObject; память управляется счётчиками ссылок.
- При обновлении конфига старый объект освобождается автоматически, когда исчезают ссылки.
- Появились сигналы, свойства, действия GTK и современные UI-файлы Blueprint.
- Новые виджеты добавляются быстрее (анимированная рамка, вкладки в заголовке и т.д.).
Valgrind Каждый коммит прогонялся под Valgrind.
- Потребовался большой suppression-файл (в основном GTK/драйверы).
- Найдены: утечка и неопределённое обращение в Zig-коде, ошибка
WeakRef
в GTK, которые иначе вызывали редкие краши.
Комментарии (194)
- Ghostty переписывает GUI на GTK/Zig, столкнувшись с проблемами GObject и управления памятью.
- Участники обсуждают, что GTK навязывает свою ООП-модель и счётчики ссылок, что сложно сочетать с Zig/Rust.
- Некоторые считают GTK не «родной» на Linux и предлагают Vala, Qt или собственный UI.
- Пользователи жалуются на баги прокрутки, копирования, nano и отсутствие поиска.
- Автор признаёт выбор GTK компромиссом ради кроссплатформенности и «родного» вида.
Going faster than memcpy
Как обогнать memcpy
Профилируя Shadesmar, увидел: при больших (>512 КБ) сообщениях 97 % времени уходит на memcpy
между процессной и разделяемой памятью. Решил ускорить копирование.
Разбор memcpy
perf
показал:
__memmove_avx_unaligned_erms
— это memcpy
через memmove
, AVX, 32 байта за раз, поддержка не выровненных блоков и ERMS (железный цикл REP MOVSB
).
memmove
выбран, т.к. допускает перекрытие.- Для <4 КБ используется SSE2, иначе —
REP MOVSB
+ AVX. - Не-временные (
NT
) инструкции иprefetcht0
уменьшают кэш-промахи.
Способ 1: простой REP MOVSB
void _rep_movsb(void *d, const void *s, size_t n) {
asm volatile("rep movsb"
: "=D"(d), "=S"(s), "=c"(n)
: "0"(d), "1"(s), "2"(n)
: "memory");
}
Тот же цикл, что и в glibc
, но без лишней логики.
Комментарии (63)
- Часть выгоды даёт отказ от лишнего копирования: часто данные можно использовать на месте.
- Несколько участников отмечают, что без контроля кэшей и правильной сериализации бенчмарки теряют смысл.
- График в конце вызывает сомнения: скачки пропускной способности выглядят неправдоподобно.
- Для IPC обсуждают zero-copy через размещение данных сразу в shared memory (Iceoryx, Boost.Interprocess, DPDK).
- Большинство сходится к выводу: для обычных задач лучше довериться стандартному
memcpy
/std::memcpy
, особенно в glibc.
A fast, growable array with stable pointers in C
Моя предыдущая статья о обобщённых структурах данных в C готовила почву к теме: структура, которая заменяет динамические массивы, даёт стабильные указатели и хорошо работает с аренными аллокаторами. Её переоткрывали много раз под разными именами: “levelwise-allocated pile” (2001), в Zig — Segmented List, частично похожая на C++ std::deque. Мне нравится название Per Vognsen — Segment Array.
Скачать мой однофайловый заголовок segment_array.h можно, подписавшись на рассылку.
Идея проста: фиксированный массив указателей на сегменты; каждый следующий сегмент вдвое больше предыдущего; новые сегменты выделяются по мере необходимости. Поскольку элементы не двигаются, указатели на них стабильны, не остаются “дыры” в арене, а доступ по индексу — за O(1).
Реализация
Структура на C:
typedef struct { u32 count; int used_segments; u8 *segments[26]; } SegmentArrayInternal;
Почему всего 26 сегментов? Из 64 бит указателя обычно реально используются 48, так что 49 сегментов уже перекрывают адресное пространство (~256 ТиБ). Я предпочитаю индекс u32 (до ~4 млрд элементов) — это даёт 32 сегмента. Ещё убираем 6 маленьких (1..32), начинаем с 64, остаётся 26 сегментов — хватает для 4 294 967 232 элементов (чуть меньше UINT32_MAX). Фиксированный массив рядом со структурой снижает риск промаха кэша.
Размеры сегментов — степени двойки: проще математика и быстрые сдвиги для индексов.
#define SMALL_SEGMENTS_TO_SKIP 6
#define log2i(X) ((u32) (8*sizeof(unsigned long long)
- __builtin_clzll((X)) - 1))
u32 capacity_for_segment_count(int segment_count) { return ((1 << SMALL_SEGMENTS_TO_SKIP) << segment_count) - (1 << SMALL_SEGMENTS_TO_SKIP); }
void *_sa_get(SegmentArrayInternal sa, u32 index, size_t item_size) { int segment = log2i((index >> SMALL_SEGMENTS_TO_SKIP) + 1); u32 slot = index - capacity_for_segment_count(segment); return sa->segments[segment] + item_sizeslot; }
log2i использует __builtin_clzll (подсчёт ведущих нулей) для быстрого вычисления номера сегмента.
Clang оптимизирует _sa_get до ~10 инструкций x86-64 (-O3), так что узким местом будет память, а не вычисления индекса. При последовательной итерации можно обходить сегменты напрямую; в segment_array.h есть макрос.
Выделение нового элемента:
u32 slots_in_segment(int segment_index) { return (1 << SMALL_SEGMENTS_TO_SKIP) << segment_index; }
void *_sa_alloc(SegmentArrayInternal *sa, size_t item_size) { if (sa->count >= capacity_for_segment_count(sa->used_segments)) { size_t segment_size = item_size * slots_in_segment(sa->used_segments); sa->segments[sa->used_segments++] = malloc(segment_size); } sa->count++; return _sa_get(sa, sa->count-1, item_size); }
Замечание: можно сделать ёмкость строго степенью двойки, если первые два сегмента одинакового размера. Код станет менее изящным, но это спасает от ~50% потерь памяти при использовании как массива бакетов в хеш-таблице со степенью двойки.
Дженерики
Я применяю технику из прошлой статьи для типобезопасного хранения любого типа. Макрос связывает тип с общей структурой:
#define SegmentArray(type)
union {
SegmentArrayInternal internal;
type *payload;
}
Дальше макросы используют payload, чтобы передавать сведения о типе…
Комментарии (77)
- Обсуждается структура «сегментированный массив» (экспоненциальные сегменты), её плюсы и минусы, и сравнение с существующими решениями: std::deque, ropes, Zig std.SegmentedList, rust-array-stump, plf::colony.
- Критика терминологии: это не «массив» в классическом смысле из‑за неконтигуозной памяти; многие API ожидают сплошной/страйдовый буфер и не подойдут.
- Производительность: при локальных L1-итерациях вычислительная часть индексации может быть ощутима; для больших объёмов память становится бутылочным горлышком. Предлагаются оптимизации итерации по сегментам и замечания про clz/bsr/lzcnt и опции компилятора.
- Виртуальная память как альтернатива: резервирование большого диапазона и по мере роста коммит страниц/guard pages; отмечены плюсы на Linux (MAP_POPULATE, mremap), но плохо для embedded/WASM.
- Сравнение с deque: фиксированные блоки vs экспоненциальные, поддержка prepend, рандом-доступ есть; реализация MSVC критикуется за малый размер блока, GNU/libc++ лучше.
- Недостатки сегментов: ухудшение предвыборки/кэш-локальности при линейной итерации, отсутствие стабильной непрерывности для API, сложность с хеш-таблицами при росте (rehash), потенциальный перерасход памяти при экспоненциальных размерах.
- Предложения: настраиваемый минимальный размер сегмента, функции «склейки» мелких сегментов, разбор условий, когда экспоненциальные сегменты оправданы, и замечания о чрезмерной макротрюковости в C/C23.
Multics
-
Логотип Multics
-
Домой
- История »
- Возможности
- Мифы
- Project MAC
- Даты
- Глоссарий
- Проект истории
- Последний сайт
- Люди »
- Истории
- Фотографии
- Юмор
- Памятные вещи
- Библиотека »
- Статьи и доклады
- Технические статьи
- Документы разработки
- Исходники
- Симулятор
- Сайты »
- Хронология площадок
- AFDSC (Пентагон, Вашингтон)
- ASEA (Вестерос, Швеция)
- Avon (Бристоль, Англия)
- Bell Canada (2 площадки)
- CISL (Кембридж, Массачусетс)
- CNO (Миннеаполис, Миннесота)
- DND-H (Галифакс, Канада)
- DOCKMASTER (АНБ, Мэриленд)
- FORD (Детройт, Мичиган)
- GM (Детройт, Мичиган)
- Майнц (Германия)
- MIT (Кембридж, Массачусетс)
- NWGS (ВМС США, 4 площадки)
- OU (Рочестер, Мичиган)
- PRHA (Сан-Хуан, Пуэрто-Рико)
- RADC (Рим, Нью-Йорк)
- RAE (Фарнборо, Англия)
- STC (Лондон, Англия)
- System-M (Финикс, Аризона)
- Systeme X (Лувесьен, Франция)
- UC/ACTC (Калгари, Канада)
- USGS (3 площадки)
- USL (Лафайет, Луизиана)
- VPI (Блэксберг, Вирджиния)
- О сайте »
- Изменения
- Новости
- Ссылки
- Галерея
- Карта сайта
- История »
-
Поиск
-
Меню: История: Возможности | Мифы | Project MAC | Даты
Комментарии (29)
- Участники обсуждают влияние Multics на современную вычислительную технику: от безопасности и архитектуры до наследия в текущих проектах (например, STOP, происходящий от SCOMP/STOP).
- Делятся воспоминаниями об использовании Multics в британских университетах в 80-х: система считалась быстрой, апгрейды памяти были ощутимыми, доступ через терминалы и JANET, позитивный опыт работы.
- Мнения расходятся: одни критикуют «всеобъемлющесть» дизайна и сложность (в контраст к UNIX), другие подчёркивают сильные стороны Multics — кольца защиты, строгие политики доступа (MAC/ACL), сегментную память и отсутствие переполнений буфера.
- Отмечают ограниченную портируемость Multics к немногим мэйнфреймам, несмотря на теоретическую переносимость.
- Ссылаются на полезные ресурсы: мифы о Multics, оценка безопасности B2, страницы по безопасности данных (AIM/MAC), «Три вопроса» для анализа багов, меморабилии, хронологии и список недавних изменений.
- Обсуждают спад активности оригинальных установок (последние закрытия около 2000 г.), эмулятор DPS8M и печальные новости об уходе участников проекта.
- Несколько комментаторов переосмыслили роль UNIX после знакомства с историей Multics и более ранними идеями (Xerox PARC), видя в Multics самостоятельную и богатую идеями систему, а не только «предтечу UNIX».
Python performance myths and fairy tales 💬 Длинная дискуссия
Добро пожаловать на LWN.net
Этот материал для подписчиков стал доступен благодаря читателю LWN. Тысячи подписчиков зависят от LWN как от источника новостей о Linux и свободном ПО. Если статья вам понравилась, пожалуйста, рассмотрите возможность оформления подписки. Спасибо за визит!
Антонио Куни, давний инженер по производительности Python и разработчик PyPy, на EuroPython 2025 в Праге представил доклад «Мифы и сказки про производительность Python». По его мнению, привычная «мудрость» о скорости Python часто вводит в заблуждение. На примерах он показал реальные узкие места и пришел к выводу: в конечном счете предел оптимизаций упирается в управление памятью. Он начал ранний проект SPy, который, возможно, приведет к сверхбыстрому Python.
Он попросил зал поднять руки, кто считает «Python медленным или недостаточно быстрым» — рук было много (в отличие от PyCon Italy). Годы работы с производительностью и общение с разработчиками породили набор мифов, которые он хочет развеять.
Мифы
Миф: «Python не медленный». Да, часто «достаточно быстрый», особенно как «склеечный» язык в эпоху «важен только GPU». Но это верно лишь для части задач. Есть множество программ, где скорость Python критична — отсюда постоянные усилия по оптимизации интерпретатора и перенос горячих участков в Cython, Numba и т.п.
В слайдах он показал множества: «программы, где Python достаточно быстр» — подмножество «всех Python-программ», а снаружи — «все возможные программы». В идеале Python должен подходить для всех; пока что задачи, требующие максимума от процессора, не могут быть на Python. Он хочет расширять «внутренние круги».
Королларий «это всего лишь клей»: «просто перепишите горячее в C/C++» (сегодня — в Rust). Прием рабочий, но быстро упирается в стену: принцип Парето подсказывает оптимизировать 20% кода, где 80% времени, но затем срабатывает закон Амдаля — ускорив горячую часть, вы упираетесь в остальной код, который начинает доминировать во времени выполнения.
Еще миф: «Python медленный, потому что интерпретируемый». Интерпретация — лишь малая часть. Даже выражение p.x * 2 в C/C++/Rust — это загрузка, умножение, сохранение. В Python же нужно определить тип p, вызвать getattribute(), распаковать p.x и 2, выполнить операцию с учетом перегрузок и протоколов, упаковать результат, выделить память и т.д. Это диктуют семантика и динамичность языка, не способ исполнения.
Статические типы
С распространением тайпингов слышно: «теперь компиляторы могут пропускать лишнее и считать напрямую». Пример:
def add(x: int, y: int) -> int:
return x + y
print(add(2, 3))
Но аннотации не применяются во время выполнения, и можно вызвать:
print(add('hello ', 'world')) # type: ignore
Чекер доволен, но семантика сложения уже другая. Аннотации бесполезны для оптимизации и скорости, если их не гарантирует рантайм. Более того, в Python легально перегружать операции, меняя поведение в рантайме, что разрушает предпосылки для агрессивных оптимизаций.
Комментарии (200)
- Обсуждение сосредоточено на мифах о скорости Python: динамичность языка, непредсказуемость типов и плохая кэш-локальность мешают компиляторам и JIT достигать производительности системных языков без компромиссов по совместимости и простоте.
- Многие отмечают, что JIT и спекулятивное выполнение помогают на «хэппи-пате», но становятся хрупкими: небольшие изменения кода могут срывать оптимизации и резко просаживать скорость.
- Популярные пути ускорения — PyPy, Numba, Pythran, mypyc, а также перенос «горячих» участков в C/C++/Rust или использование DSL/субсетов (SPy); однако граница вызовов и динамика Python часто «съедают» выгоды.
- Отмечают альтернативы и эволюцию: Mojo как супермножество Python с статикой и компиляцией, возможное сосуществование компиляторов рядом с CPython вместо «Python 4».
- Критики указывают, что популярность Python не доказывает его производительность; многие реальные «тормоза» — это не CPU, а I/O и сеть, где помогают async и масштабирование.
- Скептики считают, что «быстрым» Python не станет без отказа от ключевых динамических свойств (примерно как в JS — оптимизации на общий случай, но с ограничениями); часть участников предлагает оставлять Python для скриптинга и клеевого кода.
- Вопросы многопоточности, старта интерпретатора и GIL остаются проблемными; параллельно обсуждают идеи «final»-квалификаторов, иммутабельности и GPU/параллельных подходов, но признают их практические ограничения.
Комментарии (78)
The reason you are not seeing crashes when allocating with Rust and freeing with C (or vice versa) is that by default Rust also uses the libc allocator.https://stdrs.dev/nightly/x86_64-unknown-linux-gnu/src/std/s... Lots of detail, little substance, and misleading section headers