В последние несколько месяцев получилось закоммить несколько интересных оптимизаций в Open Source.
а) Google Snappy: наш дефолтный компрессор данных в Google
В основном оптимизации для ARM процессоров были сделаны. А что вы думали, M1 развивается, Google Tensor вышли, пора выучить ещё один ассемблер, let's make ARM great again
1. Использование специализированных инструкций. Коммит. ARM, кто бы что ни говорил, вряд ли уже можно назвать RISC архитектурой. Полистав optimization гайды, я обнаружил очень много интересных инструкций, одна из них — csinc, это conditional increment, где
Таких инструкций нет даже у x86, которые, казалось бы, первые ввели cmov (conditional move), и мой, и компиляторный взгляды поймали упущенную возможность. В ARM есть такие же csneg, csinv и так далее.
Godbolt на поиграться
2. Я также оставил компиляторную команду думать о своём поведении. Коммит
Когда можно продублировать сразу 16 байт
3. Оставил компиляторных инженеров из ARM ещё думать над своим поведением. Баг, коммит
По каким-то причинам, llvm очень хотел после загрузки одного байта сделать ещё
В LLVM уже успели посраться на этот счёт. У компиляторных инженеров есть своя религия, обожаю смотреть за этим.
Итог: Snappy расжатие обогнает сейчас AMD процессоры последнего поколения. Но не Intel пока, но почти дотянули. Суммарно выиграли процентов 15. Потратил пару-тройку дней, зааутсорсил компиляторным инженерам работы. Получил бонус внутри за проактивность
4. Коммитил в SSE2NEON. Вы выучили SIMD x86, а не знаете ARM? Такая библиотека отлично подойдёт вам, чтобы прикинуть как будет работать код на ARM эмулированием всех широких SSE инструкций с эквивалентнами из NEON. А также является отличной библиотекой для документации как писать на SIMD в другой архитектуре.
b) Speech Recognition Engine KALDI
1. Ускорил на 13.5% CPU детекцию языка. Коммит
Это продолжение EasyPerf Challenge от Дениса. Видео с презентацией всех оптимизаций https://www.youtube.com/watch?v=jQG3QnhunZg, мой пулл реквест
Оптимизация заключается в том, что в библиотеке очень много создавалось объектов через оператор new и delete и в итоге стандартный аллокатор в glibc не справлялся с такой нагрузкой. Я заменил на memory pool, и получил огромный прирост. Так как это библиотека, использовать другой аллокатор не получится по умолчанию, я подумал, что блочная аллокация должна хорошо работать везде. Оказался прав. Я также сделал ещё несколько 0.1% оптимизаций, но они все уродливые, и пока забросил это дело сабмитить наружу. Патч получился на 50 строк, очень элегантно и просто. Я честно записал как я писал код на камеру, но получилось убого, пока не покажу.
Участвовало совсем мало людей, но я боялся, что мои оптимизации совсем плохие, так как мало идей придумал. Оказалось, что нет. Из нескольких сабмишенов только 2 что-то ускорили, второе место только ускорило на 3.5%.
а) Google Snappy: наш дефолтный компрессор данных в Google
В основном оптимизации для ARM процессоров были сделаны. А что вы думали, M1 развивается, Google Tensor вышли, пора выучить ещё один ассемблер, let's make ARM great again
1. Использование специализированных инструкций. Коммит. ARM, кто бы что ни говорил, вряд ли уже можно назвать RISC архитектурой. Полистав optimization гайды, я обнаружил очень много интересных инструкций, одна из них — csinc, это conditional increment, где
csinc a, b, c, cond
означает, что если выполнено условие cond, то возвращается b, иначе c + 1 и значение идёт в регистр a.Таких инструкций нет даже у x86, которые, казалось бы, первые ввели cmov (conditional move), и мой, и компиляторный взгляды поймали упущенную возможность. В ARM есть такие же csneg, csinv и так далее.
Godbolt на поиграться
2. Я также оставил компиляторную команду думать о своём поведении. Коммит
void TestStd(char* s) {
memset(s, s[-1], 64);
}
Превращался в TestStd(char*): // @TestStd(char*)
ldurb w8, [x0, #-1]
mov x9, #0x101010101010101
mul x8, x8, x9
dup v0.2d, x8
stp q0, q0, [x0]
stp q0, q0, [x0, #32]
ret
То есть чтобы скопировать 64 байта, компилятор решил этот байт продублировать в 8 байтный регистр через умножение, потом в 16 байтный и потом загрузить. Когда можно продублировать сразу 16 байт
sub x8, x0, #1 // =1
ld1r { v0.16b }, [x8]
stp q0, q0, [x0]
stp q0, q0, [x0, #32]
ret
Godbolt на поиграться. И компилятор пофиксили тоже.3. Оставил компиляторных инженеров из ARM ещё думать над своим поведением. Баг, коммит
По каким-то причинам, llvm очень хотел после загрузки одного байта сделать ещё
and 0xff
на этот регистр, что как бы бесполезно.В LLVM уже успели посраться на этот счёт. У компиляторных инженеров есть своя религия, обожаю смотреть за этим.
Итог: Snappy расжатие обогнает сейчас AMD процессоры последнего поколения. Но не Intel пока, но почти дотянули. Суммарно выиграли процентов 15. Потратил пару-тройку дней, зааутсорсил компиляторным инженерам работы. Получил бонус внутри за проактивность
4. Коммитил в SSE2NEON. Вы выучили SIMD x86, а не знаете ARM? Такая библиотека отлично подойдёт вам, чтобы прикинуть как будет работать код на ARM эмулированием всех широких SSE инструкций с эквивалентнами из NEON. А также является отличной библиотекой для документации как писать на SIMD в другой архитектуре.
b) Speech Recognition Engine KALDI
1. Ускорил на 13.5% CPU детекцию языка. Коммит
Это продолжение EasyPerf Challenge от Дениса. Видео с презентацией всех оптимизаций https://www.youtube.com/watch?v=jQG3QnhunZg, мой пулл реквест
Оптимизация заключается в том, что в библиотеке очень много создавалось объектов через оператор new и delete и в итоге стандартный аллокатор в glibc не справлялся с такой нагрузкой. Я заменил на memory pool, и получил огромный прирост. Так как это библиотека, использовать другой аллокатор не получится по умолчанию, я подумал, что блочная аллокация должна хорошо работать везде. Оказался прав. Я также сделал ещё несколько 0.1% оптимизаций, но они все уродливые, и пока забросил это дело сабмитить наружу. Патч получился на 50 строк, очень элегантно и просто. Я честно записал как я писал код на камеру, но получилось убого, пока не покажу.
Участвовало совсем мало людей, но я боялся, что мои оптимизации совсем плохие, так как мало идей придумал. Оказалось, что нет. Из нескольких сабмишенов только 2 что-то ускорили, второе место только ускорило на 3.5%.