Подтвердить что ты не робот

Почему производительность работающей программы улучшается с течением времени?

Рассмотрим следующий код:

#include <iostream>
#include <chrono>

using Time = std::chrono::high_resolution_clock;
using us = std::chrono::microseconds;

int main()
{
    volatile int i, k;
    const int n = 1000000;

    for(k = 0; k < 200; ++k) {
            auto begin = Time::now();
            for (i = 0; i < n; ++i);  // <--
            auto end = Time::now();
            auto dur = std::chrono::duration_cast<us>(end - begin).count();
            std::cout << dur << std::endl;
    }

    return 0;
}

Я неоднократно измеряю время выполнения внутреннего цикла. Результаты показаны на следующем графике (y: duration, x: repeat):

введите описание изображения здесь

Что вызывает уменьшение времени выполнения цикла?

Среда: linux (ядро 4.2) @Intel i7-2600, скомпилированное с использованием: g++ -std=c++11 main.cpp -O0 -o main

Изменить 1

Вопрос не о оптимизации компилятора или тестах производительности. Вопрос в том, почему производительность со временем становится лучше. Я пытаюсь понять, что происходит во время выполнения.

Изменить 2

Как было предложено Vaughn Cato, я изменил политику масштабирования частоты процессора на " Производительность". Теперь я получаю следующие результаты:

введите описание изображения здесь

Это подтверждает гипотезу Вона Катона. Извините за глупый вопрос.

4b9b3361

Ответ 1

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

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

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

Ответ 2

В вашем первоначальном эксперименте слишком много переменных, чем может повлиять на измерения:

  • использование вашего процессора другими активными процессами (например, планирование вашей ОС)
  • Вопрос о том, оптимизирован ли ваш цикл или нет
  • Доступ и буферизация на консоль.
  • Начальный режим вашего процессора (см. ответ о throtling)

Я должен признать, что я очень скептически относился к вашим наблюдениям. Поэтому я написал небольшой вариант, используя предварительно выделенный вектор, чтобы избежать эффектов синхронизации ввода/вывода:

volatile int i, k;  
const int n = 1000000, kmax=200,n_avg=30;
std::vector<long> v(kmax,0); 

for(k = 0; k < kmax; ++k) {
        auto begin = Time::now();
        for (i = 0; i < n; ++i);  // <-- remain thanks to volatile
        auto end = Time::now();
        auto dur = std::chrono::duration_cast<us>(end - begin).count();
        v[k]=dur;  
}

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

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

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

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