web-dev-qa-db-ja.com

カーネルモジュールからユーザースペースへのデータの保存

私はしばらくの間カーネルプログラミングをいじっていて、いくつかのカスタムハードウェアでこの単純なデータ取得インターフェイスを作成したいと思っています。移植性と再利用性のために、私はRaspberryPiですべてを行います。

プロジェクトの難しい部分は、GPIOに接続された高速ADC(並列)と、ADCからのハードウェア割り込みを使用して各サンプルを取得し、chardeviceを介してアクセスできるバッファー内に保存するカーネルモジュールを持つことです。

私の現在の設定(動作する)は次のとおりです。

  • SPIを介してハードウェアを制御しているユーザースペースCプログラムがあります。必要なコマンドを送信すると、アナログデータの取得が開始され、ADCに送信されます。
  • ADCが変換を終了するたびに、対応する信号をGPIOの「ロー」にプッシュし、カーネルモジュール内で割り込みを受け取ります(そのGPIOにバインドされています)。 ISRは、他の12個のGPIO(12ビットADC)の値を収集し、それをバッファーに入れて、/ dev/mydeviceを介してアクセスします。
  • / dev/mydeviceから読み取り、次に 'out_data.dat'(ユーザースペースファイル)に書き込む、終わりのないwhileループを実行する別のユーザースペースプログラムがあります。
  • この大まかなセットアップ(2つのユーザースペースプログラムとカーネルモジュールがロードされている)を使用すると、1秒あたり13万を超えるサンプルをファイルに書き込むことができます(何も見逃すことはありません)。

私は今、どれだけ速くそれを達成できるかを見たいと思っています。考慮すべき2つのことがあります。

  1. 私が「通常の」方法の上に概説したセットアップは、このようなことがどのように行われるのでしょうか?直接ファイルI/Oがカーネルからアドバイスされていないことをどこでも読んだので、私はそれをしていません。確かに、ISR中に「永続的な」場所に書き込むことは可能です。これは、割り込みを使用して一部のハードウェアからコンピューターにデータを取得しようとする一般的な問題のように思えます。

  2. 上記の設定を変更せずに、他の割り込みを無効にしてできるだけスムーズにする方法はありますか?データ収集の間、私は実際には何も必要とせず、それを止める方法のある種の方法だけが必要です。データ収集は数分間しか実行されないため、その他の割り込み(ワイヤレス、モニターの更新など)は無効にできます。その後、すべてが再開され、より要求の厳しいpythonコードを実行して、データを分析および視覚化できます(少なくともそれは私の単純な見方です)。

4
Amudsen

ユーザースペースデータ収集プログラムの場合、無限ループの何が問題になっていますか? pollシステムコールを使用している限り、効率的であるはずです: https://stackoverflow.com/questions/30035776/how-to-add-poll-function-to-the -kernel-module-code/44645336#44645336

永続的なデータストレージ

それを行うための最良の方法がわかりません。投票でユーザーランドからファイルに書き込んでみませんか?届くデータが多すぎるとデータが失われるのではないかと心配していると思いますが、そうですか?

しかし、その場合の制限要因はカーネルからユーザーランドへの通信ではなく、永続ストレージデバイスの速度が遅いため、ユーザーランドでそれを行っても違いはないと思います。いずれにせよ、カーネルのみのソリューションには、次の場所で注目を集める質問があります: https://stackoverflow.com/questions/1184274/how-to-read-write-files-within-a-linux-kernel-module そして私はあなたがここでより良い解決策を得るとは思わない。

割り込みを無効にする

特にボトルネックが発生する可能性があることを考えると、それが何か違いを生むと確信していますか?お使いのデバイスが実際に多数の割り込みを生成している場合は、いずれにせよ、それらが他の割り込みを支配すると思います。他のハードウェアの状態を台無しにするリスクを冒す価値はありますか?ハードウェアデバイスの仕様は、現在のデータ帯域幅よりもはるかに広いデータ帯域幅を物理的に提供できることを示唆していますか?

自分でそれを行う方法はわかりませんが、答えが必要な場合は、「Linuxカーネルモジュールからのすべての割り込みを無効にする方法」というタイトルの別の質問をするのが最善の策です。 LDD2はcli()関数について言及しています http://www.xml.com/ldd/chapter/book/ch09.html しかし、非推奨のようです: https ://notes.shichao.io/lkd/ch7/#no-more-global-cli そのテキストは、_local_irq_disable_と_local_irq_save_を示唆しています。

また、割り込みを無効にするために見つけた方法でハックして、Niceメソッドが存在するかどうかをさらに調べる前に、効率が上がるかどうかを確認します。

エミュレーターでは、簡単に:

_static int myinit(void)
{
    pr_info("hello init\n");
    unsigned long flags;
    local_irq_save(flags);
    return 0;
}
_

失敗する:

_returned with disabled interrupts
_

どうやらv4.16 _do_one_initcall_から来ているので、そのための特別なエラー処理があります!

次に、ワーカースレッドから素朴にそれを実行してみました。

_static int work_func(void *data)
{
    unsigned long flags;
    local_irq_save(flags);
    return 0;
}

static int myinit(void)
{
    kthread = kthread_create(work_func, NULL, "mykthread");
    wake_up_process(kthread);
    return 0;
}
_

しかし、それでも効果を観察できないため、次のことから推測できるように、割り込みは他の何かによって有効にされている必要があります。

_watch -n 1 grep i8042 /proc/interrupts
_

ttyまたはmuse /キーボード割り込みを更新し続けます。

Fopsなどの他のエントリポイントから、または生のasm("cli")を試した場合も同じです。もっと知識のあるアプローチが必要になります。