странная производительность в C++ (VC 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 мс. Это делает точно то же самое, но почему это вдвое более быстро? В обоих случаях это было выполнено в режиме Release с оптимизацией на. Я делаю что-то не так в своем исходном коде C++?

5
задан raicuandi 26 May 2010 в 02:15
поделиться

2 ответа

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

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

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

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

5
ответ дан 14 December 2019 в 04:31
поделиться

Несколько вещей, которые нужно проверить:

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

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

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

3
ответ дан 14 December 2019 в 04:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: