Работа с таймером процессора
Результаты традиционного измерения очень маленьких интервалов времени часто оказываются неточными из-за того, что какое-то время тратиться на выполнение промежуточных фоновых операций операционной системы и функций определения системного времени. Для получения более точного результата можно определить начальное и конечное время интервала с помощью непосредственного обращения к таймеру процессора, а затем вычесть время, затрачиваемое на обработку прерывания.
Для обращения к регистрам TimeBase предусмотрены три библиотечные функции, не зависящие от архитектуры. Ниже приведено описание этих функций:
- read_real_time()
- Эта функция получает точное время из соответствующего источника и сохраняет его в виде двух 32-разрядных значений.
- read_wall_time()
- Эта функция получает значение TimeBase из соответствующего источника и сохраняет его в виде двух 32-разрядных значений.
- time_base_to_time()
- Эта функция преобразует содержимое регистра TimeBase в секунды и наносекунды.
Для определения времени и преобразования значения в обычный формат предусмотрено две разные функции, что позволяет минимизировать объем ресурсов, необходимых для получения значения времени.
#include <stdio.h>
#include <sys/time.h>
int main(void) {
timebasestruct_t start, finish;
int val = 3;
int w1, w2;
double time;
/* считывание времени перед началом операции */
read_real_time(&start, TIMEBASE_SZ);
/* начало контролируемого фрагмента кода */
printf("This is a sample line %d \n", val);
/* конец контролируемого фрагмента кода */
/* считывание времени после завершения операции
read_real_time(&finish, TIMEBASE_SZ);
/* безусловный вызов процедур преобразования, гарантирующий, что */
/* оба значения представлены в */
/* секундах и наносекундах */
/* независимо от аппаратной платформы. */
time_base_to_time(&start, TIMEBASE_SZ);
time_base_to_time(&finish, TIMEBASE_SZ);
/* Вычисление разности конечного и начального времени */
w1 = finish.tb_high - start.tb_high; /* возможно, ноль */
w2 = finish.tb_low - start.tb_low;
/* Если при измерении произошел перенос из младших разрядов в */
/* старшие, результаты могут оказаться неверными */
if (w2 < 0) {
w1--;
w2 += 1000000000;
}
/* преобразование чистого времени исполнения в число микросекунд в */
/* формате с плавающей точкой */
time = ((double) w2)/1000.0;
if (w1 > 0)
time += ((double) w1)*1000000.0;
printf("Время исполнения %9.3f мкс \n", time);
exit(0);
}Для того чтобы максимально упростить процедуру вызова функции таймера и возврата, попробуйте выполнить статическое связывание теста (дополнительная информация приведена в разделе Использование динамического и статического подключения).
Если эти тесты дают близкие к истинным показатели производительности, то измерения кода будут повторяемыми. Зная это время, можно рассчитать среднее время операции, однако это среднее время может включать затраты на обработку прерываний и другие посторонние операции. При измерении времени выполнения для каждого отдельного запуска можно проанализировать результаты и выбрать наиболее разумные, однако при этом в каждом измерении будут присутствовать отклонения, связанные с доступом к таймеру. Иногда бывает полезно объединить оба подхода и сравнить результаты. В любом случае при выборе метода измерения следует учитывать, с какой целью они проводятся.