カーネルモジュールのデータをユーザー空間に保存

カーネルモジュールのデータをユーザー空間に保存

私はしばらくの間カーネルプログラミングを調査してきましたが、いくつかのカスタムハードウェアを使用してこの単純なデータ収集インターフェースを作成したかったのです。移植性と再利用性のために、すべての作業はRaspberry Piによって行われました。

プロジェクトの難しい部分は、高速ADC(パラレル)をGPIOに接続し、ADCのハードウェア割り込みを使用して各サンプルを取得し、chardeviceを介してアクセス可能なバッファに格納するカーネルモジュールを持つことです。バッファ。

現在動作している設定は次のとおりです。

  • SPIを介してハードウェアを制御するユーザースペースCプログラムがあります。必要なコマンドを送信すると、アナログデータの収集が開始され、ADCに送信されます。
  • ADCが変換を完了するたびに、GPIOはその信号を「低」に設定し、カーネルモジュール(対応するGPIOにバインド)内で割り込みが発生します。 ISRは他の12個のGPIO(12ビットADC)から値を収集してバッファに入れ、/ dev / mydeviceを介してアクセスします。
  • /dev/mydeviceからデータを読み込み、「out_data.dat」(ユーザー空間ファイル)への書き込み中に無限ループを実行する別のユーザー空間プログラムがあります.
  • この粗い設定(2つのユーザースペースプログラムとカーネルモジュールのロード)を使用すると、1秒あたり130,000以上のサンプルをファイルに書き込むことができます(何も失うことなく)。

今どのくらい速く走ることができるかを確認したいと思います。考慮すべき2つのことがあります。

  1. 上記の設定は、このようなタスクを実行する「一般的な」方法ですか?カーネルが直接ファイルI / Oを推奨しないという内容をどこでも読んだので、そうしません。もちろん、ISR中に「永続的な」場所に記録することは可能です。これは、一部のハードウェアからコンピュータにデータを転送するために割り込みを使用しようとしたときによく発生する問題のようです。

  2. 上記の設定を変更せずに他の割り込みを無効にしてできるだけスムーズにする方法はありますか?データ収集プロセス中は実際には何も必要ではなく、それをブロックする方法だけが必要です。データ収集は数分間だけ実行されるため、他のすべての割り込み(無線、モニタの更新など)は無効にできます。その後、すべてが回復し、よりトリッキーなPythonコードを実行してデータを分析して視覚化することができます(少なくともこれは私の簡単なビューです)。

ベストアンサー1

ユーザー空間データ収集プログラムの無限ループの問題は何ですか?システムコールを使用する限り、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

私はまた、あなたが見つけた方法で割り込みを無効にしようとし、良い方法が存在するかどうかを学ぶ前に、より効率的であることを確認します。

シミュレータで素早く:

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/keyboard 割り込みを継続的に更新します。

fopsなどの他のエントリポイントや生を試しても同じことが言えますasm("cli")。もっと訓練されたアプローチが必要です。

おすすめ記事