2010-04-29 3 views
5

У меня есть одна странная проблема. У меня следующий фрагмент кода:Оптимизация компилятора, замедляющая производительность

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 мс в качестве старого кода.

Может ли кто-нибудь пролить свет на это странное поведение?

Почему оптимизация компилятора должна замедлять работу при удалении неиспользуемой переменной?

Примечание: код сборки (до и после изменения) выглядел так же.

+1

Вы уверены, что сборка выглядела одинаково? Разве это «выглядело одинаково» или это точно так же? – jalf

+0

его точно так же. –

ответ

5

Если код сборки выглядит одинаково до и после изменения, ошибка каким-то образом связана с тем, как вы выполняете функцию.

1

Объявление width и height as const {unsigned} ints. {unsigned следует использовать, так как высоты и ширины никогда не являются отрицательными.}

const int width = test_in.width(); 
const int height = test_in.height(); 

Это помогает компилятору с оптимизацией. Со значениями const он может поместить их в код или в регистры, зная, что они не изменятся. Кроме того, он освобождает компилятор от необходимости угадывать, изменяются ли переменные или нет.

Предлагаю распечатать код сборки версий с неиспользованным double и без него. Это даст вам представление о процессе мышления компилятора.

4

VC6 багги как ад. Известно, что в некоторых случаях генерируется некорректный код, и его оптимизатор не все продвинутый. Компилятор старше десяти лет и даже не поддерживается в течение многих лет.

Так что, на самом деле, ответ: «вы используете компилятор с ошибкой. Ожидайте ошибочного поведения, особенно когда оптимизация включена».

Я не предполагаю, что обновление до современного компилятора (или просто тестирование кода на одном) является вариантом?

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

Единственный вопрос: где разница лежит. И с помощью компилятора с ошибкой вполне может быть какая-то совершенно несвязанная часть кода, которая вдруг компилируется по-разному и ломается. Скорее всего, код сборки, сгенерированный для этой функции, - , а не, и различия настолько тонкие, что вы их не заметили.

+0

Пойдем, чтобы принять дикое предположение и сказать, что двойник заставлял более поздние подпрограммы с плавающей точкой выравниваться по стеклу с 8 байтами, что может заметно повысить производительность при использовании парных. –

+0

да, это возможно. Проблемы с выравниванием, вероятно, объяснят замедление этой величины – jalf

+0

, к сожалению, ее огромный проект наследия. Множество усилий, связанных с переносом на последний VC :( –

Смежные вопросы