Отличный текст от Google, про оптимизацию memcpy: https://storage.googleapis.com/pub-tools-public-publication-data/pdf/4f7c3da72d557ed418828823a8e59942859d677f.pdf #perf
Сравниваются 2 подхода - вручную написанный ассемблер, и автоматически настроенный(под нагрузку) код на С++. Второй способ побеждает(1% перфа Google). Я прямо ОЧЕНЬ советую прочесть хотя бы первую половину статьи, про использование SAT solver для автоматического построения алгоритма из базовых кубиков, это прямо огонь.
Так же дается описание того, как можно настроить memcpy под свою нагрузку.
На мой взгляд, конечно, оптимизацией memcpy должны авторы CPU(кто сказал "rep movsb"?):
1) Не нужно иметь сложный код от архитектуры к архитектуре(поэтому такой memcpy можно всегда инлайнить по месту)
2) Memcpy в процессоре имеет больше доступа к состоянию CPU, и может делать какие-то архитектурные оптимизации. Например, если поспекулировать, то memcpy может работать на уровне протокола синхронизации кешей - CPU читает cache line, и, вместо того, чтобы "прокачивать" его через регистры в output cache line, сразу пишет этот cache line по нужному адресу в свой cache, чтобы протокол синхронизации кешей сбросил этот cache line по нужному адресу в памяти. memcpy в CPU может игнорить write ordering.
3) Профит получит не только Google(не у всех есть 10 студентов, которых можно пустить на решение такой проблемы).
Тут, конечно, есть некоторые сложности(например, взаимодействие такой сложной инструкции и прерываний, взаимодействие с page cache), но они, кажется, решаемы. К сожалению, в x86 rep movsb проигрывает другим реализациям:
https://stackoverflow.com/questions/43343231/enhanced-rep-movsb-for-memcpy
Почему? Почему Intel оптимизирует AES, который не виден cluster wide, но не оптимизирует memcpy, который виден?
Для ARM у меня пока нет данных, но инструкции уже завезли:
https://news.ycombinator.com/item?id=28601386
Сравниваются 2 подхода - вручную написанный ассемблер, и автоматически настроенный(под нагрузку) код на С++. Второй способ побеждает(1% перфа Google). Я прямо ОЧЕНЬ советую прочесть хотя бы первую половину статьи, про использование SAT solver для автоматического построения алгоритма из базовых кубиков, это прямо огонь.
Так же дается описание того, как можно настроить memcpy под свою нагрузку.
На мой взгляд, конечно, оптимизацией memcpy должны авторы CPU(кто сказал "rep movsb"?):
1) Не нужно иметь сложный код от архитектуры к архитектуре(поэтому такой memcpy можно всегда инлайнить по месту)
2) Memcpy в процессоре имеет больше доступа к состоянию CPU, и может делать какие-то архитектурные оптимизации. Например, если поспекулировать, то memcpy может работать на уровне протокола синхронизации кешей - CPU читает cache line, и, вместо того, чтобы "прокачивать" его через регистры в output cache line, сразу пишет этот cache line по нужному адресу в свой cache, чтобы протокол синхронизации кешей сбросил этот cache line по нужному адресу в памяти. memcpy в CPU может игнорить write ordering.
3) Профит получит не только Google(не у всех есть 10 студентов, которых можно пустить на решение такой проблемы).
Тут, конечно, есть некоторые сложности(например, взаимодействие такой сложной инструкции и прерываний, взаимодействие с page cache), но они, кажется, решаемы. К сожалению, в x86 rep movsb проигрывает другим реализациям:
https://stackoverflow.com/questions/43343231/enhanced-rep-movsb-for-memcpy
Почему? Почему Intel оптимизирует AES, который не виден cluster wide, но не оптимизирует memcpy, который виден?
Для ARM у меня пока нет данных, но инструкции уже завезли:
https://news.ycombinator.com/item?id=28601386
#gold #terminal #foot #perf
https://zed.dev/
CRDT - прикольно, tree sitter - тоже(хочу его интегрировать в свой редактор), GPU accelerated GUI - ну такое. Я вот раньше думал, что GPU accelerated GUI это что-то очень крутое, а потом понял, что ерунда это все. IMHO c GPU GUI нужно собрать всего 3 программы - wayland compositor(потому что он много туда-сюда гоняет пикселей), browser, terminal(уже опционально).
Знаете, какая самая дорогая для CPU задача при отрисовке html странички в браузере?
Залить страницу белым фоном!
Ладно, это не совсем так(думаю, отрисовать много текста ЧУТЬ дороже), но мне же нужен шок-контент. Это очень дорогая операция для CPU, потому что он ограничен в своей полосе по памяти, и пишет нолики(или 0xFF) один за другим. Прикиньте, выполнить цикл 3000*2000*3*60rps раз - это сколько нужно тактов? GPU это делает очень быстро - у нее более широкий доступ к памяти, и дофига тупых ядер, которые медленно(но суммарно ОЧЕНЬ быстро(можно разбить всю заливаемую область по числу ядер GPU)) выполняют цикл for (i = x1; i < x2; ++i) mem[i + y*dimx] = 0xFF;
Cобственно, это самый важный факт, который нужно знать про GPU, чтобы понимать, почему они рулят в ML и прочей подобной нечисти, но об этом в другой раз.
Отрисовка текста - это просто bit blit(https://en.wikipedia.org/wiki/Bit_blit, а кто-то помнит, что это?) нескольких текстур на GPU. (Ладно, не совсем так, в оригинальном bit blit не было смешивания с альфа-каналом).
Вообще, конечно, рендер GUI на GPU - это из пушки по воробьям, тупой аппаратный bit blit справился не хуже бы, и стоил бы при той же скорости в 100 раз дешевле. Но имеем, что имеем.
Terminal emulator Foot, например, делает эту задачу во все мои 16 потоков CPU, и работает сравнимо с alacritty(https://codeberg.org/dnkl/foot/wiki/Performance). #foot
"Крутизна" 2D GPU рендеринга несколько преувеличена. Тупой 2D render для консоли(отрисовать сетку из прямоугольничков с текстом) - 20 строк кода(если не считать setup текстур со шрифтами, и все такое). Я однажды их даже написал - https://github.com/pg83/ted/blob/3c3f54a69b806bd7eb96f4c56189ce2a7f0507c5/gl#L325 Вот, inner loop 2D GPU accelerated rendering, не хуже, чем в Alacritty. Не такой sexy, конечно, на fixed pipeline, но я люблю тупые решения. Зачем я это сделал? Мне было интересно, насколько generic я сделал widget для редактирования текста. Вот, я перенес его из консоли в OpenGL, за 100 строк кода. Пользоваться не стал, незачем :)
https://zed.dev/
CRDT - прикольно, tree sitter - тоже(хочу его интегрировать в свой редактор), GPU accelerated GUI - ну такое. Я вот раньше думал, что GPU accelerated GUI это что-то очень крутое, а потом понял, что ерунда это все. IMHO c GPU GUI нужно собрать всего 3 программы - wayland compositor(потому что он много туда-сюда гоняет пикселей), browser, terminal(уже опционально).
Знаете, какая самая дорогая для CPU задача при отрисовке html странички в браузере?
Залить страницу белым фоном!
Ладно, это не совсем так(думаю, отрисовать много текста ЧУТЬ дороже), но мне же нужен шок-контент. Это очень дорогая операция для CPU, потому что он ограничен в своей полосе по памяти, и пишет нолики(или 0xFF) один за другим. Прикиньте, выполнить цикл 3000*2000*3*60rps раз - это сколько нужно тактов? GPU это делает очень быстро - у нее более широкий доступ к памяти, и дофига тупых ядер, которые медленно(но суммарно ОЧЕНЬ быстро(можно разбить всю заливаемую область по числу ядер GPU)) выполняют цикл for (i = x1; i < x2; ++i) mem[i + y*dimx] = 0xFF;
Cобственно, это самый важный факт, который нужно знать про GPU, чтобы понимать, почему они рулят в ML и прочей подобной нечисти, но об этом в другой раз.
Отрисовка текста - это просто bit blit(https://en.wikipedia.org/wiki/Bit_blit, а кто-то помнит, что это?) нескольких текстур на GPU. (Ладно, не совсем так, в оригинальном bit blit не было смешивания с альфа-каналом).
Вообще, конечно, рендер GUI на GPU - это из пушки по воробьям, тупой аппаратный bit blit справился не хуже бы, и стоил бы при той же скорости в 100 раз дешевле. Но имеем, что имеем.
Terminal emulator Foot, например, делает эту задачу во все мои 16 потоков CPU, и работает сравнимо с alacritty(https://codeberg.org/dnkl/foot/wiki/Performance). #foot
"Крутизна" 2D GPU рендеринга несколько преувеличена. Тупой 2D render для консоли(отрисовать сетку из прямоугольничков с текстом) - 20 строк кода(если не считать setup текстур со шрифтами, и все такое). Я однажды их даже написал - https://github.com/pg83/ted/blob/3c3f54a69b806bd7eb96f4c56189ce2a7f0507c5/gl#L325 Вот, inner loop 2D GPU accelerated rendering, не хуже, чем в Alacritty. Не такой sexy, конечно, на fixed pipeline, но я люблю тупые решения. Зачем я это сделал? Мне было интересно, насколько generic я сделал widget для редактирования текста. Вот, я перенес его из консоли в OpenGL, за 100 строк кода. Пользоваться не стал, незачем :)
Zed
Zed — The editor for what's next
Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
https://www.phoronix.com/news/Go-1.21-RC
#perf
Меня расстраивают игры с PGO в Go.
Go сейчас - sweet point между скоростью компиляции и качеством генерируемого кода. Это, кстати, одна из тех причин, по которым мне НРАВИТСЯ писать на Go. Не просто "ок", а именно нравится - вспоминается детство, безумно быстрый borland pascal (безумно - потому что он рожал код моментально на моем pentium 75, а не на современных многоядерных монстрах), и это ощущение "потока", когда от изменения строчки кода до ее проверки проходит нисколько времени.
Но, как это обычно бывает, у разрабов Go закончились идеи на тему "как же ускорять получающийся код, не замедляя компилятор", а оплачивать ипотеку как-то надо, вот и пошли в дело не самые приятные идеи.
Много раз писал и буду писать, что я почти всегда предпочту компилятор, генерирующий код в 2 раза медленнее, но делающий это в 20 раз быстрее. Потому что ускорить целевую программу в 2 раза, в целом, решаемая задача, а нервные клетки не восстанавливаются.
#perf
Меня расстраивают игры с PGO в Go.
Go сейчас - sweet point между скоростью компиляции и качеством генерируемого кода. Это, кстати, одна из тех причин, по которым мне НРАВИТСЯ писать на Go. Не просто "ок", а именно нравится - вспоминается детство, безумно быстрый borland pascal (безумно - потому что он рожал код моментально на моем pentium 75, а не на современных многоядерных монстрах), и это ощущение "потока", когда от изменения строчки кода до ее проверки проходит нисколько времени.
Но, как это обычно бывает, у разрабов Go закончились идеи на тему "как же ускорять получающийся код, не замедляя компилятор", а оплачивать ипотеку как-то надо, вот и пошли в дело не самые приятные идеи.
Много раз писал и буду писать, что я почти всегда предпочту компилятор, генерирующий код в 2 раза медленнее, но делающий это в 20 раз быстрее. Потому что ускорить целевую программу в 2 раза, в целом, решаемая задача, а нервные клетки не восстанавливаются.
Phoronix
Go 1.21 Enabling PGO For Faster Performance, Tuned Garbage Collector
The Go 1.21 release candidate is out today and it's interesting on the performance front plus a few language additions like min / max / clear functions as well as further enhancing its standard library.
👍12👎9🤔4💯1
commit -m "better"
#wasm #wasi #bootstrap Однажды начав, бывает сложно остановиться. Собрал еще 4 wasm рантайма: https://github.com/wasmx/fizzy https://github.com/wasm3/wasm3 https://github.com/WasmEdge/WasmEdge https://github.com/tetratelabs/wazero Из них только wasmedge…
#perf #wasm
Ну вот я, с помощью лома и такой-то матери, собрал нетривиальное приложение, которое actually do something - компрессор brotli.
И потестил его в разных runtime, которые у меня уже были, vs. нативное выполнение:
Для того, чтобы сделать какие-то реальные выводы, у меня пока мало точек, но начало положено!
Про плохой результат wasmedge - это, кажется, что-то странное, скорее всего, я его криво собрал.
Ну вот я, с помощью лома и такой-то матери, собрал нетривиальное приложение, которое actually do something - компрессор brotli.
И потестил его в разных runtime, которые у меня уже были, vs. нативное выполнение:
pg# cat g | time .../brotli -1 -c > qw.brotli.1
real 0m 0.50s
user 0m 0.46s
sys 0m 0.03s
pg# cat g | time .../wasmedge \
--enable-all \
.../brotli -1 -c > qw.brotli.2
real 1m 2.35s
user 1m 2.27s
sys 0m 0.04s
pg# cat g | time .../iwasm \
--llvm-jit \
.../brotli -1 -c > qw.brotli.3
real 0m 2.71s
user 0m 5.86s
sys 0m 0.06s
pg# cat g | time .../iwasm \
--fast-jit \
.../brotli -1 -c > qw.brotli.4
real 0m 1.21s
user 0m 2.20s
sys 0m 0.06s
Для того, чтобы сделать какие-то реальные выводы, у меня пока мало точек, но начало положено!
Про плохой результат wasmedge - это, кажется, что-то странное, скорее всего, я его криво собрал.
🔥9
commit -m "better"
#perf #wasm Ну вот я, с помощью лома и такой-то матери, собрал нетривиальное приложение, которое actually do something - компрессор brotli. И потестил его в разных runtime, которые у меня уже были, vs. нативное выполнение: pg# cat g | time .../brotli -1…
#wasm #perf
Разобрался с отставанием wasmedge.
Чтобы все работало быстро, нужно пройтись по wasm с помощью его AOT компилятора, и тогда получается вот такой результат:
Впрочем, скорость его AOT не впечатляет:
Разобрался с отставанием wasmedge.
Чтобы все работало быстро, нужно пройтись по wasm с помощью его AOT компилятора, и тогда получается вот такой результат:
real 0m 0.62sЭто уже довольно близко к нативной скорости выполнения того же бинаря.
user 0m 0.57s
sys 0m 0.03s
Впрочем, скорость его AOT не впечатляет:
pg# time .../bin/wasmedgec \
--optimize 3 \
--enable-threads \
.../brotli brotli
[2023-06-29 01:55:52.636] [info] compile start
[2023-06-29 01:55:52.669] [info] verify start
[2023-06-29 01:55:52.710] [info] optimize start
[2023-06-29 01:55:56.632] [info] codegen start
[2023-06-29 01:56:01.680] [info] output start
[2023-06-29 01:56:01.682] [info] compile done
[2023-06-29 01:56:01.686] [info] output start
real 0m9.117s
user 0m9.063s
sys 0m0.041s
🔥13
Вышел python 3.12
Думаю, самая крутая его фишка - это https://docs.python.org/3.12/howto/perf_profiling.html#perf-profiling
Одной строкой - интеграция с perf record/report.
Да, да, в python появился нормальный профайлер!
Тут, конечно, можно устроить срач на тему, что, если вы запускаете профайлер для python, то вы заранее делаете что-то не так. Но, тем не менее, штука очень крутая.
Думаю, самая крутая его фишка - это https://docs.python.org/3.12/howto/perf_profiling.html#perf-profiling
Одной строкой - интеграция с perf record/report.
Да, да, в python появился нормальный профайлер!
Тут, конечно, можно устроить срач на тему, что, если вы запускаете профайлер для python, то вы заранее делаете что-то не так. Но, тем не менее, штука очень крутая.
Python documentation
Python support for the Linux perf profiler
author, Pablo Galindo,. The Linux perf profiler is a very powerful tool that allows you to profile and obtain information about the performance of your application. perf also has a very vibrant eco...
👍20❤5🔥4👎1🤔1
https://ubuntu.com/blog/ubuntu-performance-engineering-with-frame-pointers-by-default #gold #LTO #perf
В ubutu включили -fno-omit-frame-pointer для 64 битных систем, по умолчанию.
Хорошая новость, из разряда "долго тупили, но опомнились, и сделали по уму".
Много раз писал, и буду писать, что вам, в среднем, не нужны оптимизации "последних 5% перфа", которые сильно усложняют отладку, и ухудшают время сборки:
- LTO. Коллеги, если вы включаете LTO в своих сборках, то вы подписываетесь на то, что будете регулярно чинить проблемы, которые просто не возникают у других людей. По двум причинам:
* Вы начинаете использовать код, который используется меньше, чем 1% пользователей вашего компилятора. Этот код хуже отлажен, в нем больше багов, он чаще будет генерить некорректный код в результате.
* Вы подвергаете свою кодовую базу стрессу, который мог совсем не предполагаться теми, кто пишет весь остальной код в вашем репозитории. Представьте себе монорепу, в которой вы пишете маленькую программу, она использует кучу библиотек из монорепы, и вы решили собрать ее с LTO. Вы наложили новый контракт на используемый вами код, и его никто не будет соблюдать, кроме вас.
Это все звучит очень теоретически, пока вы не начнете разгребать проблемы, когда компилятор что-то там хорошо "разынлайнил", и где-то закешировал регистр FS, потому что не ожидает перед собой переключение стеков, а кто-то из ваших коллег творчески поюзал код, переключающий контексты (тот или иной движок корутин, например).
Людям, которые принимают решение о выкатке кода в прод, дам совет. Если вам кто-то приносит 5% перфа, полученного за счет LTO,шлите его в хуй, спросите, за чей счет банкет, и кто будет этот код обслуживать дальше, и чинить всякие веселые баги в компиляторе, и в вашей кодовой базе. Это совершенно не бесплатные 5%, вы за них будете платить все время жизни вашего софта.
LTO имеет смысл для браузера, который собирается и отлаживается очень большой командой, и используется много кем.
Твоей программе, username, он не нужен.
- fomit-frame-pointer. Отладка затрудняется, корки совершенно бессмысленные, стектрейсы для записи в лог стоят дорого. Современные компиляторы сводят ущерб от frame pointer к минимуму.
Я иду дальше, и запрещаю UB в следующих случаях:
https://github.com/pg83/ix/blob/main/pkgs/lib/build/opt/safe/ix.sh#L4
Да, я отключаю UB в переполнениях с целыми числами, и выключаю strict aliasing.
Желающие отлаживать всякие интересные (нет) корки могут себе это отключить, на всю систему, или на отдельный пакет.
В ubutu включили -fno-omit-frame-pointer для 64 битных систем, по умолчанию.
Хорошая новость, из разряда "долго тупили, но опомнились, и сделали по уму".
Много раз писал, и буду писать, что вам, в среднем, не нужны оптимизации "последних 5% перфа", которые сильно усложняют отладку, и ухудшают время сборки:
- LTO. Коллеги, если вы включаете LTO в своих сборках, то вы подписываетесь на то, что будете регулярно чинить проблемы, которые просто не возникают у других людей. По двум причинам:
* Вы начинаете использовать код, который используется меньше, чем 1% пользователей вашего компилятора. Этот код хуже отлажен, в нем больше багов, он чаще будет генерить некорректный код в результате.
* Вы подвергаете свою кодовую базу стрессу, который мог совсем не предполагаться теми, кто пишет весь остальной код в вашем репозитории. Представьте себе монорепу, в которой вы пишете маленькую программу, она использует кучу библиотек из монорепы, и вы решили собрать ее с LTO. Вы наложили новый контракт на используемый вами код, и его никто не будет соблюдать, кроме вас.
Это все звучит очень теоретически, пока вы не начнете разгребать проблемы, когда компилятор что-то там хорошо "разынлайнил", и где-то закешировал регистр FS, потому что не ожидает перед собой переключение стеков, а кто-то из ваших коллег творчески поюзал код, переключающий контексты (тот или иной движок корутин, например).
Людям, которые принимают решение о выкатке кода в прод, дам совет. Если вам кто-то приносит 5% перфа, полученного за счет LTO,
LTO имеет смысл для браузера, который собирается и отлаживается очень большой командой, и используется много кем.
Твоей программе, username, он не нужен.
- fomit-frame-pointer. Отладка затрудняется, корки совершенно бессмысленные, стектрейсы для записи в лог стоят дорого. Современные компиляторы сводят ущерб от frame pointer к минимуму.
Я иду дальше, и запрещаю UB в следующих случаях:
https://github.com/pg83/ix/blob/main/pkgs/lib/build/opt/safe/ix.sh#L4
Да, я отключаю UB в переполнениях с целыми числами, и выключаю strict aliasing.
Желающие отлаживать всякие интересные (нет) корки могут себе это отключить, на всю систему, или на отдельный пакет.
👍17🤔9👎3🔥2💩2🫡2🥰1
https://nickb.dev/blog/the-dark-side-of-inlining-and-monomorphization/ #perf
Зумеры, в очередной раз, переизобретают и переописывают то, что всем заинтересованным людям давно известно - чрезмерный inline-инг (современное его название - мономорфизация, но кому какое дело?) - не только полезно, но и очень вредно.
Статью я проглядел мельком, поэтому не знаю, был ли там озвучен самый главный вред от чрезмерного встраивания (загрязнение кешей для кода процессора, и, тем самым, замедление на реальных задачах (но не на бенчмарках)), поэтому озвучиваю его сейчас, да.
Зумеры, в очередной раз, переизобретают и переописывают то, что всем заинтересованным людям давно известно - чрезмерный inline-инг (современное его название - мономорфизация, но кому какое дело?) - не только полезно, но и очень вредно.
Статью я проглядел мельком, поэтому не знаю, был ли там озвучен самый главный вред от чрезмерного встраивания (загрязнение кешей для кода процессора, и, тем самым, замедление на реальных задачах (но не на бенчмарках)), поэтому озвучиваю его сейчас, да.
nickb.dev
The dark side of inlining and monomorphization
After introducing an incremental lexer that is generic over a Read instance, compilation times quadrupled and output size tripled. What happened? And is it possible to claw back without any downsides?
😁7🤮3🔥2
commit -m "better"
#fast_python https://www.opennet.ru/opennews/art.shtml?num=60352 А вот, пожалуйста, новый-кленовый JIT для python. Вот цифры про perf: "По сравнению с традиционным JIT-инструментарием (LLVM -O0) предложенный JIT обеспечивает в 100 раз более быструю генерацию…
#perf #fast_python
Мне стало интересно, что там за такой новый-кленовый JIT.
И почему он должен собираться именно LLVM? Это звучало вообще странно - как так, в runtime кодогенератор от LLVM не нужен, а во время сборки - нужен? Это что за магия такая?
Все оказалось довольно просто, достаточно было прочесть https://github.com/brandtbucher/cpython/blob/justin/Tools/jit/build.py, ну и немножко https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899 (по этой ссылке содержится просьба к GCC добавить недостающие кусочки к gcc, чтобы можно было использовать не LLVM, а gcc)
(Немного в сторону от основной темы, авторы gcc, конечно, встали на дыбы, потому что как это так, не за ними все повторяют, а им надо что-то повторить за clang?
"Shouldn't we first discuss whether any of this, or particular aspects of it, are a good idea at all, before specifying behaviour that a random compiler happened to implement?")
В общем, суть в следующем: а давайте мы сконпелируем исходный текст интерпретатора с набором волшебных ключей, чтобы получившийся объектный код можно было растащить на кусочки, а потом из них собрать объектный код для байткода python?
Вот, допустим, у нас есть такой кусок байткода (это не питонячий байткод, но так будет понятнее):
Дальше в интерпретаторе есть огромный switch/case, где написано:
Далее мы компилируем этот файл в объектный код, и аккуратно вырезаем из него код, соответствующий только этому одному блоку
После чего мы проходимся по всему байткоду, который был построен cpython, и заменяем в нем отдельные инструкции на вот эти вот кусочки заранее скомпилированного нативного кода.
Затем проходимся сверху скопипасченного объектного кода парой регулярок, и получаем код, который реально может быть выполнен!
От LLVM тут нужно, чтобы он сумел скомпилировать цикл интерпретатора для другого calling convention, а, конкретно, для такого специального CC, когда все регистры сохраняет callee. Видимо, так сильно проще получить код, который можно нарезать на независимые кусочки, которые далее можно "просто" конкатенировать. Я на получившиеся кусочки глазами не смотрел, поверил автору на слово.
UPD: вот paper, где описана эта техника copy and patch - https://arxiv.org/pdf/2011.13127.pdf , from https://aha.stanford.edu/sites/g/files/sbiybj20066/files/media/file/aha_050621_xu_copy-and-patch.pdf
UPD: утащю из комментов - https://t.iss.one/c/1469934025/21379
Мне стало интересно, что там за такой новый-кленовый JIT.
И почему он должен собираться именно LLVM? Это звучало вообще странно - как так, в runtime кодогенератор от LLVM не нужен, а во время сборки - нужен? Это что за магия такая?
Все оказалось довольно просто, достаточно было прочесть https://github.com/brandtbucher/cpython/blob/justin/Tools/jit/build.py, ну и немножко https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899 (по этой ссылке содержится просьба к GCC добавить недостающие кусочки к gcc, чтобы можно было использовать не LLVM, а gcc)
(Немного в сторону от основной темы, авторы gcc, конечно, встали на дыбы, потому что как это так, не за ними все повторяют, а им надо что-то повторить за clang?
"Shouldn't we first discuss whether any of this, or particular aspects of it, are a good idea at all, before specifying behaviour that a random compiler happened to implement?")
В общем, суть в следующем: а давайте мы сконпелируем исходный текст интерпретатора с набором волшебных ключей, чтобы получившийся объектный код можно было растащить на кусочки, а потом из них собрать объектный код для байткода python?
Вот, допустим, у нас есть такой кусок байткода (это не питонячий байткод, но так будет понятнее):
...
mov A, B
...
Дальше в интерпретаторе есть огромный switch/case, где написано:
...
if (opcode == 'mov') {
auto op1 = getNextOp();
auto op2 = getNextOp();
auto& g = interpContext->globals;
g[op1] = g[op2];
}
...
Далее мы компилируем этот файл в объектный код, и аккуратно вырезаем из него код, соответствующий только этому одному блоку
if () { ... }
После чего мы проходимся по всему байткоду, который был построен cpython, и заменяем в нем отдельные инструкции на вот эти вот кусочки заранее скомпилированного нативного кода.
Затем проходимся сверху скопипасченного объектного кода парой регулярок, и получаем код, который реально может быть выполнен!
От LLVM тут нужно, чтобы он сумел скомпилировать цикл интерпретатора для другого calling convention, а, конкретно, для такого специального CC, когда все регистры сохраняет callee. Видимо, так сильно проще получить код, который можно нарезать на независимые кусочки, которые далее можно "просто" конкатенировать. Я на получившиеся кусочки глазами не смотрел, поверил автору на слово.
UPD: вот paper, где описана эта техника copy and patch - https://arxiv.org/pdf/2011.13127.pdf , from https://aha.stanford.edu/sites/g/files/sbiybj20066/files/media/file/aha_050621_xu_copy-and-patch.pdf
UPD: утащю из комментов - https://t.iss.one/c/1469934025/21379
GitHub
cpython/Tools/jit/build.py at justin · brandtbucher/cpython
The Python programming language. Contribute to brandtbucher/cpython development by creating an account on GitHub.
🔥12👍9❤4🤔2🤯2😱1
https://blog.polybdenum.com/2024/01/17/identifying-the-collect-vec-memory-leak-footgun.html #perf
Текст про то, как стандартная библиотека #rust оказалось слишком умной, и переиспользовала память Vec после того, как этот Vec был превращен в range, а из этого range снова в Vec.
Насколько я понял, там случилось ажно двесмешных штуки оптимизации:
1) into_iter().collect() переиспользовало тот же самый вектор, хотя можно было бы ожидать, что это будет похоже на shrink_to_fit()
2) into_iter().map().collect() переиспользовало старую выделенную память исходного вектора, если размер нового элемента <= размера старого элемента. Поэтому, если размер нового элемента был раз в 10 меньше, чем исходного элемента, то происходил дикий пережор памяти.
Оптимизации, конечно, семантически корректные, но спорные.
Текст про то, как стандартная библиотека #rust оказалось слишком умной, и переиспользовала память Vec после того, как этот Vec был превращен в range, а из этого range снова в Vec.
Насколько я понял, там случилось ажно две
1) into_iter().collect() переиспользовало тот же самый вектор, хотя можно было бы ожидать, что это будет похоже на shrink_to_fit()
2) into_iter().map().collect() переиспользовало старую выделенную память исходного вектора, если размер нового элемента <= размера старого элемента. Поэтому, если размер нового элемента был раз в 10 меньше, чем исходного элемента, то происходил дикий пережор памяти.
Оптимизации, конечно, семантически корректные, но спорные.
Considerations on Codecrafting
Identifying Rust’s collect::<Vec>() memory leak footgun
Over the weekend, I was working on a personal Rust project when I ran into an excessive memory usage problem. After an evening of trial and error, I found a workaround to fix the memory usage, but I still didn’t understand how the issue was even possible…
🔥8🤔6👍4🆒3
#perf
Когда-то, году в 2007, когда я "изобретал" равномерную балансировку нагрузки, и последовательно испытывал и отбрасывал разные схемы, один очень умный человек мне сказал, что я занимаюсь херней, и все уже давно придумано за нас.
Алгоритм, который он мне тогда рассказал, был устроен предельно просто - надо опросить 3 случайных хоста, и выбрать наименее нагруженный из всех трех (например, по длине очереди).
Я тогда ссыканул так сделать, потому что сеть была еще хуже, чем сейчас, хотя это сложно себе представить, и, если бы я так сделал на 3 - 4 уровнях балансировки, это легко бы отъело 100 - 150ms времени ответа.
На днях натолкнулся на https://brooker.co.za/blog/2012/01/17/two-random.html. Там написано, что надо брать не 3 случайных хоста, а два, уже на 10 бекендах разница становится заметной.
https://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf - какие-то размышления, почему именно 2.
Век живи, век учись.
Когда-то, году в 2007, когда я "изобретал" равномерную балансировку нагрузки, и последовательно испытывал и отбрасывал разные схемы, один очень умный человек мне сказал, что я занимаюсь херней, и все уже давно придумано за нас.
Алгоритм, который он мне тогда рассказал, был устроен предельно просто - надо опросить 3 случайных хоста, и выбрать наименее нагруженный из всех трех (например, по длине очереди).
Я тогда ссыканул так сделать, потому что сеть была еще хуже, чем сейчас, хотя это сложно себе представить, и, если бы я так сделал на 3 - 4 уровнях балансировки, это легко бы отъело 100 - 150ms времени ответа.
На днях натолкнулся на https://brooker.co.za/blog/2012/01/17/two-random.html. Там написано, что надо брать не 3 случайных хоста, а два, уже на 10 бекендах разница становится заметной.
https://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf - какие-то размышления, почему именно 2.
Век живи, век учись.
brooker.co.za
The power of two random choices - Marc's Blog
👍18🤔8❤6🔥4
https://www.opennet.ru/opennews/art.shtml?num=60736 - пишут, что в новой freebsd появились новые-кленовые строковые (семейство str*, mem*) функции, оптимизированные вручную, для ассемблера x86_64. #perf
Со ссылкой на https://freebsdfoundation.org/blog/a-sneak-peek-simd-enhanced-string-functions-for-amd64/, но там написано только про пререлиз 15.0, а про 14.0 и 13.3 не написано, собственно, я пока их код не нашел, и не смотрел.
Раньше:
* Ты мог использовать LGPL вариант из glibc, без возможности статической линковки.
* Ты мог использовать всратые заглушки от musl (TBD - написать про пару программ, которые у меня проводили 30% CPU time в memcpy от musl)
* Ты мог использовать подход Google, это когда они написали кучу вариантов memcpy, с разными размерами блоков, в надежде, что LTO/PGO выберет нужный вариант и без всякого ассемблера. https://t.iss.one/itpgchannel/1113 https://t.iss.one/itpgchannel/54 Увы, не все имеют ресурсы, чтобы собирать весь код с LTO/PGO.
* Ты мог использовать asmlib от Agner Fog, со всеми вытекающими. Например, этот сумрачный гений не умеет в систему контроля версий, и вообще, в версионирование своих артефактов. Вот url к asmlib, любой версии, не очень удобно для CI - https://www.agner.org/optimize/asmlib.zip Как хотите, так и ебитесь с этим. Ну и еще они под GPL, со всеми вытекающими.
Собственно, я использовал вариант от Agner Fog, потому что у меня все собирается из исходников, а бинарные артефакты я не распространяю.
Но, если новость - правда, то это просто какое-то счастье, потому что все пользователи musl получат нормальную (по скорости, и по лицензии) альтернативу заглушкам из musl.
Со ссылкой на https://freebsdfoundation.org/blog/a-sneak-peek-simd-enhanced-string-functions-for-amd64/, но там написано только про пререлиз 15.0, а про 14.0 и 13.3 не написано, собственно, я пока их код не нашел, и не смотрел.
Раньше:
* Ты мог использовать LGPL вариант из glibc, без возможности статической линковки.
* Ты мог использовать всратые заглушки от musl (TBD - написать про пару программ, которые у меня проводили 30% CPU time в memcpy от musl)
* Ты мог использовать подход Google, это когда они написали кучу вариантов memcpy, с разными размерами блоков, в надежде, что LTO/PGO выберет нужный вариант и без всякого ассемблера. https://t.iss.one/itpgchannel/1113 https://t.iss.one/itpgchannel/54 Увы, не все имеют ресурсы, чтобы собирать весь код с LTO/PGO.
* Ты мог использовать asmlib от Agner Fog, со всеми вытекающими. Например, этот сумрачный гений не умеет в систему контроля версий, и вообще, в версионирование своих артефактов. Вот url к asmlib, любой версии, не очень удобно для CI - https://www.agner.org/optimize/asmlib.zip Как хотите, так и ебитесь с этим. Ну и еще они под GPL, со всеми вытекающими.
Собственно, я использовал вариант от Agner Fog, потому что у меня все собирается из исходников, а бинарные артефакты я не распространяю.
Но, если новость - правда, то это просто какое-то счастье, потому что все пользователи musl получат нормальную (по скорости, и по лицензии) альтернативу заглушкам из musl.
www.opennet.ru
Релиз FreeBSD 13.3
После 11 месяцев разработки опубликован релиз FreeBSD 13.3. Установочные образы сформированы для архитектур amd64, i386, powerpc, powerpc64, powerpc64le, powerpcspe, armv6, armv7, aarch64 и riscv64. Дополнительно подготовлены сборки для систем виртуализации…
🔥12👍8❤2🤯1
commit -m "better"
У меня сегодня большой день - я перенес загрузчик на свою партицию, и загрузился с него. Старые FS и линуксы можно стирать, окончательно перерезав пуповину с материнской системой. Это оказалось сложнее, чем я думал, потому что разработчик efibootmgr сошел…
#xfs #perf
https://blog.allegro.tech/2024/03/kafka-performance-analysis.html
Вот, например, почему xfs - все еще лучшая FS под Linux.
https://blog.allegro.tech/2024/03/kafka-performance-analysis.html
Вот, например, почему xfs - все еще лучшая FS под Linux.
blog.allegro.tech
Unlocking Kafka’s Potential: Tackling Tail Latency with eBPF
At Allegro, we use Kafka as a backbone for asynchronous communication between microservices. With up to 300k messages published and 1M messages consumed every second, it is a key part of our infrastructure. A few months ago, in our main Kafka cluster, we…
👍9🔥4❤3
commit -m "better"
https://www.opennet.ru/opennews/art.shtml?num=60871 В копилочку. #fork О-че-редь. Огромная очередь. За любым популярным проектом. Стоит лишь раз ошибиться. И, в целом, это очень хорошо, потому что нехуй набирать пользователей под лозунгом "халява", а потом…
#perf #fork
Авторы форка Redis занялись его оптимизацией, и запилили неплохую статью по этому поводу.
https://valkey.io/blog/unlock-one-million-rps-part2/
Там представлена интересная техника хождения по ссылочным структурам данных, за счет параллельного хождения одновременно по нескольким структурам получилось лучше использовать кеш памяти.
Другое дело, что там надо, прежде всего, выкинуть списочные структуры, ну или выделять память для узлов в каком-нить пуле, чтобы она и так рядом ложилась.
Авторы форка Redis занялись его оптимизацией, и запилили неплохую статью по этому поводу.
https://valkey.io/blog/unlock-one-million-rps-part2/
Там представлена интересная техника хождения по ссылочным структурам данных, за счет параллельного хождения одновременно по нескольким структурам получилось лучше использовать кеш памяти.
Другое дело, что там надо, прежде всего, выкинуть списочные структуры, ну или выделять память для узлов в каком-нить пуле, чтобы она и так рядом ложилась.
valkey.io
Valkey · Unlock 1 Million RPS: Experience Triple the Speed with Valkey - part 2
Maximize the performance of your hardware with memory access amortization
👍22
#gold
> Одмен, а в чем прикол делать дистр с фулл статик линковкой? У тебя пост на канальчике про это есть какой-нить?
У меня про это много чего написано, достаточно погрепать канал по "статическая".
В целом, аргументация такая:
* динлинковка - это вынужденная мера, появившаяся, когда у компухтеров было мало памяти
* динамическая линковка - сложнее, тулинг хуже (санитайзеры требуют, чтобы почти весь код (кроме того, что перехватывается), был собран статически использовать msan с кучей .so - заградительно сложно, отладчик работает хуже, код ходит через GOT/plt, а не напрямую).
* динамическая линковка - сложнее, например, во взаимодействии с другими системами (fork(), threads, tls, etc)
* динамический загрузчик - сложный, а еще он #suid, есть известные проблемы с безопасностью
* плагины лежат хз где, и часто их не хватает, потому что приложения не могут сказать, чтобы в gstreamer был такой-то #plugins
* в целом, загружать в runtime сторонний код в свое приложение (не в песочнице) - очень странная идея, потому что CI с ним, у вас, скорее всего, не было, и как он будет ездить по вашим данным - неизвестно. Для плагинов сейчас норм решение - #WebAssembly в песочнице, или там https://github.com/libriscv/libriscv
* code bloat, больше поверхность для rop
* #ABI - это бич C/C++
* #perf - 5 - 10% CPU на дороге не валяются
* динамически слинкованные бинари дольше запускаются
В общем, я не за статлинковку, я против динамической.
Статлинковка простая, как 5 копеек, и современные окружения (go, rust) это понимают.
> Одмен, а в чем прикол делать дистр с фулл статик линковкой? У тебя пост на канальчике про это есть какой-нить?
У меня про это много чего написано, достаточно погрепать канал по "статическая".
В целом, аргументация такая:
* динлинковка - это вынужденная мера, появившаяся, когда у компухтеров было мало памяти
* динамическая линковка - сложнее, тулинг хуже (
* динамическая линковка - сложнее, например, во взаимодействии с другими системами (fork(), threads, tls, etc)
* динамический загрузчик - сложный, а еще он #suid, есть известные проблемы с безопасностью
* плагины лежат хз где, и часто их не хватает, потому что приложения не могут сказать, чтобы в gstreamer был такой-то #plugins
* в целом, загружать в runtime сторонний код в свое приложение (не в песочнице) - очень странная идея, потому что CI с ним, у вас, скорее всего, не было, и как он будет ездить по вашим данным - неизвестно. Для плагинов сейчас норм решение - #WebAssembly в песочнице, или там https://github.com/libriscv/libriscv
* code bloat, больше поверхность для rop
* #ABI - это бич C/C++
* #perf - 5 - 10% CPU на дороге не валяются
* динамически слинкованные бинари дольше запускаются
В общем, я не за статлинковку, я против динамической.
Статлинковка простая, как 5 копеек, и современные окружения (go, rust) это понимают.
GitHub
GitHub - libriscv/libriscv: The fastest RISC-V sandbox
The fastest RISC-V sandbox. Contribute to libriscv/libriscv development by creating an account on GitHub.
👍60❤6🤡6🔥4🤔3🗿2
commit -m "better"
Авторы форка Redis занялись его оптимизацией, и запилили неплохую статью по этому поводу.
https://valkey.io/blog/unlock-one-million-rps-part2/
Там представлена интересная техника хождения по ссылочным структурам данных, за счет параллельного хождения одновременно по нескольким структурам получилось лучше использовать кеш памяти.
https://valkey.io/blog/unlock-one-million-rps-part2/
Там представлена интересная техника хождения по ссылочным структурам данных, за счет параллельного хождения одновременно по нескольким структурам получилось лучше использовать кеш памяти.
https://www.opennet.ru/opennews/art.shtml?num=63335
Представлены результаты тестирования свежих выпусков СУБД Redis 8.0 и Valkey 8.1, в которых были заявлены значительные оптимизации производительности. Во всех проведённых тестах развиваемый сообществом форк обогнал оригинальный проект, в основном благодаря внедрению в Valkey нового механизма для многопоточной обработки ввода/вывода в асинхронном режиме, переданного проекту компанией Amazon.
#perf #fork
Представлены результаты тестирования свежих выпусков СУБД Redis 8.0 и Valkey 8.1, в которых были заявлены значительные оптимизации производительности. Во всех проведённых тестах развиваемый сообществом форк обогнал оригинальный проект, в основном благодаря внедрению в Valkey нового механизма для многопоточной обработки ввода/вывода в асинхронном режиме, переданного проекту компанией Amazon.
#perf #fork
www.opennet.ru
Сравнение производительности СУБД Valkey и Redis
Представлены результаты тестирования свежих выпусков СУБД Redis 8.0 и Valkey 8.1, в которых были заявлены значительные оптимизации производительности. Во всех проведённых тестах развиваемый сообществом форк обогнал оригинальный проект, в основном благодаря…
👍27🤡4🆒2
https://www.agner.org/forum/viewtopic.php?t=287&start=10
TL;DR - разбор Zen 5 на микроархитектурном уровне, от Agner Fog (https://t.iss.one/itpgchannel/1737)
Удивительно, насколько детально он умеет понимать микроархитектуру CPU только по внешним, косвенным, признакам.
TL;DR - разбор Zen 5 на микроархитектурном уровне, от Agner Fog (https://t.iss.one/itpgchannel/1737)
Удивительно, насколько детально он умеет понимать микроархитектуру CPU только по внешним, косвенным, признакам.
Telegram
commit -m "better"
https://www.opennet.ru/opennews/art.shtml?num=60736 - пишут, что в новой freebsd появились новые-кленовые строковые (семейство str*, mem*) функции, оптимизированные вручную, для ассемблера x86_64. #perf
Со ссылкой на https://freebsdfoundation.org/blog/a…
Со ссылкой на https://freebsdfoundation.org/blog/a…
🔥15❤4🆒2