バルクエンドポイントを使用するカスタムUSBデバイス用のLinuxカーネルドライバを作成していますが、非常に遅いデータレートを取得しています。具体的には、10MB相当のデータを書き込んで読み込むには約25秒かかります。私は組み込みシステムとこれに似た結果を持つ合理的なPC上で実行されているLinux VMでこれを試しました。Linux usbバルク転送カーネルドライバとハードウェアループバックでパフォーマンスが非常に悪い(〜0.4MB/s)
サイプレスのEZ-USB FX2開発キットをターゲットボードとして使用しています。 2つのinと2つのoutエンドポイントを設定するbulkloopファームウェアを実行しています。各エンドポイントはダブルバッファーで512バイトのウィンドウをサポートします。ファームウェアは、main()のwhile(1)ループを介してエンドポイントをポーリングし、スリープなしで、自動ポインタを使用してデータが利用可能な場合、エンドポイント内のデータをコピーします。私はこれが、特定のアプリケーションを使ってWindows上で公平にデータを移動できますが、これを確認する機会はなかったと言われています。
私のコード(以下の関連部分)は、デバイスプローブルーチンでbulk_ioという関数を呼び出します。この関数は、デバイスに512バイトを書き込もうとするurbsの番号(URB_SETS)を作成します。この数値を1から32の間で変更しても、パフォーマンスは変わりません。それらはすべて同じバッファからコピーしています。アウト・エンドポイントへの各書き込み操作のコールバック・ハンドラーは、対応するエンドポイントに読み取りurbを作成するために使用されます。私が一度に実行したい書き込み/読み出し要求の総数(20,000)に達するまで、読み取りコールバックは別の書き込みurbを作成します。私は今、他の割り込みをブロックしている場合、コールバック関数のほとんどの操作を下半分に押し込むように取り組んでいます。また、ポーリングの代わりに割り込みを使用するようにCypress FX2用のバルクループファームウェアを書き直すことも考えています。演技をそんなに低くするために普通に見えるものはここにありますか?前もって感謝します。より多くのコードを表示したい場合はお知らせください。これはCypress FX2のI/Oをテストするための単なるベアボーンのドライバです。
これはアウトエンドポイント、書き込みコールバック関数です:
この機能を設定するために呼び出されるstatic void bulk_io_in_callback0(struct urb *t_urb) {
struct usb_dev_stat *uds = t_urb->context;
struct urb *urb0 = usb_alloc_urb(0,GFP_KERNEL);
if (urb0 == NULL) {
printk("bulk_io_out_callback0: out of memory!");
}
if (uds->seq--) {
usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_sndbulkpipe(uds->udev,uds->ep_out[0]), uds->buf_out, uds->max_packet, bulk_io_out_callback0, uds);
usb_submit_urb(urb0,GFP_KERNEL);
}
else {
uds->t1 = get_seconds();
uds->buf_in[9] = 0; // to ensure we only print the first 8 chars below
printk("bulk_io_in_callback0: completed, time=%lds, bytes=%d, data=%s\n", (uds->t1-uds->t0), uds->max_packet*SEQ, uds->buf_in);
}
usb_free_urb(urb0);
}
初期urbs:
static void bulk_io_out_callback0(struct urb *t_urb) {
// will need to make this work with bottom half
struct usb_dev_stat *uds = t_urb->context;
struct urb *urb0 = usb_alloc_urb(0,GFP_KERNEL);
if (urb0 == NULL) {
printk("bulk_io_out_callback0: out of memory!");
}
usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_rcvbulkpipe(uds->udev,uds->ep_in[0]), uds->buf_in, uds->max_packet, bulk_io_in_callback0, uds);
usb_submit_urb(urb0,GFP_KERNEL);
usb_free_urb(urb0);
}
これは、エンドポイントでのコールバック関数を読んで
static int bulk_io (struct usb_interface *interface, struct usb_dev_stat *uds) {
struct urb *urb0;
int i;
uds->t0 = get_seconds();
memcpy(uds->buf_out,"abcd1234",8);
uds->seq = SEQ; // how many times we will run this
printk("bulk_io: starting up the stream, seq=%ld\n", uds->seq);
for (i = 0; i < URB_SETS; i++) {
urb0 = usb_alloc_urb(0,GFP_KERNEL);
if (urb0 == NULL) {
printk("bulk_io: out of memory!\n");
return(-1);
}
usb_fill_bulk_urb(urb0, interface_to_usbdev(uds->intf), usb_sndbulkpipe(uds->udev,uds->ep_out[0]), uds->buf_out, uds->max_packet, bulk_io_out_callback0, uds);
printk("bulk_io: submitted urb, status=%d\n", usb_submit_urb(urb0,GFP_KERNEL));
usb_free_urb(urb0); // we don't need this anymore
}
return(0);
}
編集1 I verifi編そのudev->スピード== 3、USB_SPEED_HIGHので、Linuxはこれが低速なデバイスであると考えているので、これはではないという意味....
編集2私はURBの作成に関連するコールバックのすべて(kmallocのを移動し、提出)し、同じ半分のパフォーマンス、同じパフォーマンスを解放します。
だから謎はもはやありません。データ/アーミングエンドポイントを移動しているときにGPIOを切り替えるためにCY7C68013Aの 'bulkloop'ファームウェアを修正し、その機能を実行するサイクルの80%を費やしていました。 USBバッファを8051のコアタッチにすると、上記のようにスループットが〜0.5MB/sに低下するようです。私は先に進み、CyUSBのlib windows bulkloopデモでベンチマークを行い、パフォーマンスは0.1MB/sくらいに低下しました。結論として、バルクループファームウェアを使用することは、USBドライバのパフォーマンスの良いテストではありません。次はCY7C68013Aデータを供給するFPGAで試してみましょう。 – armguy
ちょっとここでは、URBコールバックを可能な限り小さく保つ必要があります(たとえば、フラグを設定するだけです) –