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

Мне трудно понять процессорное время. Результат этой программы:

#include <iostream>
#include <chrono>

// the function f() does some time-consuming work
void f()
{
volatile long double d;
int size = 10000;
for(int n=0; n<size; ++n)
for(int m=0; m<size; ++m)
d = n*m;
}

int main()
{
std::clock_t start = std::clock();
f();
std::clock_t end = std::clock();

std::cout << "CPU time used: "<< (end - start)
<< "\n";
}

Кажется, случайно колеблется между 210 000, 220 000 и 230 000. Сначала я был поражен, почему эти дискретные значения. Потом я узнал, что std::clock() только возвращается приблизительное время процессора. Так что, вероятно, значение, возвращаемое std::clock() округляется до кратного 10 000. Это также объясняет, почему максимальная разница между временем ЦП составляет 20 000 (10 000 == ошибка округления при первом вызове std::clock() и 10 000 по второму).

Но если я перейду на int size = 40000; в теле f()Я получаю колебания в диапазоне от 3 400 000 до 3 500 000, которые нельзя объяснить округлением.

Из того, что я читал о тактовая частота, в Википедии:

Процессору требуется фиксированное количество тактов (или тактов) для
выполнить каждую инструкцию. Чем быстрее часы, тем больше инструкций
процессор может выполнять в секунду.

То есть, если программа является детерминированной (что, я надеюсь, моя), процессорное время, необходимое для завершения, должно быть:

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

Мои эксперименты не показывают ни того, ни другого, поскольку моя программа должна 3 * size * size инструкции. Не могли бы вы объяснить, что я делаю не так?

-1

Решение

Вы не указываете, на каком оборудовании вы запускаете бинарный файл.

Есть ли у него процессор, управляемый прерываниями?

Это многозадачная операционная система?

Вы путаете время цикла процессора (часы процессора, как ссылается Википедия) со временем, которое требуется для выполнения определенного фрагмента кода от начала до конца, и со всеми остальными вещами, которые бедный процессор должен делать одновременно ,

Кроме того … весь ваш исполняемый код находится в кеше 1-го уровня, или это какой-то код в уровне 2, или в основной памяти, или на диске … как насчет следующего запуска?

2

Другие решения

Во-первых, утверждение, которое вы цитируете из Википедии, просто ложно.
Это могло бы быть правдой 20 лет назад (но не всегда, даже
тогда), но сегодня это совершенно неверно. Есть много вещей
которые могут повлиять на ваши сроки:

  • Первый: если вы работаете в Windows, clock сломано,
    и совершенно ненадежно. Возвращает разницу в прошедшем
    время, а не время процессора. И прошедшее время зависит от всех видов
    другие вещи процессор может делать.

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

В общем, все, что меньше 10%, может быть легко связано с
вопросы кеширования. И я видел различия в 10 раз
под Windows, в зависимости от того, была ли запущена сборка или
не.

6

Время ЦП действительно «фиксировано» для данного набора обстоятельств. Однако на современном компьютере в системе происходят другие вещи, которые мешают выполнению вашего кода. Может случиться так, что кэши стираются, когда ваше почтовое программное обеспечение просыпается, чтобы проверить, есть ли новые электронные письма для вас, или когда программное обеспечение принтера HP проверяет наличие обновлений, или когда антивирусное программное обеспечение решает запустить для небольшой проверки, если ваша память содержит любые вирусы и т. д., и т. д., и т. д.

Частично это также вызвано проблемой, заключающейся в том, что учет времени ЦП в любой системе не является точным на 100% — он работает на «тактах» и подобных вещах, поэтому время, используемое, например, прерыванием для обслуживания сетевого пакета, поступающего в или прерывание обслуживания жесткого диска, или прерывание таймера, чтобы сказать «еще одну миллисекунду, помеченную» всеми этими учетными записями в «текущий запущенный процесс». Предполагая, что это Windows, есть еще одна «особенность», и это по историческим и другим причинам, std::clock() просто возвращает время сейчас, а не время, используемое вашим процессом. Так, например:

t = clock();
cin >> x;
t = clock() - t;

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

1

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

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

1