Linux でタイマーのジッターを特徴付けようとしています。私のタスクは、100 ミリ秒のタイマーを実行し、数値がどのように機能するかを確認することでした。
マルチコアマシンで作業しています。標準のユーザー プログラムを setitimer() で使用し、root と同じように実行し、次にプロセッサ アフィニティを使用し、最後にプロセッサ アフィニティとプロセス優先度を使用しました。次に、PREEMPT_RT カーネルで同じことを実行し、PREEMPT_RT ページのデモ コードのように clock_nanosleep() を使用してサンプルを実行しました。すべての実行の中で、タイマーのパフォーマンスは非常に類似しており、変更にもかかわらず実質的な違いはありませんでした。
私たちの最終目標は安定したタイマーです。私が定期的に得ることができる最高の最悪のケースは約200usでした. すべてのケースのヒストグラムは、非常に奇妙な動作を示しています。1 つには、タイマーが早く起動するとは思わないでしょう。しかし、彼らはそうします。ヒストグラムでわかるように、オフセット 0 の両側に谷があります。これらは、2 番目のグラフの 3 つのバンドに表示されます。最初のグラフでは、X 軸はマイクロ秒単位です。2 番目のグラフでは、Y 軸はマイクロ秒単位です。
30 秒のテスト (つまり、300 個のタイマー イベント) を 100 回実行して、いくつかの数値を生成しました。次の図でそれらを確認できます。200us で大きな低下があります。2 番目のグラフには、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);
}
}
編集: これは Xeon E31220L で、2.2 GHz で実行され、x86_64 Fedora Core 19 が実行されています。