У нас есть python/pyperformance, но он в целом не позволяет отслеживать изменения в GC в силу исторических причин. У нас есть Py_STATS, но такие сборки редко собираются и там смотрят на другое.
При внедрении Incremental GC был нарушен процесс (я не знаю причин) и его добавили в обход PEP. PEP наверное позволил бы на ранних этапах найти больше проблем, чем после внедрения. Работы по подготовке PEPa ведутся.
Сейчас в 3.15+ мы добавили новое API для мониторинга событий GC (я буквально неделю назад на PyCon Russia рассказывал, можно посмотреть у меня в гитхабе слайды), будем на основе этого строить какие-то бенчмарки.
Проблема в том, что это волонтерская работа, которая идет в свободное время, которого не так много, к сожалению.
Всем привет, я немного затронул эту движуху - у кого есть вопросы задавайте.
Кому интересно (простите за рекламу) в одной из статей своей серии о сборке мусора в питоне я разбирал как устроен инкрементальный сборщик мусора, также можно посмотреть доклад с UfaDevConf, в котором я рассказывал как инкрементальный сборщик может оказать влияние на, первый взгляд, безобидную программу.
Однако из-за порционной обработки на окончательное освобождение памяти требуется больше времени.
Вот тут сказано самое главное, но очень вскольз.
Инкрементальный сборщик мусора привнес две "новые" для CPython концепции - фазу MarkAlive и инкремент сборки мусора.
И обе концепции в реальной жизни могут неприятно выстрелить. MarkAlive может привести к квадратичное сложности (видео по ссылке выше как раз об этом) если у вас довольно большой набор локальных переменных в текущем фрейме.
Из за того, что реальная работа по сборке мусора откладывается на неопределенное время, циклы, которые существуют в программе (в частности в httpx в Response) живут дольше, чем в поколенческом GC. А у Response довольно большой payload, там помимо SSL контекста довольно много всего. В итоге память не успевает освобождаться и нижележащий аллокатор выделяет новую память. В зависимости от размера payload (в статье есть эксперименты, на гитхабе тоже, на DPO можно увидеть Cyclotron, который сделал Нил для этих целей) аллокация может стабилизироваться на различной полке (1Гб, 8Гб, 20Гб и тд.), что очевидно не приемлемо для многих сервисов.
Поддерживать две версии накануне бета релиза тоже не решились, т.к. код GC довольно сложная вещь и это потребовало бы больше усилий по сопровождению. Ну и 3.14.5 совершил очень редкую вещь, когда в patchlevel релизе отменили сложную функциональность, которая затронула много всего. Таких прецедентов в 3.* всего два наверное.
Для неизменяемых структур можно делать оптимизации связанные с использованием из нескольких потоков, например, снизить количество refcount операций и/или локов. Подсчет ссылок как в FreeThreaded версии, так и в GIL-enabled JIT версии все еще сильно влияет на производительность.
У take семантика забрать значения, у as оставить на месте и вернуть копию. Можно было бы использовать steal, но от него решили отказаться в пользу существующего прецедента в bytearray.
В gcmon я сделал выгрузку в Perfetto UI (можно chrome trace json format использовать, можно perfetto protobuf, в последнем варианте больше функциональности). Оно конечно будет не онлайн, но дает богатые возможности для работы с данными. Плюс есть SQL, которым можно данные обрабатывать и даже добавлять "дополнительные" метрики.
Идея в том, что "последовательный поиск в отсортированном массиве" идет по значениям "двоичного дерева" для определенного уровня. Поэтому это можно в данном контексте назвать двоичным поиском.
В статье выше есть пример
[40|80]
/ | \
[10|20] [50|60] [90|100]
Вот для этого примера последовательный поиск идет сначала для значений 40, 80. Потом на уровень ниже и т.д.
Что не заставило себя долго ждать gh-155176: Don't track frozendicts whose contents can never be tracked by the GC by aisk · Pull Request #155178 · python/cpython
У нас есть python/pyperformance, но он в целом не позволяет отслеживать изменения в GC в силу исторических причин. У нас есть
Py_STATS, но такие сборки редко собираются и там смотрят на другое.При внедрении Incremental GC был нарушен процесс (я не знаю причин) и его добавили в обход PEP. PEP наверное позволил бы на ранних этапах найти больше проблем, чем после внедрения. Работы по подготовке PEPa ведутся.
Сейчас в 3.15+ мы добавили новое API для мониторинга событий GC (я буквально неделю назад на PyCon Russia рассказывал, можно посмотреть у меня в гитхабе слайды), будем на основе этого строить какие-то бенчмарки.
Проблема в том, что это волонтерская работа, которая идет в свободное время, которого не так много, к сожалению.
Всем привет, я немного затронул эту движуху - у кого есть вопросы задавайте.
Кому интересно (простите за рекламу) в одной из статей своей серии о сборке мусора в питоне я разбирал как устроен инкрементальный сборщик мусора, также можно посмотреть доклад с UfaDevConf, в котором я рассказывал как инкрементальный сборщик может оказать влияние на, первый взгляд, безобидную программу.
Вот тут сказано самое главное, но очень вскольз.
Инкрементальный сборщик мусора привнес две "новые" для CPython концепции - фазу MarkAlive и инкремент сборки мусора.
И обе концепции в реальной жизни могут неприятно выстрелить. MarkAlive может привести к квадратичное сложности (видео по ссылке выше как раз об этом) если у вас довольно большой набор локальных переменных в текущем фрейме.
Формирование инкремента довольно запутанная вещь и, главное, не контролируемая извне. В итоге GC call может произойти, но инкремент не будет создан и никакая работа по сборке мусора выполнена не будет. Это как раз ситуация из первой ссылки в посте - Observed memory leak in ssl library: Python 3.14 GC issue · Issue #142516 · python/cpython .
Из за того, что реальная работа по сборке мусора откладывается на неопределенное время, циклы, которые существуют в программе (в частности в httpx в Response) живут дольше, чем в поколенческом GC. А у Response довольно большой payload, там помимо SSL контекста довольно много всего. В итоге память не успевает освобождаться и нижележащий аллокатор выделяет новую память. В зависимости от размера payload (в статье есть эксперименты, на гитхабе тоже, на DPO можно увидеть Cyclotron, который сделал Нил для этих целей) аллокация может стабилизироваться на различной полке (1Гб, 8Гб, 20Гб и тд.), что очевидно не приемлемо для многих сервисов.
Поддерживать две версии накануне бета релиза тоже не решились, т.к. код GC довольно сложная вещь и это потребовало бы больше усилий по сопровождению. Ну и 3.14.5 совершил очень редкую вещь, когда в patchlevel релизе отменили сложную функциональность, которая затронула много всего. Таких прецедентов в 3.* всего два наверное.
На моих данных из gcmon T-Digest работал не правильно, а вот DDSketch от DataDog работал и работает отлично. А вот тут отличная статья от них Computing accurate percentiles with DDSketch
И раз уж зашел разговор - исключить из сборщика мусора!
Для неизменяемых структур можно делать оптимизации связанные с использованием из нескольких потоков, например, снизить количество refcount операций и/или локов. Подсчет ссылок как в FreeThreaded версии, так и в GIL-enabled JIT версии все еще сильно влияет на производительность.
У take семантика забрать значения, у as оставить на месте и вернуть копию. Можно было бы использовать steal, но от него решили отказаться в пользу существующего прецедента в bytearray.
В gcmon я сделал выгрузку в Perfetto UI (можно chrome trace json format использовать, можно perfetto protobuf, в последнем варианте больше функциональности). Оно конечно будет не онлайн, но дает богатые возможности для работы с данными. Плюс есть SQL, которым можно данные обрабатывать и даже добавлять "дополнительные" метрики.
Предупреждение для потомков: статья, как и обе библиотеки, нейрослоп.
0.14.5, но как они отменили бесплатный план пользоваться перестал
YMMV, вот одна из сессий рефакторинга в qwen code (5 часов потому что делал в фоне)
17М токенов (16М конечно закешировано)
Там немного по другому тарифу верификация - Правила тарификации для SourceCraft | Документация
Opencode TUI позволяет вставлять картинки из буфера обмена (под виндой)
Крутая статья, спасибо!
Идея в том, что "последовательный поиск в отсортированном массиве" идет по значениям "двоичного дерева" для определенного уровня. Поэтому это можно в данном контексте назвать двоичным поиском.
В статье выше есть пример
Вот для этого примера последовательный поиск идет сначала для значений 40, 80. Потом на уровень ниже и т.д.
В 3.15 размер будет больше - gh-133059: Increase PYNSMALLPOSINTS size by dg-pb · Pull Request #133160 · python/cpython
Размер кеша в новых версиях поменялся
Спасибо, интересно!
Не знал про счетчики Морриса - спасибо!
Уточню, volatile необходимо использовать когда значение может измениться из вне, например, при работе с портами.