Почему оператор модов бенчмаркинга (%) часто показывает 0 потраченного времени, даже для 5000 раундов? - PullRequest
1 голос
/ 16 апреля 2020

Я хочу получить представление о том, как быстро работает оператор модуля (%). Я настроил простую программу для сравнения %, применяемого к случайно сгенерированным значениям. Время измеряется в наносекундах с часами высокого разрешения. Часто это сообщает, что 0ns истек. Очевидно, что ничего не происходит мгновенно, так с чего бы это? Если я увеличу количество раундов примерно до 50 000, это обычно занимает около 1 000 000 нс. Но даже 5000 раундов - это всегда 0 нс. Я измеряю это неправильно? Какая оптимизация делается, чтобы учесть это?

#include <iostream>
#include <chrono>
#include <random>

void runTest(const int rounds, const int min, const int max);

int main()
{
    std::cout << "started" << std::endl;
    runTest(5000, 1000000, 2000000);

    return 0;
}



/*IN: number of rounds to run on the test, the min and max value to choose between for operands to mod
OUT: time taken (in nanoseconds) to complete each operation on the same randomly generated numbers*/
void runTest(const int rounds, const int min, const int max)
{
    std::random_device rd;     // only used once to initialise (seed) engine
    std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
    std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased

    std::chrono::nanoseconds durationNormalMod = std::chrono::nanoseconds::zero();
    std::chrono::nanoseconds durationFastMod = std::chrono::nanoseconds::zero();

    long long result = 0;

    for(auto i = 0; i < rounds; i++)
    {
        const int leftOperand = uni(rng);
        const int rightOperand = uni(rng);
        auto t1 = std::chrono::high_resolution_clock::now();
        long long x = (leftOperand % rightOperand);
        auto t2 = std::chrono::high_resolution_clock::now();
        //std::cout << "x: " << x << std::endl;
        result += x;
        durationNormalMod += std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1);
    }

    std::cout << "duration of %: " << durationNormalMod.count() << std::endl;
    std::cout << "result: " << result << std::endl;//preventing optimization by using result
}

Я компилирую с g++ prog.cpp -o prog.exe -O3.

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

Ответы [ 3 ]

4 голосов
/ 16 апреля 2020

При сравнительном тестировании важно:

  1. Использовать вычисленный результат каким-либо образом. Любой результат, который никогда не использовался, и вычисления, которые привели к нему, могут и будут удалены оптимизирующим компилятором.

  2. Время не одного вычисления, а ряда вычислений, таких как истекшее время между обращениями к часам составляет порядка миллисекунд. Это связано с тем, что доступ к часам является относительно дорогостоящей операцией и значительно искажает время очень быстрых вычислений.

  3. Отключите масштабирование тактовой частоты ЦП или, по крайней мере, прогрейте ЦП перед измерением времени.

2 голосов
/ 16 апреля 2020

Часы, даже часы high_resolution_clock, в большинстве реализаций не имеют достаточно тонкой детализации для измерения наносекунд.

Вы должны выполнить несколько операций подряд и разделить общее время на количество повторений. У вас уже есть al oop: переместите измерение времени за пределы l oop. И увеличьте количество повторений.

Хотя это немного сложно, поскольку l oop иногда может привести к тому, что компилятор выполнит какую-то векторную операцию вместо намеченного тривиального повторения.

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

1 голос
/ 16 апреля 2020

Оптимизация выполняется в соответствии с так называемым правилом «как будто». Компилятору разрешено выполнять любые преобразования в вашем коде, если наблюдаемые значения одинаковы. Поскольку вы не используете результат вычислений, нет наблюдаемого поведения, которое изменилось бы, если вычисления не выполняются вообще. Измеренное время не считается наблюдаемым поведением (см. здесь ).

...