7

C/C++ で発生するタスクを正確にスケジュールできる粒度を判断しようとしています。現時点では、タスクを 5 マイクロ秒ごとに確実にスケジュールできますが、これをさらに下げることができるかどうかを確認しようとしています。

これを達成する方法/可能であればアドバイスをいただければ幸いです。

タイマーの粒度は OS に依存することが多いことを知っているので、現在 Linux で実行していますが、タイミングの粒度がより良い場合は Windows を使用します (ただし、QueryPerformanceCounter で見つけたものに基づいて、そうであるとは思いません)。

ベアメタル (VM なし) ですべての測定を実行します。/proc/timer_info私のCPUのナノ秒タイマーの解像度を確認します(ただし、ナノ秒のアラーム解像度に変換されないことはわかっています)

現時点の

私の現在のコードは、Gist here として見つけることができます

現時点では、5 マイクロ秒 (5000 ナノ秒) ごとに 1% 未満の到着遅延でリクエストを実行できます。遅延到着が発生した場合、通常は 1 サイクル (5000 ナノ秒) しか遅れていません。

現在3つのことをやっています

プロセスをリアルタイムの優先度に設定します(@ Spudd86 hereによって指摘されたものもあります)

struct sched_param schedparm;
memset(&schedparm, 0, sizeof(schedparm));
schedparm.sched_priority = 99; // highest rt priority
sched_setscheduler(0, SCHED_FIFO, &schedparm);

タイマーのスラックを最小限に抑える

prctl(PR_SET_TIMERSLACK, 1);

timerfds の使用 (2.6 Linux カーネルの一部)

int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
struct itimerspec timspec;
bzero(&timspec, sizeof(timspec));
timspec.it_interval.tv_sec = 0;
timspec.it_interval.tv_nsec = nanosecondInterval;
timspec.it_value.tv_sec = 0;
timspec.it_value.tv_nsec = 1;

timerfd_settime(timerfd, 0, &timspec, 0);

可能な改善

  1. プロセッサをこのプロセス専用にしますか?
  2. ブロックするのではなく、タイトなループを作成できるように、ノンブロッキングの timerfd を使用します (タイトなループはより多くの CPU を浪費しますが、アラームへの応答も速くなる可能性があります)。
  3. トリガーに外部組み込みデバイスを使用する (なぜこれが良いのか想像できません)

どうして

現在、ベンチマーク エンジン用のワークロード ジェネレーターの作成に取り組んでいます。ワークロード ジェネレーターは、ポアソン プロセスを使用して到着率 (X リクエスト/秒など) をシミュレートします。ポアソン プロセスから、ベンチマーク エンジンから要求を行う必要がある相対的な時間を判断できます。

たとえば、1 秒あたり 10 リクエストの場合、t = 0.02、0.04、0.05、0.056、0.09 秒でリクエストが行われる可能性があります。

これらのリクエストは、事前にスケジュールしてから実行する必要があります。1 秒あたりのリクエスト数が増加するにつれて、これらのリクエストのスケジューリングに必要な粒度が増加します (1 秒あたり数千のリクエストにはミリ秒未満の精度が必要です)。その結果、私はこのシステムをさらに拡張する方法を見つけようとしています。

4

2 に答える 2

3

バニラ Linux が提供する限界に非常に近づいており、それが保証できる限界をはるかに超えています。カーネルにリアルタイム パッチを追加し、完全なプリエンプションを調整すると、負荷がかかった状態での保証が向上します。また、タイムクリティカルなコードから動的メモリ割り当てを削除します.mallocと友人は、i/ o キャッシュ。また、パフォーマンスを保証するために、そのマシンからスワップを削除することも検討します。プロセッサをタスク専用にすると、コンテキストの切り替え時間を防ぐのに役立ちますが、保証はありません。

また、そのレベルの sched_priority に注意することをお勧めします。Linux のさまざまな重要な部分を上回っているため、非常に奇妙な効果が生じる可能性があります。

于 2013-11-12T11:06:25.050 に答える
3

リアルタイム カーネルを構築することで得られるのは、カーネルによって処理される IO/タイマー イベントと、応答としてアプリに制御が渡されるまでの時間について、より信頼性の高い保証 (つまり、最大レイテンシの短縮) です。これにはスループットの低下という代償が伴い、最良の場合の待ち時間が長くなることに気付くかもしれません。

ただし、OS タイマーを使用して高精度でイベントをスケジュールする唯一の理由は、次の予定のイベントを待つ間にループで CPU サイクルを消費することを恐れている場合です。OS タイマー (特にMS Windows の場合) は、細分性の高いタイミング イベントに対して信頼性が低く、システムで利用可能なタイミング/HPET ハードウェアの種類に大きく依存します。

非常に正確なイベント スケジューリングが必要な場合は、ハイブリッド方式を使用します。まず、最悪の場合のレイテンシー、つまり、スリープを要求した時間と、スリープ後の実際のクロック時間との最大の差を測定します。この差を「D」としましょう。(実際には、通常の実行中にオンザフライでこれを行うことができます。睡眠のたびに「D」を追跡し、「D = (D*7 + lastD) / 8」のようなもので一時的な平均を生成します)。

次に、"N - D*2" ("N" は次のイベントの時間) を超えてスリープを要求しないでください。次のイベントの "D*2" 時間内に、スピン ループに入り、"N" が発生するのを待ちます。

これはより多くの CPU サイクルを消費しますが、必要な精度によっては、システムに優しいスピン ループで "sched_yield()" を実行できる場合があります。

于 2014-05-16T17:28:16.400 に答える