2013-05-02 3 views
-1

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

#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() возвращает только approximate processor time. Поэтому, вероятно, значение, возвращаемое std::clock(), округляется до кратного 10 000. Это также объясняет, почему максимальная разница между временами ЦП составляет 20 000 (10 000 = ошибка округления по первому вызову std::clock() и 10 000 вторым).

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

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

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

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

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

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

+2

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

+0

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

+0

У вас есть упрощенные ожидания относительно того, как (а) компьютеры и (б) работают операционные системы, работающие во времени. –

ответ

2

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

Имеет ли процессор с прерыванием?

Является ли это многозадачной операционной системой?

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

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

+1

В теории 'clock()' измеряет время процессора, приписываемое процессу, поэтому проблема должна быть только в кеше. (На практике 'clock()' нарушается в библиотеках Microsoft и является настолько ненадежным, чтобы быть совершенно бесполезным.) –

6

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

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

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

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

+0

+1 ... а также в многопроцессорных операционных системах нет гарантии на выполнение 'f() 'прямо после предыдущей строки' std :: clock_t start = std :: clock(); '. – deepmax

+0

@MM. Это не имеет значения, поскольку любое промежуточное время не будет временем процессора, связанным с вашим процессом. (Но это будет иметь значение, если ваша реализация 'clock()' нарушена.) –

+0

Спасибо за этот ответ, вы знаете хорошую альтернативу для измерения времени, потому что, как вы сказали, часы действительно нарушены на практике –

1

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

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

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

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

+0

Процитировать стандарт C: «Функция часов возвращает наилучшее приближение реализации к _processor_ времени, используемого программой [...]» (выделено мной). Единственное слово, которое правильно описывает реализацию Windows, «сломан». –

+1

Да, это, вероятно, сохранилось так, что во времена DOS и, возможно, ранних версий Windows, код был написан с использованием 'clock()' для выполнения других задач, связанных с хронометром, и, таким образом, когда код переносится на более позднюю версию, мы можем 't разрешить код сломаться ... " –

1

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

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

Смежные вопросы