У меня есть одна странная проблема. У меня есть следующая часть кода:
template<clss index, class policy>
inline int CBase<index,policy>::func(const A& test_in, int* srcPtr ,int* dstPtr)
{
int width = test_in.width();
int height = test_in.height();
double d = 0.0; //here is the problem
for(int y = 0; y < height; y++)
{
//Pointer initializations
//multiplication involving y
//ex: int z = someBigNumber*y + someOtherBigNumber;
for(int x = 0; x < width; x++)
{
//multiplication involving x
//ex: int z = someBigNumber*x + someOtherBigNumber;
if(soemCondition)
{
// floating point calculations
}
*dstPtr++ = array[*srcPtr++];
}
}
}
Внутренний цикл выполняется почти 200 000 раз, и целая функция берет 100 мс для завершения. (представленное использование AQTimer)
Я нашел неиспользуемую переменную double d = 0.0;
вне внешнего цикла и удаленный то же. После этого изменения внезапно метод берет 500 мс для того же количества выполнения. (В 5 раз медленнее).
Это поведение восстанавливаемо в различных машинах с различными типами процессора. (Core2, dualcore процессоры).
Я использую компилятор VC6 с уровнем оптимизации O2
. Follwing являются другими используемыми параметрами компилятора:
-MD -O2 -Z7 -GR -GX -G5 -X -GF -EHa
Я подозревал оптимизацию компилятора и удалил компиляторную оптимизацию /O2
. После того, как та функция стала нормальной, и требуется 100 мс в качестве старого кода.
Кто-либо мог пролить некоторый свет на это странное поведение?
Почему компиляторная оптимизация должна замедлить производительность, когда я удаляю неиспользуемую переменную?
Примечание: Ассемблерный код (перед и после изменения) смотрел то же.
Если ассемблерный код выглядит одинаково до и после изменения, ошибка каким-то образом связана с тем, как вы рассчитываете время функции.
VC6 чертовски глючит. Известно, что в некоторых случаях он генерирует неправильный код, и его оптимизатор тоже не так уж и продвинут. Компилятору более десяти лет, и он даже не поддерживался в течение многих лет.
На самом деле, ответ таков: «вы используете компилятор с ошибками. Ожидайте ошибочного поведения, особенно когда включена оптимизация».
Я не думаю, что переходите на современный компилятор (или просто тестируете код на одном из них). ) - это вариант?
Очевидно, что сгенерированная сборка не может быть такой же, иначе не было бы разницы в производительности.
Единственный вопрос - , где разница. А с ошибочным компилятором вполне может быть какая-то совершенно несвязанная часть кода, которая внезапно компилируется по-другому и ломается. Однако, скорее всего, ассемблерный код, сгенерированный для этой функции, не тот же самый, и различия настолько незначительны, что вы их не заметили.
Объявить width
и height
как const {unsigned} int. { Следует использовать беззнаковый , поскольку высота и ширина никогда не являются отрицательными. }
const int width = test_in.width();
const int height = test_in.height();
Это помогает компилятору в оптимизации. Имея значения как const
, он может помещать их в код или в регистры, зная, что они не изменятся. Кроме того, это избавляет компилятор от необходимости угадывать, изменяются ли переменные или нет.
Предлагаю распечатать ассемблерный код версий с неиспользованным double
и без него. Это даст вам представление о мыслительном процессе компилятора.