Pull to refresh

Оптимизируем код, или перегоним Огнелиса в скорости

Reading time2 min
Views735
Почитал топик об новых супероптимизациях в Огнелисе и долго думал.
Для меня не очень понятно, почему вокруг такого рода работы устроен праздник с феерверком и снегурочкой. Давайте подробнее рассмотрим что же было сделано.

* Function Inlining: Removing the overhead of function calls by simply replacing them with their resulting native code.
Инлайнинг функций умеют делать практически все компиляторы. Это очень простой и можно сказать бесплатный способ ускорения программы. У него есть определенные ограничения:
1) Избыточный инланинг ведет к раздуванию кода. Это сейчас практически не проблема — памяти ощутимо много, но компилятор имеет ограничение сверху на размер включаемой ф-ции.
2) Компилятор НЕ умеет инлайнить функции из соседнего модуля, из системных библиотек, а так из динамических библиотек.

Кроме того нормальный (современный) компилятор умеет работать с так называемыми «интринсиками» — функциями, которые он распознает по табличке и имеет готовый код для них. Это обычно математические функции, такие как sin(). Так вот, этот самый синус будет сделан не как call sin(), а будет вставлен куском кода, т.е. автоматически заинлайнен.

* Type Inference: Removing checks surrounding common operators (like «+») when the types contained within a variable are already known. This means that the engine will have already pre-determined, for example, that two strings need to be concated when it sees the «+» operator.

Ну эт обычно называется RTTI skip — выбросили проверку типов там где она не нужна… Возможно для JIT компилятора это и суперкруто, однако обычные умеют делать такое уже давно. Естественно вся ответственность за типы, а точнее их возможное несоответствие ложится на программиста :)

* Looping: The overhead of looping has been grossly diminished. It's one of the most common areas of overhead in JavaScript applications (common repetition of a task) and the constant determining of bounds and the resulting inner code is made negligible.
9 из 10 что был сделан простой анролл цикла. Unrolling представляет собой дублирование тела цикла N раз:
for (int i=0; i<maxI; i++){
a[i] = b[i]+c[i];
}


если unroll на 4 то получаем:
for (int i=0; i<maxI; i+=4){
a[i] = b[i]+c[i];
a[i+1] = b[i+1]+c[i+1];
a[i+2] = b[i+2]+c[i+2];
a[i+3] = b[i+3]+c[i+3];
}

Ну и плюс доппроверку, что maxI кратно 4 :)

Теперь берем нашу программу, Intel C Compiler (или Intel Fortran Compiler — кому что нравится) и собираем проект со следующими ключами:
-O3 (да, агрессивная оптимизация);
-axT (включаем векторизацию, т.е использование SSEx + генерация общего кода для тяжелых случаев);
-ip (межпроцедурная оптимизация, включая частичный инлайнинг. для фанатов есть опция -ipo — межмодульная оптимизация, не портабельно!!!);
-ansi-alias -fno-alias (улучшает векторизируемость :) циклов)

Плюс ко всему этому получаем: автоматический анролл циклов как минимум на 4, инлайнинг и интринсики всех математических функций.
И огнелис не догонит ;)
Да, и в общем случае есть разница между обычным и JIT компилятором, но она не настолько велика, чтобы выдавать давно известные фичи за открытия (типа: «О! Мы придумали инлайнинг!»)

PS. Первый блин, просьба комом не бить по лицу.
Tags:
Hubs:
Total votes 23: ↑13 and ↓10+3
Comments13

Articles