Как измерить время работы программы c
Замерить время работы функции на С++
Мне нужно замерить время выполнения фрагмента кода (можно функции) на С++.
Я прочитал, что для этого используется clock() из модуля time.h (ctime) — она возвращает число таков, измеряемое процессором от начала выполнения программы.
Глобальная константа CLOCKS_PER_SEC хранит число тактов, выполняемое процессором в секунду. Соответственно, чтобы получить время работы программы в секундах достаточно результат работы функции разделить на эту константу:
clock() / CLOCKS_PER_SEC;
Для определения времени работы фрагмента программы нужно определить моменты времени до фрагмента и после него, а затем — посчитать разницу. Однако следующий фрагмент кода работает не так, как мне хотелось бы:
В данном случае я надеюсь получить время, которое пользователь тратит на нажатие клавиши, однако вне зависимости от того, как долго я жду — результат получается примерно одинаковый, а время очень маленьким (см. скриншот). Хотя, если вместо getchar я ставлю фрагмент кода, выполняющий какие-либо вычисления — выводится правдоподобный результат.
Подскажите в чем проблема и как ее решить.
Функция clock() возвращает количество тиков процессора, которое сделала именно ваша программа, т.е. если программа ожидает ввод данных пользователем, то она не работает (операционная система вытесняет процесс из очереди задач). Следовательно нельзя замерить время ожидания ввода при помощи функции clock() — хотя подход, который вы привели, идеально подходит если вы хотите сравнить два алгоритма, т.к. в этом случае меньшее влияние оказывает загруженность системы.
Определить количество секунд, которое выполняется программа можно с помощью функции time() :
Время при этом сохраняет с типом данных time_t — это целое число секунд, прошедшее с 1 января 1970 года. Функция difftime вычисляет разницу двух моментов времени. С помощью такого подхода вы сможете замерить время работы части программы, однако результат будет в секундах.
При помощи средств, появившихся в стандартной библиотеке С++11 можно получить более высокую точность измерения и замерить время независимо от системных часов (с помощью так называемых стабильных часов). Обзор библиотеки chrono.
Следующий фрагмент кода выполняет замер времени с использованием стабильных часов:
Функция std::chrono::duration_cast преобразует объект типа time_point во временной интервал ( duration ), при этом в качестве параметра шаблона передается промежуток времени в виде долей секунды (в данном случае миллисекунды).
Stopwatch Класс
Определение
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Предоставляет набор методов и свойств, которые можно использовать для точного измерения затраченного времени.
Примеры
В следующем примере показано, как использовать Stopwatch класс для определения времени выполнения приложения.
В следующем примере показано использование Stopwatch класса для вычисления данных о производительности.
Комментарии
StopwatchЭкземпляр может измерять затраченное время для одного интервала или общее время, затраченное на несколько интервалов. В типичном Stopwatch сценарии вызывается Start метод, затем вызывается Stop метод, а затем проверяются затраченное время с помощью Elapsed Свойства.
По умолчанию значение затраченного времени Stopwatch экземпляра равно сумме всех измеренных интервалов времени. Каждый вызов начинает подсчитаться Start на совокупное затраченное время; каждый вызов Stop завершает текущую меру интервала и замораживает совокупное значение затраченного времени. Используйте Reset метод для очистки совокупного истекшего времени в существующем Stopwatch экземпляре.
StopwatchМеры времени, затраченные на подсчет тактов таймера в базовом механизме таймера. Если установленное оборудование и операционная система поддерживают счетчик производительности с высоким разрешением, то Stopwatch класс использует этот счетчик для измерения затраченного времени. В противном случае Stopwatch класс использует системный таймер для измерения затраченного времени. Используйте Frequency поля и, IsHighResolution чтобы определить точность и разрешение Stopwatch реализации времени.
На многопроцессорном компьютере не имеет значения, на каком процессоре выполняется поток. Однако из-за ошибок в BIOS или слое абстрагирования оборудования (HAL) можно получить разные временные результаты на разных процессорах. Чтобы указать соответствие процессоров для потока, используйте ProcessThread.ProcessorAffinity метод.
Конструкторы
Инициализирует новый экземпляр класса Stopwatch.
Получает частоту таймера в виде количества тактов в секунду. Это поле доступно только для чтения.
Указывает, зависит ли таймер от счетчика производительности высокого разрешения. Это поле доступно только для чтения.
Свойства
Получает общее затраченное время, измеренное текущим экземпляром.
Получает общее затраченное время в миллисекундах, измеренное текущим экземпляром.
Получает общее затраченное время в тактах таймера, измеренное текущим экземпляром.
Получает значение, указывающее, запущен ли таймер Stopwatch.
Методы
Определяет, равен ли указанный объект текущему объекту.
Служит хэш-функцией по умолчанию.
Получает текущее число тактов временного механизма.
Возвращает объект Type для текущего экземпляра.
Создает неполную копию текущего объекта Object.
Останавливает измерение интервала времени и обнуляет затраченное время.
Останавливает измерение интервала времени, обнуляет затраченное время и начинает измерение затраченного времени.
Запускает или возобновляет измерение затраченного времени для интервала.
Инициализирует новый экземпляр Stopwatch, задает свойство затраченного времени равным нулю и запускает измерение затраченного времени.
Останавливает измерение затраченного времени для интервала.
Возвращает строку, представляющую текущий объект.
Урок №129. Измерение времени выполнения (тайминг) кода
Обновл. 24 Сен 2021 |
Иногда, в процессе написания кода, вы можете столкнуться с ситуациями, когда не будете уверены, какая из двух функций окажется более эффективной (предполагается, что конечный результат у обеих функций одинаковый). Как это определить?
Один из самых простых способов — засечь время выполнения каждого из фрагментов кода. В C++11 это делается через библиотеку chrono. Мы можем легко инкапсулировать весь необходимый нам функционал в класс, который затем будем использовать в наших собственных программах.
Для его использования нужно определить объект класса Timer в верхней части функции main() (или откуда вы хотите начинать отсчет), а затем просто вызвать метод elapsed() после части кода, которую вы проверяете:
Рассмотрим реальный пример, где нужно отсортировать массив из 10 000 элементов. Воспользуемся алгоритмом сортировки методом выбора:
Теперь проделаем то же самое, но с std::sort из Стандартной библиотеки C++:
Таким образом, алгоритм std::sort() в 75 раз быстрее, чем сортировка, которую написали мы сами!
Что влияет на тайминг кода?
Тайминг кода является достаточно простым и прозрачным, но ваши результаты могут существенно отличаться из-за ряда вещей:
Во-первых, убедитесь, что вы используете режим конфигурации «Release», а не «Debug». Во время режима «Debug» оптимизация обычно отключена, а она может оказывать значительное влияние на результаты. Например, в конфигурации «Debug», выполнение сортировки элементов массива через std::sort() на компьютере автора заняло 0.0237 секунды, что в 34 раза больше, нежели в конфигурации «Release»!
Во-вторых, на результаты тайминга влияют процессы, которые ваша система может выполнять в фоновом режиме. Для достижения наилучших результатов убедитесь, что ваша ОС не делает ничего, что интенсивно нагружает процессор, жесткий диск (например, запущен поиск файла или сканирование антивирусом) или расходует много памяти (например, вы играете в игры или работаете в фото или видео редакторе).
Выполняйте тайминг как минимум 3 раза. Если результаты одинаковые — выбираем среднее. Если один или два результата значительно отличаются друг от друга, то запустите тайминг еще несколько раз, пока не получите лучшее представление о том, какие из результатов оказались «левыми». Обратите внимание, некоторые, казалось бы, невинные вещи, такие как веб-браузеры, могут временно увеличить нагрузку на ваш процессор до 100%, когда сайт, на котором вы находитесь в фоновом режиме, выполняет целую кучу скриптов JavaScript (рекламные баннеры, запуск видео, сложная анимация и т.д.). Запуск тайминга несколько раз позволит определить, повлияло ли подобное событие на ваши результаты.
В-третьих, при сравнении двух фрагментов кода старайтесь не запускать ничего лишнего в фоновом режиме при прогонах кода, так как это также может повлиять на результаты тайминга. Возможно, ваш антивирус начал сканирование в фоновом режиме, или, может быть, вы решили послушать музыку на стриминговом сервисе (и это всё в перерывах между прогонами).
Рандомизация также может повлиять на тайминг. Если бы мы отсортировали массив, заполненный случайными числами, то это бы повлияло на результаты тайминга (тот факт, что числа являются рандомными). Рандомизацию использовать можно, но убедитесь, что ваше стартовое значение является фиксированным (т.е. не используйте системные часы в качестве стартового значения) и результаты рандомизации идентичны при каждом запуске. Кроме того, убедитесь, что в фрагментах кода не используется пользовательский ввод, так как время ожидания ввода от пользователя не должно учитываться при определении эффективности кода.
Наконец, ваши результаты действительны только для архитектуры вашего компьютера, ОС, компилятора и системных/технических характеристик. Вы можете получить совсем другие результаты на других системах, которые имеют другие сильные и слабые стороны.
C/C++: как измерять процессорное время
КДПВ
P.S. Когда в статье написано «сегодня» или «сейчас», имеется ввиду «на момент выхода статьи», то есть, если я не ошибаюсь, март 2012. Ни я, ни автор не гарантируем, что это до сих пор так.
P.P.S. На момент публикации оригинал недоступен, но хранится в кэше Яндекса
Функции API, позволяющие получить процессорное время, использованное процессом, отличаются в разных операционных системах: Windows, Linux, OSX, BSD, Solaris, а также прочих UNIX-подобных ОС. Эта статья предоставляет кросс-платформенную функцию, получающую процессорное время процесса и объясняет, какие функции поддерживает каждая ОС.
Как получить процессорное время
Процессорное время увеличивается, когда процесс работает и потребляет циклы CPU. Во время операций ввода-вывода, блокировок потоков и других операций, которые приостанавливают работу процессора, процессорное время не увеличивается пока процесс снова не начнет использовать CPU.
Разные инструменты, такие как ps в POSIX, Activity Monitor в OSX и Task Manager в Windows показывают процессорное время, используемое процессами, но часто бывает полезным отслеживать его прямо из самого процесса. Это особенно полезно во время бенчмаркинга алгоритмов или маленькой части сложной программы. Несмотря на то, что все ОС предоставляют API для получения процессорного времени, в каждой из них есть свои тонкости.
Далее мы подробно обсудим все функции, тонкости и причины, по которым в коде столько #ifdef ‘ов.
Использование
Чтобы замерить процессорное время алгоритма, вызовите getCPUTime( ) до и после запуска алгоритма, и выведите разницу. Не стоит предполагать, что значение, возвращенное при единичном вызове функции, несет какой-то смысл.
Обсуждение
Каждая ОС предоставляет один или несколько способов получить процессорное время. Однако некоторые способы точнее остальных.
OS | clock | clock_gettime | GetProcessTimes | getrusage | times |
---|---|---|---|---|---|
AIX | yes | yes | yes | yes | |
BSD | yes | yes | yes | yes | |
HP-UX | yes | yes | yes | yes | |
Linux | yes | yes | yes | yes | |
OSX | yes | yes | yes | ||
Solaris | yes | yes | yes | yes | |
Windows | yes |
Каждый из этих способов подробно освещен ниже.
GetProcessTimes( )
На Windows и Cygwin (UNIX-подобная среда и интерфейс командной строки для Windows), функция GetProcessTimes( ) заполняет структуру FILETIME процессорным временем, использованным процессом, а функция FileTimeToSystemTime( ) конвертирует структуру FILETIME в структуру SYSTEMTIME, содержащую пригодное для использования значение времени.
Доступность GetProcessTimes( ): Cygwin, Windows XP и более поздние версии.
Получение процессорного времени:
clock_gettme( )
Однако, есть несколько тонкостей, затрудняющих использование этой функции в кросс-платформенном коде:
На практике из-за всех этих тонкостей, использование clock_gettime( ) требует много проверок с помощью #ifdef и возможность переключиться на другую функцию, если она не срабатывает.
Доступность clock_gettime( ): AIX, BSD, Cygwin, HP-UX, Linux и Solaris. Но clock id на BSD и HP-UX нестандартные.
Доступность clock_getres( ): AIX, BSD, Cygwin, HP-UX и Linux, но не работает Solaris.
Доступность clock_getcpuclockid( ): AIX и Cygwin, не недостоверна на Linux.
Получение процессорного времени:
getrusage( )
На всех UNIX-подобных ОС, функция getrusage( ) это самый надежный способ получить процессорное время, использованное текущим процессом. Функция заполняет структуру rusage временем в секундах и микросекундах. Поле ru_utime содержит время проведенное в user mode, а поле ru_stime — в system mode от имени процесса.
Доступность getrusage( ): AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris.
Получение процессорного времени:
times( )
На всех UNIX-подобных ОС, устаревшая функция times( ) заполняет структуру tms с процессорным временем в тиках, а функция sysconf( ) возвращает количество тиков в секунду. Поле tms_utime содержит время, проведенное в user mode, а поле tms_stime — в system mode от имени процесса.
Внимание: Более старый аргумент функции sysconf( ) CLK_TCK устарел и может не поддерживаться в некоторых ОС. Если он доступен, функция sysconf( ) обычно не работает при его использовании. Используйте _SC_CLK_TCK вместо него.
Доступность times( ): AIX, BSD, Cygwin, HP-UX, Linux, OSX и Solaris.
Получение процессорного времени:
clock( )
На всех UNIX-подобных ОС, очень старая функция clock( ) возвращает процессорное время процесса в тиках, а макрос CLOCKS_PER_SEC количество тиков в секунду.
Заметка: Возвращенное процессорное время включает в себя время проведенное в user mode И в system mode от имени процесса.
Внимание: Хотя изначально CLOCKS_PER_SEC должен был возвращать значение, зависящее от процессора, стандарты C ISO C89 и C99, Single UNIX Specification и стандарт POSIX требуют, чтобы CLOCKS_PER_SEC имел фиксированное значение 1,000,000, что ограничивает точность функции микросекундами. Большинство ОС соответствует этим стандартам, но FreeBSD, Cygwin и старые версии OSX используют нестандартные значения.
Внимание: В Windows, функция clock( ) поддерживается, но возвращает не процессорное, а реальное время.
Доступность clock( ): AIX, BSD, Cygwin, HP-UX, Linux, OSX и Solaris.
Получение процессорного времени:
Другие подходы
Существуют и другие ОС-специфичные способы получить процессорное время. На Linux, Solarisи некоторых BSD, можно парсить /proc/[pid]/stat, чтобы получить статистику процесса. На OSX, приватная функция API proc_pidtaskinfo( ) в libproc возвращает информацию о процессе. Также существуют открытые библиотеки, такие как libproc, procps и Sigar.
На UNIX существует несколько утилит позволяющих отобразить процессорное время процесса, включая ps, top, mpstat и другие. Можно также использовать утилиту time, чтобы отобразить время, потраченное на команду.
На Windows, можно использовать диспетчер задач, чтобы мониторить использование CPU.
На OSX, можно использовать Activity Monitor, чтобы мониторить использование CPU. Утилита для профайлинга Instruments поставляемая в комплекте с Xcode может мониторить использование CPU, а также много других вещей.
Как измерить время выполнения операции в C#
При разработке различных программ иногда бывает необходимо измерить точное время какой-либо операции, например, узнать сколько времени требуется на загрузку данных из файла, запись в базу данных и так далее. Сегодня мы рассмотрим то, как измерить время выполнения операции в C#, используя стандартные средства и возможности языка.
System. Diagnostics
Простой пример использования Stopwatch
Для начала, рассмотрим простой пример использования класса Stopwatch для измерения затраченного времени на выполнение операции.
Чтобы измерить время выполнения операции в C# нам необходимо выполнить несколько простых шагов:
Stopwatch
Свойства Stopwatch
Elapsed
Свойство возвращает объект типа TimeSpan — интервал времени, используя который, можно получить время выполнения операции в удобном для вас виде. Например,
ElapsedMilliseconds
Свойство ElapsedMilliseconds позволяет получить общее затраченное время, измеренное текущим экземпляром класса Stopwatch в миллисекундах. В примере использования класса Stopwatch выше продемонстрировано использование этого свойства.
Elapsed Ticks
Результатом выполнения этого кода может быть вот такой вывод консоли:
Is Running
Поля Stopwatch
Класс Stopwatch содержит два статических поля, позволяющих получить сведения о настройках таймера.
Frequency
Поле Frequency содержит частоту таймера в виде количества тактов в секунду.
Это поле удобно использовать вместе со свойством Elapsed Ticks для преобразования количества тактов в секунды. Например,
Is High Resolution
Свойство Is High Resolution указывает, зависит ли таймер Stopwatch от счетчика производительности высокого разрешения ( true ) или же использует класс DateTime ( false ).
Пример использования поля
Вывод консоли будет иметь следующий вид:
Частота таймера = 10000000
Таймер работает с точностью до 100 наносекунд
Методы Stopwatch
Start и Stop
Start New
Reset
Метод Reset() останавливает измерение интервала времени и обнуляет счётчик затраченного времени. Использование Reset() позволяет избежать создания новых экземпляров Stopwatch для измерения времени, затраченного на выполнение нескольких операций в C#.
Restart
Метод Restart() останавливает измерение интервала времени, обнуляет затраченное время и повторно запускает таймер. Таким образом, предыдущий пример можно переписать следующим образом: