#cpp
Возникла следующая проблема: имеется вот такой участок кода start = clock(); LLTWithBlock(n, 4, a); end = clock(); duration = (double)(end - start); std::cout << "Alltime: " << duration << std::endl; Время выполнения 8 секунд. После чего заменяю константу "4" на переменную "r" (тоже равную 4, считывается из файла) LLTWithBlock(n, r, a); И новое время выполнения становится 22 секунды. Я отдаленно понимаю, что в ассемблерном коде будут создаваться разные экземпляры функции, но откуда такая разница во времени выполнения? P.S. Время замерялось не один раз, данная ситуация повторяется при каждом запуске программы. upd: меняется конкретно время выполнения следующей функции (вызываемой внутри) void A_LLT(unsigned n, unsigned r, unsigned numBlock, double *b, double *bb, double *a){ unsigned adr; unsigned cnt = r*(numBlock + 1);//номер 1 строки в текущем блоке(прямоугольном) в большой матрице unsigned nb = (n - cnt) / r, end;//n/r число целых блоков размера р в матрице. //Отнимаем 1(мы его раскладываем) и нумблок(число уже разложенных блоков) for (unsigned ib = 0; ib < nb; ib++)//ход по квадратным блокам { end = ib * r + r; for (unsigned i = ib * r; i < end; i++)//по строкам в блоке { adr = (cnt + i) * (cnt + i + 1) / 2 + cnt; for (unsigned j = 0; j <= i; j++, adr++)//по строкам { for (unsigned k = 0; k < r; k += 4) { a[adr] -= b[i*r + k] * b[j*r + k]; a[adr] -= b[i*r + k + 1] * b[j*r + k + 1]; a[adr] -= b[i*r + k + 2] * b[j*r + k + 2]; a[adr] -= b[i*r + k + 3] * b[j*r + k + 3]; } } } } for (unsigned i = nb * r, end = i + n % r; i < end; i++)//по строкам в блоке n - r - numBlock * r { adr = (cnt + i) * (cnt + i + 1) / 2 + cnt; for (unsigned j = 0; j <= i; j++, adr++)//по строкам { for (unsigned k = 0; k < r; k += 4) { a[adr] -= b[i*r + k] * b[j*r + k]; a[adr] -= b[i*r + k + 1] * b[j*r + k + 1]; a[adr] -= b[i*r + k + 2] * b[j*r + k + 2]; a[adr] -= b[i*r + k + 3] * b[j*r + k + 3]; } } }}
Ответы
Ответ 1
Код просмотрен в дизассемблере, совершенно разный. Очень сильная оптимизация кода и очень активное использование SSE. На моей машине разница получилась примерно той же - в 3 раза.Ответ 2
Код конечно есть, но нет явной заготовки для бенчмарка, пришлось ручками "угадывать". Но даже беглый анализ кода показывает явные оптимизации, которые может сделать компилятор. Например, в коде много вызовов вида b[i*r + k]. Если значение всех переменных компилятору неизвестны, он вынужден вычислять одно умножение, потом сложение, потом ещё одно умножение и сложение(вычисленный индекс умножается на размер элемента и складывается с начальным адресом массива). А это не такая уж и тривиальная задача. Если же компилятор может доказать, что r = 4, то он может это все заменить одной инструкцией lea ( и просмотр исходного кода показывает, что похоже это так и происходит). Дальше посмотрим на некоторые участки кода, которые это все может затронуть. // внутри Dot int m = n % 4; for (unsigned i = 0; i < m; i++) sum += a[i] * b[i]; for (unsigned i = m; iОтвет 3
Соберите программу с выводом ассемблерного листинга (для gcc это флаг -s), и сравните код между вызовами clock() Если компилятор все время выдает одинаковый код, как с переменной, так и с константой - проблемы где-то в условиях эксперимента, так как чудес не бывает. Если же код разный, а производительность важна - у вас два варианта добиваться нужной скорости, изменяя параметры компиляции написать огромное количество if на все возможные значения переменной, которые будут вызывать код с константой.
Комментариев нет:
Отправить комментарий