web-dev-qa-db-ja.com

Linux推奨の方法で1msの解像度タイマー

Linuxで1msの解像度のタイマーティックが必要です。これは、タイマー値をインクリメントするために使用され、タイマー値は、さまざまなイベントをトリガーする必要があるかどうかを確認するために使用されます。 posIX timerfd_createは、glibc要件のため、オプションではありません。 timer_createとtimer_settimerを試しましたが、それらから得られる最良の解像度は10msの解像度であり、小さい値はデフォルトで10msの解像度になっているようです。 Getittimerとsetitimerの解像度は、マンページによると10ミリ秒です。

私が現在考えているこのタイマーを実行する唯一の方法は、メインループでCLOCK_MONOTONICを指定してclock_gettimeを使用し、msが経過したかどうかをテストし、合格した場合はカウンターを増やすことです(その後、さまざまなイベントが発生するかどうかを確認します)。

メインループで常にクエリを実行するよりも、これを行うためのより良い方法はありますか?これに対する推奨される解決策は何ですか?

私が使用している言語は昔ながらのcです

更新
2.6.26カーネルを使用しています。 1kHzで割り込みをかけることができ、POSIX timer_ *関数を最大1msにプログラムできることはわかっていますが、それは信頼できないようで、一部の新しいカーネルが必要になる可能性があるため、使用したくありません。システム。一部のストックカーネルには、まだ100Hzが構成されているようです。そして、私はそれを検出する必要があります。アプリケーションは私のシステム以外で実行されている可能性があります:)

反応しなければならないネットワークイベントがあるかもしれないので、私は1msの間眠ることができません。

どのように解決したかそれほど重要ではないので、グローバルタイマーの解像度は100msであると宣言しただけです。独自のタイマーを使用するすべてのイベントは、タイマーの有効期限として少なくとも100ミリ秒を設定する必要があります。私は多かれ少なかれもっと良い方法があるのだろうかと思っていたので、質問です。

私が答えを受け入れた理由フリースペースからの答えは、リアルタイムLinuxシステムなしでは実際には不可能である理由を最もよく説明していると思います。

18
Edger

メインループでのポーリングも答えではありません。プロセスのCPU時間があまりかからない可能性があるため、コードが実行されるまでに10ミリ秒以上が経過し、コードが無効になります。

10msは、ほとんどの非- リアルタイムオペレーティングシステム (RTOS)の標準タイマー解像度です。ただし、RTOS以外では意味がありません。スケジューラとディスパッチャの動作は、タイマーの期限切れにどれだけ迅速に応答できるかに大きく影響します。たとえば、10ミリ秒未満の解像度のタイマーがあったとしても、コードが実行されていないと、タイマーの期限切れに応答できません。コードがいつ実行されるかを予測できないため、タイマーの有効期限に正確に応答することはできません。

もちろん、リアルタイムのLinuxカーネルもあります。リストについては http://www.linuxdevices.com/articles/AT8073314981.html を参照してください。 A RTOSは、コードがいつ実行されるかについてソフトまたはハードの保証を取得できる機能を提供します。これは、タイマーの期限切れなどに確実かつ正確に応答する唯一の方法です。

15
freespace

1msの解像度タイマーを取得するには、 libevent が行うことを実行します。

タイマーを min-heap に編成します。つまり、ヒープの最上位は、最も早い有効期限(絶対)時間のタイマーです(rbツリーも機能しますが、オーバーヘッドが大きくなります)。メインイベントループでselect()またはepoll()を呼び出す前に、最も早いタイマーの有効期限から現在までのデルタをミリ秒単位で計算します。このデルタをselect()へのタイムアウトとして使用します。 select()およびepoll()タイムアウトの解像度は1ミリ秒です。

上で説明したメカニズムを使用するタイマー解決テストがあります(libeventは使用しません)。このテストでは、希望するタイマーの有効期限と、実際の1ミリ秒、5ミリ秒、および10ミリ秒のタイマーの有効期限との差を測定します。

1000 deviation samples of  1msec timer: min=  -246115nsec max=  1143471nsec median=   -70775nsec avg=      901nsec stddev=    45570nsec
1000 deviation samples of  5msec timer: min=  -265280nsec max=   256260nsec median=  -252363nsec avg=     -195nsec stddev=    30933nsec
1000 deviation samples of 10msec timer: min=  -273119nsec max=   274045nsec median=   103471nsec avg=     -179nsec stddev=    31228nsec
1000 deviation samples of  1msec timer: min=  -144930nsec max=  1052379nsec median=  -109322nsec avg=     1000nsec stddev=    43545nsec
1000 deviation samples of  5msec timer: min= -1229446nsec max=  1230399nsec median=  1222761nsec avg=      724nsec stddev=   254466nsec
1000 deviation samples of 10msec timer: min= -1227580nsec max=  1227734nsec median=    47328nsec avg=      745nsec stddev=   173834nsec
1000 deviation samples of  1msec timer: min=  -222672nsec max=   228907nsec median=    63635nsec avg=       22nsec stddev=    29410nsec
1000 deviation samples of  5msec timer: min= -1302808nsec max=  1270006nsec median=  1251949nsec avg=     -222nsec stddev=   345944nsec
1000 deviation samples of 10msec timer: min= -1297724nsec max=  1298269nsec median=  1254351nsec avg=     -225nsec stddev=   374717nsec

テストはFedora13カーネル2.6.34でリアルタイムプロセスとして実行され、1msタイマーの最高の精度はavg = 22nsec stddev = 29410nsecでした。

18

それが最善の解決策かどうかはわかりませんが、カーネルの高解像度タイマーを使用してタイミングをとる小さなカーネルモジュールを作成することを検討してください。基本的に、読み取りが1ミリ秒間隔でのみ返されるデバイスファイルを作成します。

このタイプのアプローチの例は、ztdummyモジュールを介してAsteriskPBXで使用されます。 ztdummyをグーグルで検索すると、これを行うコードを見つけることができます。

6
bmdhacks

カーネルはアプリケーションが常にCPUを取得することを保証しないため、メインループで一定のクエリを実行しても、標準のLinuxで1ミリ秒の精度を達成するのは難しいと思います。たとえば、プリエンプティブマルチタスクのために数十ミリ秒スリープ状態になる可能性があり、それについてできることはほとんどありません。

Real-Time Linux を調べてみてください。

5
che

X86プラットフォームをターゲットにしている場合は、HPETタイマーを確認する必要があります。高精度のハードウェアタイマーです。マザーボードでサポートされている必要があり(現在、すべてがサポートされています)、カーネルにもそのドライバが含まれている必要があります。私はそれを問題なく数回使用し、1msよりもはるかに優れた解像度を達成することができました。

ここにいくつかのドキュメントと例があります:

3
Zuljin

Gettimeofday/usleepベースのポーリングで問題のない結果が得られたことを思い出しているようです。1秒あたり1000タイマーなどは必要ありませんでしたが、必要なティックのタイミングで十分な精度が必要でした。アプリはMIDIドラムマシンコントローラー。非常に悪いドラマーのように聞こえたくない場合は、ドラムマシンに必要なサブミリ秒の精度を取得したことを覚えているようです(特にMIDIの組み込みレイテンシーを数えます)。 --iirc(2005年だったので、私の記憶は少し曖昧です)usleepでターゲット時間の200マイクロ秒以内に到達していました。

しかし、私はシステム上で他の多くを実行していませんでした。制御された環境がある場合は、そのようなソリューションで逃げることができるかもしれません。システムでさらに多くのことが行われている場合(cronがupdatedbを起動するのを見るなど)、状況が崩壊する可能性があります。

2
smcameron

Linux 2.4カーネルで実行していますか?

VMware KB記事#1420から( http://kb.vmware.com/kb/142 )。

Linuxゲストオペレーティングシステムは、タイマー割り込みをカウントすることで時間を維持します。パッチが適用されていない2.4以前のカーネルは、仮想システムタイマーをプログラムして、100Hzでのクロック割り込みを要求します(1秒あたり100割り込み)。一方、2.6カーネルは、1000Hzで割り込みを要求します。これは10倍の頻度です。 2.6の機能を含むようにディストリビューションベンダーによって変更された一部の2.4カーネルも、1000Hzの割り込み、または場合によっては512Hzなどの他のレートでの割り込みを要求します。

1
jakber

まず、カーネルソースを取得し、調整されたHZパラメーターを使用してコンパイルします。

  • HZ=1000の場合、タイマーは1秒間に1000回割り込みます。 i386マシンにはHZ=1000を使用しても問題ありません。
  • 組み込みマシンでは、HZは100または200に制限される場合があります。

正常に動作させるには、PREEMPT_KERNELオプションをオンにする必要があります。このオプションを適切にサポートしていないカーネルがあります。検索してチェックアウトできます。

最近のカーネル、つまり2.6.35.10は、動的ティックをオンにするNO_HZオプションをサポートしています。これは、アイドル状態ではタイマーティックがないことを意味しますが、指定された瞬間にタイマーティックが生成されます。

カーネルにはRTパッチがありますが、ハードウェアサポートは非​​常に限られています。

一般的に、RTAIはあなたの問題に対するすべてのキラーソリューションですが、そのハードウェアサポートは非​​常に限られています。ただし、emc2などの優れたCNCコントローラーは、RTAIをクロッキングに使用します。おそらく5000 Hzですが、インストールするのは大変な作業になる可能性があります。

可能であれば、ハードウェアを追加してパルスを生成することができます。それはどんなOSバージョンにも適応できるシステムを作るでしょう。

1
richard j. lee

Linuxカーネル用のktimerパッチがあります。

http://lwn.net/Articles/167897/

http://www.kernel.org/pub/linux/kernel/projects/rt/

HTH

1
plan9assembler

単純なリアルタイムアプリケーションにはRTOS)は必要ありません。最近のすべてのプロセッサには汎用タイマーがあります。作業中のターゲットCPUのデータシートを入手してください。カーネルソースを確認してください。 Archディレクトリには、これらのタイマーの処理方法に関するプロセッサ固有のソースがあります。

これで取ることができる2つのアプローチがあります:

1)アプリケーションはステートマシンのみを実行しており、他には何も実行していません。 Linuxは単に「ブートローダー」です。キャラクターデバイスをインストールするカーネルオブジェクトを作成します。カーネルに挿入したら、GPタイマーを設定して継続的に実行します。あなたはそれが動作している周波数を知っています。ここで、カーネルで、ウォッチドッグを明示的に無効にします。ここで、割り込み(ハードウェアとソフトウェア)を無効にします。シングルCPU Linuxカーネルで、spin_lock()を呼び出すと、これが実行されます(決して手放さないでください)。CPUはあなたのものです。ビジーループ。必要なティック数が経過するまでGPTの値をチェックし、通過したら、次のタイムアウトの値を設定して、処理ループに入ります。コードのバースト時間が1ミリ秒未満であることを確認してください

2)2番目のオプション。これは、プリエンプティブLinuxカーネルを実行していることを前提としています。実行中のOSと一緒に未使用のGPTを設定します。ここで、1msのタイムアウトが発生する前に、構成可能なマージンを発生させるように割り込みを設定します(たとえば、50〜75 uSec)。割り込みが発生すると、すぐに割り込みを無効にし、1msのウィンドウが発生するのを待ってから、ステートマシンに入ります。待機OUTで割り込みを有効にします。これは、割り込みを無効にするカーネル内の他のものと協力しているという事実を説明しています。これは、割り込みを長時間(100us以上)ロックアウトするカーネルアクティビティが他にないことを前提としています。これで、起動イベントの精度を測定し、必要に応じてウィンドウを大きくすることができます。

代わりに、RTOSがどのように機能するかを学習しようとしている場合、または複数のリアルタイム責任で制御の問題を解決しようとしている場合は、RTOSを使用してください。

1
Eric Texley

少なくともループ内でnanosleepを使用して1msスリープできますか?それとも、それはglibcのものですか?

更新:気にしないでください。manページから「プロセスが再び実行可能になるまで、指定よりも最大10ミリ秒長くかかる可能性があります」と表示されます。

0
Paul Tomblin

「/ dev/rtc0」(または「/ dev/rtc」)デバイスとそれに関連するioctl()インターフェースを使用するのはどうですか?正確なタイマーカウンターがあると思います。レートを1ミリ秒だけに設定することはできませんが、近い値または1/1024秒(1024Hz)、または8192Hzなどのより高い周波数に設定できます。

0
user3694063