Я пытаюсь охарактеризовать дрожание таймера в Linux. Моя задача состояла в том, чтобы запустить таймеры 100 мс и посмотреть, как работают числа.
Я работаю над многоядерной машиной. Я использовал стандартную пользовательскую программу с setitimer(), ту же работу, что и root, а затем с близостью процессора и, наконец, с близостью процессора и приоритетом процесса. Затем я запускал то же самое с ядром PREEMPT_RT, а затем запускал примеры с помощью clock_nanosleep(), как в демо-коде на странице PREEMPT_RT. Из всех прогонов производительность таймера была очень схожей, без реальной разницы, несмотря на изменения.
Наша цель - постоянный таймер. Лучшим худшим случаем, который я мог получить регулярно, было около 200us. Гистограмма для всех случаев показывает действительно странное поведение. Во-первых, я не ожидал, что таймеры будут срабатывать раньше. Но они это делают. И, как вы можете видеть на гистограмме, я получаю впадины с обеих сторон смещения 0. Они видны в трех полосах на втором графике. На первом графике ось X находится в микросекундах. На втором графике ось Y находится в микросекундах.
Я выполнил 30-секундный тест (то есть 300 событий таймера) 100 раз, чтобы сгенерировать некоторые числа. Вы можете увидеть их на следующих диаграммах. В 200us большое падение. Все 30000 тайм-часов смещаются на второй график, где вы можете увидеть некоторые выбросы.
Итак, вопрос в том, кто-нибудь еще сделал такой анализ раньше? Вы видели такое же поведение? Мое предположение заключается в том, что ядро RT помогает системам с большими нагрузками, но в нашем случае это не помогло устранить дрожание таймера. Это ваш опыт?
Вот код. Как я уже сказал, я изменил код примера на сайте PREEMPT_RT, который использует функцию clock_nanosleep(), поэтому я не буду включать в себя мои минимальные изменения для этого.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <stdlib.h>
#define US_PER_SEC 1000000
#define WAIT_TIME 100000
#define MAX_COUNTER 300
int counter = 0;
long long last_time = 0;
static long long times[MAX_COUNTER];
int i = 0;
struct sigaction sa;
void timer_handler(int signum)
{
if (counter > MAX_COUNTER)
{
sigaction(SIGALRM, &sa, NULL);
for (i = 0; i < MAX_COUNTER; i++)
{
printf("%ld\n", times[i]);
}
exit(EXIT_SUCCESS);
}
struct timeval t;
gettimeofday(&t, NULL);
long long elapsed = (t.tv_sec * US_PER_SEC + t.tv_usec);
if (last_time != 0)
{
times[counter] = elapsed - last_time;
++counter;
}
last_time = elapsed;
}
int main()
{
struct itimerval timer;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &timer_handler;
sigaction(SIGALRM, &sa, NULL);
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 1;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = WAIT_TIME;
setitimer(ITIMER_REAL, &timer, NULL);
while (1)
{
sleep(1);
}
}
EDIT: это на Xeon E31220L, работающем на частоте 2,2 ГГц, при запуске x86_64 Fedora Core 19.