Оптимизация компилятора, приводящая к снижению производительности - PullRequest
5 голосов
/ 29 апреля 2010

У меня есть одна странная проблема. У меня есть следующий кусок кода:

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, двухъядерные процессоры).

Я использую компилятор VC6 с уровнем оптимизации O2. Follwing - это другие используемые опции компилятора:

 -MD -O2 -Z7 -GR -GX -G5 -X -GF -EHa

Я заподозрил оптимизацию компилятора и удалил оптимизацию компилятора /O2. После того, как эта функция стала нормальной и она принимает старый код за 100 мс.

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

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

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

Ответы [ 3 ]

5 голосов
/ 29 апреля 2010

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

4 голосов
/ 29 апреля 2010

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

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

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

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

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

1 голос
/ 29 апреля 2010

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

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

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

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

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