пятница, 20 июля 2012 г.

Таймеры высокого разрешения Linux C/C++

В операционной системе Linux помимо обычных задержек(sleep) и таймеров, реализованы таймеры высокого разрешения. Таймер и задержки высокого разрешения позволяет измерять временные промежутки с точностью до наносекунд, а так же позволяют приложения "засыпать" на непродолжительное время(в зависимости от конфигурации системы) соизмеримое с несколькими микросекундами.



//===============================================================
// Name        : HiTimer.c
// Author      : D.Falko
// Version     : 1.0
// Description : High Resolution timer test
//===============================================================
 
 
#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <string.h>
#include <sys/mman.h>
#include <limits.h>
 
 
int main(int argc, char *argv[])
{
    if(0 == geteuid()) // приложение должно быть запущенно с правами суперпользователя
    {
        struct sched_param sp;
        memset(&sp, 0, sizeof(sp));
        sp.__sched_priority = sched_get_priority_max(SCHED_FIFO);
        sched_setscheduler(0, SCHED_FIFO, &sp);
        mlockall(MCL_CURRENT | MCL_FUTURE);
    }
    else
    {
        printf("Not running with superuser rigthsn");
        exit(1);
    }
    if(argc < 3)
    {
        printf("Using: HiTimer iterations delayn");
        exit(1);
    }
 
    int iter = atoi(argv[1]);
    int delay = atoi(argv[2]);
 
    int i=0;
    struct timespec tS, startT, stopT;
 
    clock_getres(CLOCK_MONOTONIC, &tS); // узнаем разрешение таймера
    printf("Timer res: %ld sec, %ld nsecn", tS.tv_sec, tS.tv_nsec);
 
 
    struct timespec time;
    clock_gettime(CLOCK_MONOTONIC, &startT); // засекаем время начала теста
 
    while(i<iter)
    {   // повторяем iter раз задержку delay
        i++;
        clock_gettime(CLOCK_MONOTONIC, &time); получаем актуальное время
        time.tv_nsec+=delay; // добавляем требуемую задержку
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
                        &time, NULL); // засыпаем
    }
    clock_gettime(CLOCK_MONOTONIC, &stopT);
    long int nsec=stopT.tv_sec*1000000000 + stopT.tv_nsec
                  -startT.tv_sec*1000000000 + startT.tv_nsec;

    // iter*delay должно примерно равняться nsec, узнаем погрешность задержек 
    printf("Number of iterations: %d timer value: %d nsecn",
                                                   iter, delay);
    printf("Time elapsed:  %ld nsecn", nsec);
 
 
    return 0;
}

А теперь подробней о использованных компонентах.

Используемая структура времени определена в <sys/time.h> и выглядят следующим образом:

struct timespec {
    long    tv_sec;         /* секунды */
    long    tv_nsec;        /* наносекунды */
};
 

Далее мы узнаем и выводим на экран точность(разрешение) системных часов, при помощи функции:

int clock_getres(clockid_t clk_id, struct timespec *res);
в структуру struct timespec *res записывается разрешения, указанных в clockid_t clk_id часов.

clockid_t clk_id может быть:
CLOCK_REALTIME: часы реального времени, доступные всем процессам в системе. Часы измеряются в секундах и наносекундах с начала эпохи (то есть 00:00:00 1 января 1970 по Гринвичу). Точность 1/HZ секунд. 
CLOCK_MONOTONIC: время непрерывной работы ОС, доступное всем процессам. В Линукс оно измеряются  в секундах и наносекундах после загрузки ОС. Точность 1/HZ с. Время в этих часах не может быть изменено каким-либо процессом, по этому рекомендуется использовать его.
CLOCK_PROCESS_CPUTIME_ID: часы, замеряющие время работы процесса. Время данного процесса, потраченное на выполнение в системе, измеряется в секундах и наносекундах. Точность 1/HZ. Значение часов может быть изменено.
CLOCK_THREAD_CPUTIME_ID: Как CLOCK_PROCESS_CPUTIME_ID, но для  потока.

Функция:

int clock_gettime(clockid_t clk_id, struct timespec *tp);
записывает в tp время.

Ну и последняя используемая функция:

int clock_nanosleep(clockid_t clock_id, int flags,
                    const struct timespec *request, //задержка
                    struct timespec *remain); 
const struct timespec *request - время задержки, если функция вернет (по какой-либо причине) управление раньше установленного времени, то в переменной struct timespec *remain будет записано оставшиеся время.


Так же отдельной статьи достойны строки этой программы позволяющей ей получить приоритет реального времени, и система планировщиков Linux в целом.

Комментариев нет:

Отправить комментарий