-DNDEBUG с -Ofast медленнее, чем только -Ofast - PullRequest
0 голосов
/ 21 декабря 2018

Я нахожусь в процессе оптимизации простого генетического алгоритма и нейронной сети, и мне приходится работать с некоторыми опциями в GCC для создания более быстрых исполняемых файлов.

В моем коде у меня есть некоторые утверждения, такие как

mat mat_add(mat a, mat b)
{
    assert(a->rows == b->rows);
    assert(a->cols == b->cols);
    mat m = mat_create(a->rows, a->cols);
    for(size_t i = 0; i < a->rows; i++) {
        for(size_t j = 0; j < a->cols; j++)
            mat_set(m, i, j, mat_get(a, i, j) + mat_get(b, i, j));
    }
    return m;
}

Я полагал, что если бы я добавил -DNDEBUG, чтобы отключить утверждения, исполняемый файл был бы быстрее, потому что он не проверял бы условия выше.Тем не менее, на самом деле это медленнее.

Без -DNDEBUG:

$ gcc src/*.c -lm -pthread -Iinclude/ -Wall -Ofast
$ for i in $(seq 1 5); do time ./a.out; done

real    0m11.677s
user    1m28.786s
sys     0m0.729s

real    0m11.716s
user    1m29.304s
sys     0m0.723s

real    0m12.217s
user    1m31.707s
sys     0m0.806s

real    0m12.602s
user    1m32.863s
sys     0m0.726s

real    0m12.225s
user    1m30.915s
sys     0m0.736s

С -DNDEBUG:

$ gcc src/*.c -lm -pthread -Iinclude/ -Wall -Ofast -DNDEBUG
$ for i in $(seq 1 5); do time ./a.out; done

real    0m13.698s
user    1m42.533s
sys     0m0.792s

real    0m13.764s
user    1m43.337s
sys     0m0.709s

real    0m13.655s
user    1m42.986s
sys     0m0.739s

real    0m13.836s
user    1m43.138s
sys     0m0.719s

real    0m14.072s
user    1m43.879s
sys     0m0.712s

Это не намного медленнее, но этозаметно.

Что может быть причиной этого замедления?

1 Ответ

0 голосов
/ 21 декабря 2018

Функции mat_set и mat_get выполняют свои собственные проверки границ для индексов?При наличии подтверждений цикл доступен только в том случае, если b->rows == a->rows истинно.Это позволяет компилятору оптимизировать любую проверку i < b->rows в mat_get для b, поскольку он знает b->rows == a->rows и i < a->rows по условию цикла.

Если это в конечном итоге имеет местовы можете достичь того же самого без утверждений и без какой-либо ветви времени выполнения, добавив (особенность GNU C):

if (a->rows != b->rows || a->cols != b->cols)
    __builtin_unreachable();

Более переносимый, но менее надежный способ сделать это - просто написать какое-то бессмысленное неопределенное поведение, например1/0; в теле if.

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