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

Измерение времени выполнения программы C / C ++ или ее частей иногда бывает сложнее, чем следовало бы, поскольку многие методы часто не переносятся на другие платформы. Выбор правильного метода во многом будет зависеть от вашей операционной системы, версии компилятора, а также от того, что вы подразумеваете под словом «время».

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

Время стены против времени процессора

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

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

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

Примечания к примерам кода

Приведенные ниже примеры кода основаны на программах, которые вычисляют приближение для бесконечной суммы 1 / 2⁰ + 1 / 2¹ + 1 / 2² + 1 / 2³ +… = 2. Хотя 100 итераций цикла достаточно для точного определения sum (по крайней мере, на моей машине - результаты могут отличаться на других платформах), эти программы выполняют 1 миллиард итераций, чтобы иметь значительное количество времени для измерения.

В этих программах ЦП занят почти 100% времени, поэтому разница между временем настенного компьютера и временем ЦП практически не будет. Если вы хотите, чтобы во время экспериментов CPU некоторое время простаивал, вы можете легко сделать это с помощью функции sleep() (доступна в <unistd.h>).

А теперь давайте приступим к нашему списку.

1. Использование команды Linux «время»

Работает: только на Linux. (На самом деле это можно использовать для любой программы, которую можно запустить с терминала.)
Меры: как настенное время, так и процессорное время.

Хорошо, это не совсем код C / C ++. Но, поскольку этого, вероятно, будет достаточно для многих людей, использующих Linux, я решил включить эту опцию перед более сложными. Если вы просто хотите измерить время использования ЦП и / или стены для вашей всей программы, вам действительно не нужно менять для этого свой код. Просто напишите time перед тем, что вы обычно пишете, чтобы запустить вашу программу из командной строки терминала. Затем, когда ваша программа будет завершена, измеренное время отобразится на экране. Нравится:

$ time ./MyProgram
Result: 2.00000000000000000000 
 
real 0m5.931s 
user 0m5.926s 
sys 0m0.005s

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

Примечание. Прежде чем писать это, я всегда предполагал, что в Windows есть собственная версия команды time для командной строки, поэтому я был действительно удивлен, когда узнал, что ее нет. Если интересно, вы можете найти несколько альтернатив в Интернете, но я думаю, что встраивание измерений времени непосредственно в ваш код C / C ++ должно быть более переносимым.

2. Использование ‹chrono›

Работает на: Linux и Windows, но требует C ++ 11 или новее.
Меры: время стены.

Это, вероятно, лучший и самый переносимый способ измерения времени стены в настоящее время, но он доступен только в C ++ 11 и более поздних версиях. Если ваш проект / компилятор не поддерживает C ++ 11, вам понадобится один из других вариантов, перечисленных в этой статье.

Библиотека <chrono> имеет доступ к нескольким различным часам на вашем компьютере, каждый из которых имеет разные цели и характеристики. При желании вы можете получить более подробную информацию о каждом типе часов здесь. Но, если вам действительно не нужны другие часы, я бы рекомендовал просто использовать high_resolution_clock. Здесь используются часы с самым высоким доступным разрешением, поэтому, вероятно, он подходит для большинства людей. Вот как это использовать:

Как вы можете видеть в строке 19, мы решили преобразовать измеренное время в наносекунды (хотя позже мы конвертируем его в секунды). Если вы предпочитаете, вы можете изменить код, чтобы использовать другой модуль по вашему выбору, используя chrono::hours, chrono::minutes, chrono::seconds, chrono::milliseconds или chrono::microseconds.

Примечание. Я видел, как люди упоминали, что измерение времени выполнения с помощью этой библиотеки может привести к значительным накладным расходам по сравнению с другими методами C / C ++, особенно при многократном использовании в цикле. Честно говоря, я сам не проверял и не испытывал этого, поэтому я не могу сказать об этом много. Если вы обнаружите, что это проблема для вас, возможно, вам следует рассмотреть один из других вариантов ниже.

3. С помощью ‹sys / time.h› и gettimeofday ()

Работает на: Linux и Windows.
Меры: время стены.

Функция gettimeofday() возвращает время, прошедшее с 00:00:00 UTC 1 января 1970 года (часто называемое временем эпохи). Сложность заключается в том, что функция возвращает количество секунд и микросекунд в отдельных long int переменных, так что для получения общего времени, включая микросекунды, вам необходимо соответственно суммировать оба значения. Вот как это сделать:

Примечание 1. Если вас не интересуют доли секунды, вы можете напрямую получить истекшее время, вычислив end.tv_sec - begin.tv_sec.
Примечание 2: второй аргумент of gettimeofday() используется для указания текущего часового пояса. Поскольку мы вычисляем прошедшее время, часовые пояса не имеют значения, при условии, что для begin и end используется одно и то же значение. Таким образом, мы использовали ноль для обоих вызовов.

4. С ‹time.h› и time ()

Работает на: Linux и Windows.
Измерения: время стены, но измеряет только полные секунды.

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

Примечание. time_t фактически совпадает с long int, поэтому вы можете распечатать его напрямую с помощью printf() или cout или легко преобразовать его в другой числовой тип по вашему выбору.

5. Использование ‹time.h› и clock ()

Работает в: Linux и Windows.
Измерения: время процессора в Linux и время настенной сети в Windows.

Функция clock() возвращает количество тактов часов с момента начала выполнения программы. Если вы разделите его на константу CLOCKS_PER_SEC, вы получите, как долго программа работает в секундах. Однако это будет иметь разное значение в зависимости от операционной системы: В Linux вы получите время ЦП, а в Windows - время стены. Так что вы должны быть очень осторожны при использовании этого. Вот код:

Примечание. clock_t также является long int, поэтому вам нужно преобразовать его в тип с плавающей запятой, прежде чем делить его на CLOCKS_PER_SEC, иначе вы получите целочисленное деление.

6. С ‹time.h› и clock_gettime ()

Работает: только на Linux.
Измерения: время настенной сети и процессорное время.

Самое приятное в этом то, что вы можете использовать его для измерения как времени на стене, так и времени процессора. Однако он доступен только в системах Unix. В приведенном ниже примере измеряется время стены, но вы можете изменить его для измерения времени процессора, просто заменив константу CLOCK_REALTIME на CLOCK_PROCESS_CPUTIME_ID.

Примечание 1: помимо CLOCK_REALTIME и CLOCK_PROCESS_CPUTIME_ID, есть другие часы, которые вы можете использовать с этой функцией. Вы можете проверить эту страницу для более полного списка.
Примечание 2: Структура timespec, используемая этой функцией, очень похожа на структуру, используемую gettimeofday() (метод № 3 выше). Однако он содержит наносекунды вместо микросекунд, поэтому будьте осторожны при преобразовании единиц.

7. С помощью ‹sysinfoapi.h› и GetTickCount64 ()

Работает на: только Windows.
Меры: время стены.

Функция GetTickCount64() возвращает количество миллисекунд с момента запуска системы. Также существует 32-битная версия (GetTickCount()), но она ограничена 49,71 днями, поэтому немного безопаснее использовать 64-битную. Вот как это использовать:

8. С помощью ‹processsthreadsapi.h› и GetProcessTimes ()

Работает на: только Windows.
Измерения: процессорное время.

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

Примечание. Я адаптировал этот код из Ответа на переполнение стека, поэтому я хотел бы отдать должное Александру Йи, пользователю, разместившему там ответ. Фактически, там он описывает хороший переносимый способ вычисления как настенного времени, так и процессорного времени на машинах Linux и Windows с помощью макросов #ifdef, так что вы также можете проверить полный ответ там.

Последние мысли

Что ж, вот и все: множество способов измерить время выполнения на C / C ++. Как видите, универсального решения не существует: все вышеперечисленные методы имеют ограничения, и ни один из них не может вычислить и время стены, и время процессора и доступен как для Linux, так и для Windows. Тем не менее, я ожидаю, что по крайней мере один из этих методов будет работать для вашего кода и того, к чему вы стремитесь. Спасибо за чтение.

Предлагаемая литература

Еще от того же автора



Что на самом деле означает« большая буква О
В большинстве случаев нотация большой буквы используется немного неверно. levelup.gitconnected.com»





Математика« большого О и других асимптотических обозначений
Формальные определения таких обозначений, как Большое О , Большая Омега и Большая Тета . todatascience.com »





Ресурсы

Если вам нужна дополнительная информация, ниже вы найдете более подробную документацию для каждого метода, перечисленного в этой статье:

  1. Команда Linux« Время »
  2. ‹ Хроно
  3. Gettimeofday ()
  4. "время()"
  5. "Часы()"
  6. Clock_gettime ()
  7. GetTickCount64 ()
  8. GetProcessTimes ()

Раскрытие информации: этот пост содержит одну или несколько ссылок из программы Amazon Services LLC Associates. В качестве аффилированного лица я получаю комиссионные за покупки, сделанные по этим ссылкам, без каких-либо дополнительных затрат для клиента.