Споры разработчиков ядра привели в конечном счете к тому, что частота программных часов стала одной из настроек ядра (Timer frequency в разделе Processor type and features). Начиная с версии ядра 2.6.13, частоте работы часов может устанавливаться значение 100, 250 (по умолчанию) или 1000 Гц, что определяет значения мгновений, равные 10, 4 и 1 миллисекунде соответственно. С версии ядра 2.6.20 стала доступна еще одна частота: 300 Гц, представленная числом, которое делится без остатка на две самые распространенные частоты видеокадров: 25 кадров в секунду (PAL) и 30 кадров в секунду (NTSC).
Временем процесса называется объем времени центрального процессора, использованный процессом с момента его создания. В целях учета ядро делит время центрального процессора на следующие два компонента.
• Пользовательское время центрального процессора, представляющее собой время, потраченное на выполнение кода в пользовательском режиме. Иногда его называют фактическим временем, и оно является временем, когда программе кажется, что она имеет доступ к ЦП.
• Системное время центрального процессора, представляющее собой время, потраченное на выполнение кода в режиме ядра. Это время, которое ядро затрачивает на выполнение системных вызовов или других задач в интересах программы (например, на обслуживание ошибок отсутствия страниц).
Иногда время процесса называют общим временем центрального процессора, потребленным процессом.
При запуске программы из оболочки для получения обоих значений времени процесса, а также реального времени, требуемого для выполнения программы, можно воспользоваться командой time(1):
$ time./myprog
real 0m4.84s
user 0m1.030s
sys 0m3.43s
Информация о времени процесса может быть извлечена системным вызовом times(), возвращающим ее в структуре, на которую указывает аргумент buf.
#include <sys/times.h>
clock_t times(struct tms *buf);
Возвращает при успешном завершении количество тиков часов (sysconf(_SC_CLK_TCK)) с некоторого момента времени в прошлом, или значение (clock_t) –1 при ошибке
Эта tms-структура, на которую указывает buf, выглядит следующим образом:
struct tms {
clock_t tms_utime; /* Пользовательское время ЦП,
использованное вызывающим процессом */
clock_t tms_stime; /* Системное время ЦП, использованное вызывающим процессом */
clock_t tms_cutime; /* Пользовательское время ЦП, прошедшее в ожидании
завершения всех дочерних процессов */
clock_t tms_cstime; /* Системное время ЦП, прошедшее в ожидании завершения
всех дочерних процессов */
};
В первых двух полях tms-структуры возвращаются пользовательские и системные компоненты времени центрального процессора, до сих пор затраченного вызывающим процессом. Последние два поля возвращают информацию о времени ЦП, затраченном всеми завершившимися дочерними процессами, для которых родительский процесс (то есть процесс, вызвавший times()) выполнил системный вызов wait().
Тип данных clock_t, применяемый для задания типов четырех полей tms-структуры, является целочисленным типом, который используется для времени, замеренного в единицах, называемых тиками часов. Чтобы привести его к секундам, надо значение типа clock_t разделить на результат (значение, которое вернула sysconf(_SC_CLK_TCK)). (Функция sysconf() рассматривается в разделе 11.2.)
В большинстве аппаратных архитектур Linux sysconf(_SC_CLK_TCK) возвращает число 100. Это соответствует константе ядра USER_HZ. Но на некоторых архитектурах, таких как Alpha и IA-64, USER_HZ может быть определена со значением, отличным от 100.
В случае успешного завершения times() возвращает затраченное (реальное) время в тиках часов, прошедшее с некоторого момента в прошлом. В SUSv3 намеренно не указывается, что собой представляет этот момент, — там просто утверждается, что он не должен поменяться в течение всего времени существования вызывающего процесса. Поэтому единственный портируемый вариант использования этого возвращаемого значения — замерить затраченное время в выполнении процесса, вычислив разницу между значениями, возвращенными парой вызовов times(). Но даже при таком использовании возвращаемое значение times() не отличается надежностью, поскольку может переполнить допустимый диапазон значений типа clock_t, и тогда значение снова начнется с нуля. Иными словами, последующий вызов times() может вернуть число, меньшее, чем ранее сделанный вызов times(). Надежный способ замерить протекание затраченного времени — использовать функцию gettimeofday() (рассмотренную в разделе 10.1).