странная производительность в C ++ (VC 2010) - PullRequest
5 голосов
/ 26 мая 2010

У меня есть этот цикл, написанный на C ++, для его компиляции с MSVC2010 требуется много времени. (300мс)

    for (int i=0; i<h; i++) {
    for (int j=0; j<w; j++) {
        if (buf[i*w+j] > 0) {
            const int sy = max(0, i - hr);
            const int ey = min(h, i + hr + 1);
            const int sx = max(0, j - hr);
            const int ex = min(w, j + hr + 1);
            float val = 0;
            for (int k=sy; k < ey; k++) {
                for (int m=sx; m < ex; m++) {
                    val += original[k*w + m] * ds[k - i + hr][m - j + hr];
                }
            }
            heat_map[i*w + j] = val;
        }
    }
}

Это показалось мне немного странным, поэтому я провел несколько тестов, затем изменил несколько битов на встроенную сборку: (в частности, код, который суммирует "val")

    for (int i=0; i<h; i++) {
    for (int j=0; j<w; j++) {
        if (buf[i*w+j] > 0) {
            const int sy = max(0, i - hr);
            const int ey = min(h, i + hr + 1);
            const int sx = max(0, j - hr);
            const int ex = min(w, j + hr + 1);
            __asm {
                fldz
            }
            for (int k=sy; k < ey; k++) {
                for (int m=sx; m < ex; m++) {
                    float val = original[k*w + m] * ds[k - i + hr][m - j + hr];
                    __asm {
                        fld val
                        fadd
                    }
                }
            }
            float val1;
            __asm {
                fstp val1
            }
            heat_map[i*w + j] = val1;
        }
    }
}

Теперь он работает в два раза быстрее, 150 мс. Это делает то же самое, но почему это в два раза быстрее? В обоих случаях он был запущен в режиме выпуска с включенной оптимизацией. Я делаю что-то не так в своем исходном коде C ++?

Ответы [ 2 ]

5 голосов
/ 26 мая 2010

Я предлагаю вам попробовать различные модели вычисления с плавающей точкой, поддерживаемые компилятором - precise, strict или fast (см. Параметр /fp) - с вашим исходным кодом, прежде чем делать какие-либо выводы. Я подозреваю, что ваш исходный код был скомпилирован с какой-то чрезмерно ограничительной моделью с плавающей точкой (за ней не следовала ваша сборка во второй версии кода), поэтому исходный код намного медленнее.

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

Обратите внимание, например, что в первом варианте кода промежуточная сумма накапливается в значении float. Если он был скомпилирован с моделью precise, промежуточные результаты должны были бы быть округлены с точностью до типа float, даже если переменная val была оптимизирована и вместо нее использовался внутренний регистр FPU. В вашем ассемблерном коде вы не удосуживаетесь округлять накопленный результат, что могло бы способствовать его лучшей производительности.

Я бы посоветовал вам скомпилировать обе версии кода в режиме /fp:fast и посмотреть, как их производительность сравнивается в этом случае.

3 голосов
/ 26 мая 2010

Несколько вещей, чтобы проверить:

  • Вам нужно проверить, что на самом деле это тот же код. Например, ваши встроенные операторы сборки точно такие же, как и сгенерированные компилятором? Я вижу три потенциальные различия (потенциальные, потому что они могут быть оптимизированы). Первым является начальная установка val в ноль, вторым является дополнительная переменная val1 (маловероятно, поскольку она, скорее всего, просто изменит постоянное вычитание указателя стека), третье, что версия встроенной сборки может поместите промежуточные результаты обратно в val.

  • Вы должны убедиться, что у вас достаточно места для выборки. Вы не упомянули, выполняли ли вы только один прогон каждой версии или сто прогонов, но чем больше прогонов, тем лучше, чтобы устранить эффект «шума» в вашей статистике.

  • Еще лучшим измерением будет время ЦП, а не истекшее время. Прошедшее время подвержено изменениям в окружающей среде (например, проверка на вирусы или одна из ваших служб решили принять решение во время тестирования). Большое пространство для выборки облегчит, но не обязательно решит, это.

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