Низкая производительность оператора std :: complex * на некоторых компиляторах - PullRequest
1 голос
/ 21 июня 2020

Производительность моего внутреннего l oop страдает из-за тестов NaN в операторе std :: complex *. Я знаю это, потому что если я заменю оператор * моей собственной функцией ручного умножения, которая не включает тесты NaN, мой код будет работать в два раза быстрее (!) На реальных рабочих нагрузках. Я счастлив, что в обрабатываемых мной данных не будет NaN, поэтому меня не волнует это соответствие pedanti c IEEE, и я хотел бы устранить его для увеличения скорости.

В чем я не уверен about - лучший способ устранить этот код проверки NaN. Я думал, что -ffinite-math-only поможет, но (рассматривая разборку), похоже, это не имеет никакого эффекта. Действительно, использование из отчаяния всех "-Ofast -ffast-math -funsafe-math-optimizations -ffinite-math-only" не имеет никакого эффекта. Есть ли какой-нибудь вариант компилятора, который я мог бы использовать, чтобы исключить нежелательные тесты NaN?

К сожалению, я на 99% уверен, что мой код использовал для компиляции в «быструю» версию, что приводит меня подумать, что такой вариант действительно существует. Используя ручное умножение, я точно воспроизводю точные эталонные измерения, которые я сделал за несколько дней с go. Однако я не могу точно узнать, что изменилось в процессе компиляции, потому что это расширение python, и я заметил падение производительности при обновлении с anaconda python 3.5 до 3.7. Я могу только представить, что параметры компилятора (или что-то еще), используемые за кулисами, изменились, но go не так просто вернуться и проверить (мне пришлось бы понизить версию всей моей установки и надеяться, что я смогу воспроизвести старая производительность).

Я наивно пробовал создать подкласс std :: complex и переопределить оператор * так, как я хочу. Этот работает , но я обнаружил, что мне нужно перегрузить несколько других функций, например, con (), чтобы избежать случайного возврата к базовому типу std :: complex. Это похоже на неуклюжий обходной путь, а не на «правильный» способ сделать это.

Может ли кто-нибудь предложить хороший способ добиться того, чего я хочу (заставляя компилятор исключить проверки NaN в операторе std :: complex * , чтобы получить прирост производительности)?

Изменить: 'codegorilla' запросил воспроизводимый пример. Следующий простой код демонстрирует проблему , но см. Примечание ниже о том, как моя проблема, похоже, зависит от компилятора c.

#include <complex>
int main(void)
{
    std::complex<float> a(rand(), rand()); // input that cannot be optimized away
    std::complex<float> b(rand(), rand());
    std::complex<float> c = a * b;
    printf("%lf\n", c.real()); // output that cannot be optimized away
    return 0;
}

Дизассемблировать с помощью

gcc -Ofast -S test.cpp -o test.s; open test.s

Я работал над OS X, где gcc -v сообщает Apple LLVM version 8.1.0 (clang-802.0.42). Однако теперь я вижу, что это, похоже, проблема c, специфичная для компилятора - все компилируется, как я ожидал, на gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) вещи компилируются так, как я ожидал (оптимизированный код, сгенерированный с -Ofast, но не -O3)

С моим компилятором можно увидеть вызов __ZNSt3__1mlIfEENS_7complexIT_EERKS3_S5_ (и я подозреваю, что большая часть общей проблемы производительности заключается в том, что это не встроено как компактная операция). Проверка дизассемблирования для этой функции подтверждает, что, согласно источнику для std :: complex, большая часть функции выполняет проверки и исправления для крайних случаев, связанных с NaN. Это то, что я надеюсь, что смогу устранить (что затем сделает возможным встраивание функций и последующую оптимизацию и, в конечном итоге, измеренное удвоение скорости кода).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...