19

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

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

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

私が使用している言語は普通の古い c です

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

対応しなければならないネットワーク イベントがある可能性があるため、1 ミリ秒もスリープできません。

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

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

4

12 に答える 12

17

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

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

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

于 2008-10-27T14:52:02.473 に答える
17

1 ミリ秒の解像度タイマーを取得するには、libeventが行うことを行います。

タイマーをmin-heapに編成します。つまり、ヒープの一番上は、有効期限 (絶対) 時間が最も早いタイマーです (rb-tree も機能しますが、オーバーヘッドが大きくなります)。呼び出す前、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

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

于 2011-01-18T12:33:19.383 に答える
6

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

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

于 2008-10-27T14:53:05.140 に答える
5

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

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

于 2008-10-27T14:49:47.597 に答える
3

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

以下にいくつかのドキュメントと例を示します。

于 2011-01-18T12:02:39.753 に答える
2

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

しかし、私はシステム上で他の多くを実行していませんでした. 制御された環境があれば、そのような解決策でうまくいくかもしれません。システムでさらに多くのことが起こっている場合 (cron が updatedb を起動するのを監視するなど)、状況が崩壊する可能性があります。

于 2009-01-20T05:26:10.693 に答える
1

単純なリアルタイムアプリケーションには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を使用してください。

于 2013-01-11T03:00:42.990 に答える
1

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

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

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

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

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

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

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

于 2011-01-18T11:24:29.930 に答える
1

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

VMware KB 記事 #1420 ( http://kb.vmware.com/kb/1420 ) より。

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

于 2008-10-27T14:50:18.873 に答える
1

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

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

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

HTH

于 2008-10-27T14:56:56.100 に答える
0

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

于 2014-05-31T11:18:32.710 に答える
0

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

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

于 2008-10-27T14:48:12.887 に答える