Замер времени посредством библиотеки
Замер времени
Работает через раз. #include <conio.h> #include <iostream> #include <time.h> #include.
Замер времени вычисления
Предположим, я хочу определить время "прокрутки" цикла (или другого процесса). Я знаю два способа.
Осуществить замер времени for и while
Здравствуйте! Условие задачи: Написать программу выводящее на экран любое текстовое сообщение.
Замер времени выполнения функции на ядре
Здравствуйте! Не могу понять почему не считает время выполнения алгоритма на ядре какие бы я.
Как найти время работы программы на С++
У многих начинающих программистов рано или поздно возникает вопрос: «Как найти время работы программы?». В интернете много ответов на данный вопрос: написать свой мини-дебаггер, посчитать количество тактов и т. д. Самый простой вариант — это посчитать разницу между начальным временем и конечным. То есть, есть начальное значение времени, после которого объявлен фрагмент кода, время выполнения которого необходимо измерить. После фрагмента кода фиксируется ещё одно, конечное, значение времени. После чего, из конечного значения времени вычитаем начальное время и получим время, за которое выполнился измеряемый фрагмент кода или вся программа. Время работы программы необходимо найти для того, чтобы проверить, насколько эффективнее стал работать отдельный алгоритм или программа в целом! Как это сделать,смотрите ниже.
// Как найти время работы фрагмента кода? // заголовочный файл с прототипом функции clock() #include // . unsigned int start_time = clock(); // начальное время // здесь должен быть фрагмент кода, время выполнения которого нужно измерить unsigned int end_time = clock(); // конечное время unsigned int search_time = end_time - start_time; // искомое время
Для того, чтобы найти время работы программы, нужно воспользоваться функцией clock() . Прототип функции clock() находится в заголовочном файле , который нужно подключить, строка 4. Функция clock() возвращает значение времени в миллисекундах (1с = 1000млс). Причём отсчёт времени начинается с момента запуска программы. Если надо измерить работу всей программы, то в конце программы, перед оператором return 0; нужно запустить функцию clock() , которая покажет рабочее время. Для поиска времени работы фрагмента кода нужно найти разницу между конечным и начальным временем, как показано выше.
// Как найти время работы программы? // заголовочный файл с прототипом функции clock() #include // . // здесь должен быть код программы, время выполнения которой нужно измерить unsigned int end_time = clock(); // время работы программы
Разработаем программу, в которой с помощью функции clock() вычислим время работы программы. Программа ищет минимальное значение в массиве размером в 200000 элементов. Размер массива специально выбран большим, для того, чтобы было заметно, как работает программа. Так как числа генерируются случайно, то при каждом запуске получается новый случай, и время может не совпадать. К тому же, время выполнения программы зависит от того, насколько загружен компьютер и от того, какая у компьютера вычислительная мощность. На разных машинах по-разному будет затрачиваться время на выполнение программы, на более мощных компьютерах затрачиваемое время будет меньше и наоборот.
// runtime.cpp: определяет точку входа для консольного приложения. // Как найти время работы программы? #include "stdafx.h" #include #include using namespace std; int main(int argc, char* argv[]) < srand(time(0)); const int array_size = 200000; // размер одномерного массива int array1[array_size]; // объявление одномерного массива for (int counter = 0; counter < array_size; counter++) < array1[counter] = rand() % 50 - rand() % 50; // заполняем массив случайными значениями в диапазоне от -49 до 49 включительно cout int min = array1[0]; // переменная для хранения минимального значения for (int counter = 1; counter < array_size; counter++) < if ( min >array1[counter] ) // поиск минимального значения в одномерном массиве min = array1[counter]; > cout
// runtime.cpp: определяет точку входа для консольного приложения. // Как найти время работы программы? #include #include #include using namespace std; int main(int argc, char* argv[]) < srand(time(0)); const int array_size = 200000; // размер одномерного массива int array1[array_size]; // объявление одномерного массива for (int counter = 0; counter < array_size; counter++) < array1[counter] = rand() % 50 - rand() % 50; // заполняем массив случайными значениями в диапазоне от -49 до 49 включительно cout int min = array1[0]; // переменная для хранения минимального значения for (int counter = 1; counter < array_size; counter++) < if ( min >array1[counter] ) // поиск минимального значения в одномерном массиве min = array1[counter]; > cout
В строке 26 запускается функция clock() , которая скажет сколько потребовалось время программе. Разбирать алгоритм поиска не нужно, так как это совсем другая тема. Главное, нужно понять, как использовать функцию clock() , для поиска времени работы программы или отдельного фрагмента кода. А именно, в строке 26, после основного кода программы, но до оператора return 0; объявлена функция clock() , которая вернёт значение времени. Результат работы программы (см. Рисунок 1).
CppStudio.com
-13 4 -2 30 8 9 27 10 11 -14 -31 1 6 -16 38 31 38 -26 22 21 13 16 42 11 2 11 25 12 0 3 -7 -38 -8 -4 0 42 29 -27 -8 6 -24 12 -12 -5 27 -21 11 5 -28 33 -6 -27 19 8 -24 -4 20 -33 16 13 30 38 -3 25 -8 30 13 -19 -7 -19 12 11 -11 -14 -33 12 -5 -2 7 10 16 -14 -23 10 -10 4 -19 15 27 20 23 -5 34 12 19 -19 -13 30 -11 6 -7 -16 27 -11 -19 -9 26 -3 0 -7 41 -3 -31 10 2 -4 5 15 -37 6 -10 -10 25 -28 7 17 19 -38 15 12 -27 -48 6 36 -35 18 -17 -20 28 -13 -32 -27 7 38 16 1 25 -16 -10 5 -26 31 -15 8 22 13 6 -5 11 -31 -3 -31 10 8 -3 19 -43 8 -29 -21 -8 3 44 32 -5 9 -23 19 -6 3 6 -7 -9 23 -31 2 -19 -2 -3 -5 -5 36 12 -14 21 5 9 10 13 21 -21 12 12 14 18 -27 - 26 -6 -6 -46 7 12 -16 -24 -26 18 -1 9 2 15 -12 17 20 19 -6 0 -1 -16 11 26 -12 0 -28 12 -26 -2 23 -1 0 11 -13 -34 6 22 4 -35 37 15 -15 -26 31 25 -4 2 19 0 7 -21 26 -1 -13 37 28 -13 4 22 22 5 34 2 8 6 -15 -1 25 25 0 22 -17 3 -27 1 43 8 41 -25 12 -15 32 -14 -6 -2 24 22 -33 0 -31 32 17 -32 -22 22 -32 0 3 -24 7 2 40 -28 -39 24 -5 12 -1 -1 27 min = -49 runtime = 59.449 Для продолжения нажмите любую клавишу . . .
Рисунок 1 — Как найти время работы программы
На рисунке 1 видно, что время выполнения программы приблизительно равно 59 секунд. Даже если элементы массива неизменны, время всё равно будет немного отличаться при повторном запуске программы, так как некоторые ресурсы компьютера постоянно будут заняты, а значит, не доступны программе. Если Вы запустите эту программу у себя на компьютере, то время выполнения программы может быть совсем другим, так как наши машины не идентичны.
Передача функции и подсчет времени ее работы
необходимо создать функцию(1) для измерения скорости выполнения функции(2) и передать функции(1) функцию(2). Функция(1) должна просто выводить в консоль время работы функции(1).
Функция(1)(данный код работает и показывает некий результат для различных сортировок):
#include #include const auto start_time = std::chrono::steady_clock::now(); foo2(array, size); double result_time = std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time).count() / 1000000.0; printf("foo2 duration: %.10lf", result_time);
void foo2(int array[], int array_size)
Вопросы:
1. Как вы считаете, корректен ли подобный способ получения продолжительности работы функции?
2. Как лучше передать функции(1) функцию(2)? Имеется множество алгоритмов, и требуется вычислять скорость их работы.
Deleted
21.02.14 04:48:55 MSK
Зачем тащить всякую хрень из STL? Для этого rdtsc есть
SZT ★★★★★
( 21.02.14 05:26:15 MSK )
template std::chrono::nanoseconds measure(F const& f, Args. args) < const auto start = Clock::now(); f(args. ); const auto end = Clock::now(); return end - start; >int f(int a, float b) < return a + b; >struct F < int x; int operator()(int a, float b) const < return x + a + b; >>; std::cout ([]() < sleep(1); >).count() (f, 1, 2.).count() (F, 2, 3.).count()
high_resolution_clock / system_clock / steady_clock — на выбор, отличаются монотонностью/реальностью. Ну и такты ещё можно RDTSC-ом считать, да.
quasimoto ★★★★
( 21.02.14 05:49:15 MSK )
Ответ на: комментарий от SZT 21.02.14 05:26:15 MSK
20 лет уже как не STL, а стандартная библиотека 🙂
chrono — так вообще относительно новая вещь из неё.
Всё-таки, часы и такты это разные вещи.
quasimoto ★★★★
( 21.02.14 06:03:48 MSK )
Ответ на: комментарий от quasimoto 21.02.14 06:03:48 MSK
20 лет уже как не STL, а стандартная библиотека 🙂
Стандартная библиотека это слишком общее слово. В Pure C тоже есть стандартная библиотека libc, и на плюсах можно писать вообще без STL, используя libc или даже вообще без библиотек, дергая ядро напрямую системными вызовами, используя для этого ассемблерные вставки. Вон Qt вообще без STL нормально работают, и ничего. Впрочем, я отвлекся
chrono — так вообще относительно новая вещь из неё.
Которая к тому же есть далеко не во всех вариантах STL.
Всё-таки, часы и такты это разные вещи.
Зная число тактов и тактовую частоту процессора, несложно посчитать время
SZT ★★★★★
( 21.02.14 07:28:53 MSK )
А почему бы не воспользоваться clock_gettime() из time.h? Будет что-то вроде:
timespec after, before; clock_gettime(CLOCK_MONOTONIC, &before); func2(); clock_gettime(CLOCK_MONOTONIC, &after); printf("%l s, %l ms\n\r", after.tv_sec - before.tv_sec, after.tv_nsec - before.nsec);
// Если что, на чистых сях давно не писал
anonymous
( 21.02.14 07:48:36 MSK )
Ответ на: комментарий от quasimoto 21.02.14 05:49:15 MSK
Это, случаем, не variadic template?
Adonai ★★★
( 21.02.14 08:57:53 MSK )
Ответ на: комментарий от SZT 21.02.14 05:26:15 MSK
Верно, давайте тащить чудесный непереносимый между компиляторами ассемблер. Зачем использовать всякие неудобные высокоуровневые костыли?
staseg ★★★★★
( 21.02.14 09:54:48 MSK )
Ответ на: комментарий от SZT 21.02.14 07:28:53 MSK
Стандартная библиотека это слишком общее слово. В Pure C тоже есть стандартная библиотека libc, и на плюсах можно писать вообще без STL, используя libc или даже вообще без библиотек, дергая ядро напрямую системными вызовами, используя для этого ассемблерные вставки.
Вспоминается старый прикол, как из буханки хлеба можно смастерить троллейбус. но зачем?
staseg ★★★★★
( 21.02.14 09:59:03 MSK )
Ответ на: комментарий от SZT 21.02.14 07:28:53 MSK
std:: это вообще не STL — называется стандартная библиотека, std::chrono — тем более. STL это то что лежит на http://www.sgi.com/tech/stl/ — большинство её вообще не используют, просто она в своё время оказала влияние на _стандартную_ библиотеку плюсов (то есть то что описано в стандарте и идёт, например, с GCC) непосредственно некоторыми контейнерами и паттернами написания обобщённого кода вообще. С тех пор такое же влияние на стандарт оказывали и другие сторонние библиотеки — boost, например.
Которая к тому же есть далеко не во всех вариантах STL.
Эти штуки shipped с компиляторами — если претендуют на поддержку C++11, то они там есть (GCC, Clang).
Зная число тактов и тактовую частоту процессора, несложно посчитать время
Там есть некоторые проблемы связанные с out of order, multi-processor / multi-cores системами, сменой частоты. А часы это отдельный чип на плате со своей частотой. То есть разные вещи — так-то приготовить можно (с cpuid, повторением в цикле, калибровкой), но это имеет смысл если нужны именно такты а не время и для относительно малых их количеств.
Adonai , они — раз уж всё равно C++11.
quasimoto ★★★★
( 21.02.14 12:37:16 MSK )
Последнее исправление: quasimoto 21.02.14 12:37:29 MSK (всего исправлений: 1)
1. Как вы считаете, корректен ли подобный способ получения продолжительности работы функции?
надо код смотреть. Если нет побочных эффектов по времени — да, корректно. А может foo2 форкается и возвращается запустив сама себя ещё раз?
если у тебя PureC функции, то передай указатель на функцию.
если у тебя ООП код C++, то сделай класс для расчёта времени(а дальше от задачи зависит. Смотря что ты считаешь «временем»)
emulek ★
( 21.02.14 13:04:19 MSK )
Ответ на: комментарий от staseg 21.02.14 09:54:48 MSK
Верно, давайте тащить чудесный непереносимый между компиляторами ассемблер.
если ТС считает, что «время это число тактов моего x86», то иначе нельзя.
А как он считает на самом деле — я не знаю. В многозадачной ОС время можно определять по разному, способ с RDTSC самый простой и потому самый переносимый ИМХО.
emulek ★
( 21.02.14 13:07:53 MSK )
1. Как вы считаете, корректен ли подобный способ получения продолжительности работы функции?
в корне ошибочен.
Во первых для измерений заюзанных ресурсов (CPU в том числе) есть getrusage. Замеров времени недостаточно.
Во вторых время исполнения зависит от хреновой горы неподконтрольных параметров и чтобы получить «объективку» статистику надо (как-то и где-то) накапливать и потом уже считать. Хотя бы усреднять до min max avg
MKuznetsov ★★★★★
( 21.02.14 13:15:05 MSK )
Ответ на: комментарий от quasimoto 21.02.14 06:03:48 MSK
20 лет уже как не STL, а стандартная библиотека 🙂
И где вы нашли противоречие? STL - standard template library.
andreyu ★★★★★
( 21.02.14 13:32:03 MSK )
Ответ на: комментарий от MKuznetsov 21.02.14 13:15:05 MSK
Во первых для измерений заюзанных ресурсов
а нужны разве ресурсы, а не время?
Во вторых время исполнения зависит от хреновой горы неподконтрольных параметров
а если ТСа волнуют эти параметры, и он хочет их замерить?
emulek ★
( 21.02.14 13:34:56 MSK )
2. Как лучше передать функции(1) функцию(2)? Имеется множество алгоритмов, и требуется вычислять скорость их работы.
а недолжно быть «функции 2»: это либо класс-измеритель и шаблон-измеряемое в C++ либо макросы С и кучка функций. Чтобы как минимум сохранить возможность передачи нужных параметров в функцию 2.
и вообще для этого есть профилировщики 🙂
C/C++: как измерять процессорное время
КДПВ
От переводчика:
Большинство моих знакомых для измерения времени в разного вида бенчмарках в С++ используют chrono или, в особо запущенных случаях, ctime . Но для бенчмаркинга гораздо полезнее замерять процессорное время. Недавно я наткнулся на статью о кроссплатформенном замере процессорного времени и решил поделиться ею тут, возможно несколько увеличив качество местных бенчмарков.
P.S. Когда в статье написано "сегодня" или "сейчас", имеется ввиду "на момент выхода статьи", то есть, если я не ошибаюсь, март 2012. Ни я, ни автор не гарантируем, что это до сих пор так.
P.P.S. На момент публикации оригинал недоступен, но хранится в кэше Яндекса
Функции API, позволяющие получить процессорное время, использованное процессом, отличаются в разных операционных системах: Windows, Linux, OSX, BSD, Solaris, а также прочих UNIX-подобных ОС. Эта статья предоставляет кросс-платформенную функцию, получающую процессорное время процесса и объясняет, какие функции поддерживает каждая ОС.
Как получить процессорное время
Процессорное время увеличивается, когда процесс работает и потребляет циклы CPU. Во время операций ввода-вывода, блокировок потоков и других операций, которые приостанавливают работу процессора, процессорное время не увеличивается пока процесс снова не начнет использовать CPU.
Разные инструменты, такие как ps в POSIX, Activity Monitor в OSX и Task Manager в Windows показывают процессорное время, используемое процессами, но часто бывает полезным отслеживать его прямо из самого процесса. Это особенно полезно во время бенчмаркинга алгоритмов или маленькой части сложной программы. Несмотря на то, что все ОС предоставляют API для получения процессорного времени, в каждой из них есть свои тонкости.
Код
Функция getCPUTime( ) , представленная ниже, работает на большинстве ОС (просто скопируйте код или скачайте файл getCPUTime.c). Там, где это нужно, слинкуйтесь с librt, чтобы получить POSIX-таймеры (например, AIX, BSD, Cygwin, HP-UX, Linux и Solaris, но не OSX). В противном случае, достаточно стандартных библиотек.
Далее мы подробно обсудим все функции, тонкости и причины, по которым в коде столько #ifdef 'ов.
getCPUTime.c
/* * Author: David Robert Nadeau * Site: http://NadeauSoftware.com/ * License: Creative Commons Attribution 3.0 Unported License * http://creativecommons.org/licenses/by/3.0/deed.en_US */ #if defined(_WIN32) #include #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) #include #include #include #include #else #error "Unable to define getCPUTime( ) for an unknown OS." #endif /** * Returns the amount of CPU time used by the current process, * in seconds, or -1.0 if an error occurred. */ double getCPUTime( ) < #if defined(_WIN32) /* Windows -------------------------------------------------- */ FILETIME createTime; FILETIME exitTime; FILETIME kernelTime; FILETIME userTime; if ( GetProcessTimes( GetCurrentProcess( ), &createTime, &exitTime, &kernelTime, &userTime ) != -1 ) < SYSTEMTIME userSystemTime; if ( FileTimeToSystemTime( &userTime, &userSystemTime ) != -1 ) return (double)userSystemTime.wHour * 3600.0 + (double)userSystemTime.wMinute * 60.0 + (double)userSystemTime.wSecond + (double)userSystemTime.wMilliseconds / 1000.0; >#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */ #if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) /* Prefer high-res POSIX timers, when available. */ < clockid_t id; struct timespec ts; #if _POSIX_CPUTIME >0 /* Clock ids vary by OS. Query the id, if possible. */ if ( clock_getcpuclockid( 0, &id ) == -1 ) #endif #if defined(CLOCK_PROCESS_CPUTIME_ID) /* Use known clock id for AIX, Linux, or Solaris. */ defined(CLOCK_VIRTUAL) /* Use known clock id for BSD or HP-UX. */ if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; > #endif #if defined(RUSAGE_SELF) < struct rusage rusage; if ( getrusage( RUSAGE_SELF, &rusage ) != -1 ) return (double)rusage.ru_utime.tv_sec + (double)rusage.ru_utime.tv_usec / 1000000.0; >#endif #if defined(_SC_CLK_TCK) < const double ticks = (double)sysconf( _SC_CLK_TCK ); struct tms tms; if ( times( &tms ) != (clock_t)-1 ) return (double)tms.tms_utime / ticks; >#endif #if defined(CLOCKS_PER_SEC) < clock_t cl = clock( ); if ( cl != (clock_t)-1 ) return (double)cl / (double)CLOCKS_PER_SEC; >#endif #endif return -1; /* Failed. */ >
Использование
Чтобы замерить процессорное время алгоритма, вызовите getCPUTime( ) до и после запуска алгоритма, и выведите разницу. Не стоит предполагать, что значение, возвращенное при единичном вызове функции, несет какой-то смысл.
double startTime, endTime; startTime = getCPUTime( ); . endTime = getCPUTime( ); fprintf( stderr, "CPU time used = %lf\n", (endTime - startTime) );
Обсуждение
Каждая ОС предоставляет один или несколько способов получить процессорное время. Однако некоторые способы точнее остальных.
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, содержащую пригодное для использования значение времени.
typedef struct _SYSTEMTIME < WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; >SYSTEMTIME, *PSYSTEMTIME;
Доступность GetProcessTimes( ): Cygwin, Windows XP и более поздние версии.
Получение процессорного времени:
#include . FILETIME createTime; FILETIME exitTime; FILETIME kernelTime; FILETIME userTime; if ( GetProcessTimes( GetCurrentProcess( ), &createTime, &exitTime, &kernelTime, &userTime ) != -1 ) < SYSTEMTIME userSystemTime; if ( FileTimeToSystemTime( &userTime, &userSystemTime ) != -1 ) return (double)userSystemTime.wHour * 3600.0 + (double)userSystemTime.wMinute * 60.0 + (double)userSystemTime.wSecond + (double)userSystemTime.wMilliseconds / 1000.0; >
clock_gettme( )
На большинстве POSIX-совместимых ОС, clock_gettime( ) (смотри мануалы к AIX, BSD, HP-UX, Linux и Solaris) предоставляет самое точное значение процессорного времени. Первый аргумент функции выбирает "clock id", а второй это структура timespec , заполняемая использованным процессорным временем в секундах и наносекундах. Для большинства ОС, программа должна быть слинкована с librt.
Однако, есть несколько тонкостей, затрудняющих использование этой функции в кросс-платформенном коде:
- Функция является опциональной частью стандарта POSIX и доступна только если _POSIX_TIMERS определен в значением больше 0. На сегодняшний день, AIX, BSD, HP-UX, Linux и Solaris поддерживают эту функцию, но OSX не поддерживает.
- Структура timespec , заполняемая функцией clock_gettime( ) может хранить время в наносекундах, но точность часов отличается в разных ОС и на разных системах. Функция clock_getres( ) возвращает точность часов, если она вам нужна. Эта функция, опять-таки, является опциональной частью стандарта POSIX, доступной только если _POSIX_TIMERS больше нуля. На данный момент, AIX, BSD, HP-UX, Linux и Solaris предоставляют эту функцию, но в Solaris она не работает.
- стандарт POSIX определяет имена нескольких стандартных значений "clock id", включая CLOCK_PROCESS_CPUTIME_ID , чтобы получить процессорное время процесса. Тем не менее, сегодня BSD и HP-UX не имеют этого id, и взамен определяют собственный id CLOCK_VIRTUAL для процессорного времени. Чтобы запутать все ещё больше, Solaris определяет оба этих, но использует CLOCK_VIRTUAL для процессорного времени потока, а не процесса.
- Вместо того, чтобы использовать одну из констант, объявленных выше, функция clock_getcpuclockid( ) возвращает таймер для выбранного процесса. Использование процесса 0 позволяет получить процессорное время текущего процесса. Однако, это ещё одна опциональная часть стандарта POSIX и доступна только если _POSIX_CPUTIME больше 0. На сегодняшний день, только AIX и Linux предоставляют эту функцию, но линуксовские include-файлы не определяют _POSIX_CPUTIME и функция возвращает ненадёжные и несовместимые с POSIX результаты.
- Функция clock_gettime( ) может быть реализована с помощью регистра времени процессора. На многопроцессорных системах, у отдельных процессоров может быть несколько разное восприятие времени, из-за чего функция может возвращать неверные значения, если процесс передавался от процессора процессору. На Linux, и только на Linux, это может быть обнаружено, если clock_getcpuclockid( ) возвращает не-POSIX ошибку и устанавливает errno в ENOENT . Однако, как замечено выше, на Linux clock_getcpuclockid( ) ненадежен.
На практике из-за всех этих тонкостей, использование 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.
Получение процессорного времени:
#include #include . #if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) clockid_t id; struct timespec ts; #if _POSIX_CPUTIME > 0 /* Clock ids vary by OS. Query the id, if possible. */ if ( clock_getcpuclockid( 0, &id ) == -1 ) #endif #if defined(CLOCK_PROCESS_CPUTIME_ID) /* Use known clock id for AIX, Linux, or Solaris. */ defined(CLOCK_VIRTUAL) /* Use known clock id for BSD or HP-UX. */ if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; #endif
getrusage( )
На всех UNIX-подобных ОС, функция getrusage( ) это самый надежный способ получить процессорное время, использованное текущим процессом. Функция заполняет структуру rusage временем в секундах и микросекундах. Поле ru_utime содержит время проведенное в user mode, а поле ru_stime — в system mode от имени процесса.
Внимание: Некоторые ОС, до широкого распространения поддержки 64-бит, определяли функцию getrusage( ) , возвращающую 32-битное значение, и функцию getrusage64( ) , возвращающую 64-битное значение. Сегодня, getrusage( ) возвращает 64-битное значение, а getrusage64( ) устарело.
Доступность getrusage( ): AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris.
Получение процессорного времени:
#include #include . struct rusage rusage; if ( getrusage( RUSAGE_SELF, &rusage ) != -1 ) return (double)rusage.ru_utime.tv_sec + (double)rusage.ru_utime.tv_usec / 1000000.0;
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.
Получение процессорного времени:
#include #include . const double ticks = (double)sysconf( _SC_CLK_TCK ); struct tms tms; if ( times( &tms ) != (clock_t)-1 ) return (double)tms.tms_utime / ticks;
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 используют нестандартные значения.
Внимание: На AIX и Solaris, функция clock( ) включает процессорное время текущего процесса И и любого завершенного дочернего процесса для которого родитель выполнил одну из функций wait( ) , system( ) или pclose( ) .
Внимание: В Windows, функция clock( ) поддерживается, но возвращает не процессорное, а реальное время.
Доступность clock( ): AIX, BSD, Cygwin, HP-UX, Linux, OSX и Solaris.
Получение процессорного времени:
#include . clock_t cl = clock( ); if ( cl != (clock_t)-1 ) return (double)cl / (double)CLOCKS_PER_SEC;
Другие подходы
Существуют и другие ОС-специфичные способы получить процессорное время. На 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, а также много других вещей.
Downloads
- getCPUTime.c реализует выше описанную функцию на C. Скомпилируйте её любым компилятором C и слинкуйте с librt, на системах где она доступна. Код лицензирован под Creative Commons Attribution 3.0 Unported License.
Смотри также
Связанные статьи на NadeauSoftware.com
- C/C++ tip: How to measure elapsed real time for benchmarking объясняет как получить реальное время, чтобы измерить прошедшее время для куска кода, включая время, потраченное на I/O или пользовательский ввод.
- C/C++ tip: How to use compiler predefined macros to detect the operating system объясняет как использовать макросы #ifdef для ОС-специфичного кода. Часть из этих методов использовано в этой статье, чтобы определить Windows, OSX и варианты UNIX.
Статьи в интернете
- Процессорное время на википедии объясняет, что такое процессорное время.
- CPU Time Inquiry на GNU.org объясняет как использовать древнюю функцию clock( ).
- Determine CPU usage of current process (C++ and C#) предоставляет код и объяснения для получения процессорного времени и другой статистики на Windows.
- Posix Options на Kernel.org объясняет опциональные фичи и константы POSIX, включая _POSIX_TIMERS и _POSIX_CPUTIME.