arm*_*guy 5 linux usb performance kernel driver
我正在为自定义USB设备编写一个Linux内核驱动程序,它将使用批量端点,一切似乎工作正常,但是,我的数据速率非常慢.具体来说,写入和读取10MB的数据需要大约25秒.我在嵌入式系统和运行在合理PC上的Linux VM上尝试了这一点,结果相似.
我使用赛普拉斯的EZ-USB FX2开发套件作为目标板.它正在运行bulkloop固件,它设置了两个入口和两个出端点.每个端点都是双缓冲的,并支持512字节窗口.固件通过main()中的while(1)循环轮询出端点,没有睡眠,并且当使用自动打印机提供这些数据时,将数据从out复制到端点.有人告诉我,这可以使用他们的特定应用程序在Windows上公平地移动数据但是没有机会验证这一点.
我的代码(下面的相关部分)在设备探测例程中调用一个名为bulk_io的函数.此函数创建一个out urbs的数字(URB_SETS),尝试将512字节写入设备.将此数字更改为1到32之间不会改变性能.它们都是从同一个缓冲区复制的.每个对out端点的写操作的回调处理程序用于在端点中的相应端点上创建读取urb.读取回调创建另一个写入urb,直到我达到了我想要一次运行的写入/读取请求总数(20,000).我现在正在努力将回调函数中的大多数操作推送到下半部分,以防它们阻塞其他中断.我也在考虑重写赛普拉斯FX2的批量循环固件,以便使用中断而不是轮询.这里有什么东西看起来与众不同,使性能如此之低?先感谢您.如果您想查看更多代码,请告诉我,这只是测试赛普拉斯FX2 I/O的简单驱动程序.
这是out端点写回调函数:
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);
}
Run Code Online (Sandbox Code Playgroud)
这是端点读取回调函数:
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);
}
Run Code Online (Sandbox Code Playgroud)
调用此函数来设置初始urbs:
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);
}
Run Code Online (Sandbox Code Playgroud)
编辑1我验证了udev-> speed == 3,所以USB_SPEED_HIGH,这意味着这不是因为Linux认为这是一个慢设备....
编辑2我移动了与urb创建相关的回调中的所有内容(kmalloc,submit)并释放到下半部分,性能相同.
根据我的经验,小块地阅读和写作并不是很有效。
我使用 Cypress 的 EZ-USB FX2 开发套件作为目标板。它正在运行bulkloop固件,该固件设置两个输入和两个输出端点。每个端点都是双缓冲的并支持 512 字节窗口。
这并不意味着您一次只能写入不超过 512 个字节。
我会尝试一次写入不少于 4096 字节,因为这是标准页面大小(在嵌入式系统中可能不是那么标准)。如果有效的话,我会尝试一次向其中写入 1/4 兆字节,如果有效的话,甚至会写入更多。
这里的关键点是知道设备的写入窗口何时已满。当它是时 - 它会调用任何回调,或者您通过任何其他方式获取该信息并使用它来向您的应用程序发出停止写入的信号。
请注意,在“给设备”512 字节后,该窗口不会填满,因为一旦有任何内容要读取,设备就会开始从此窗口读取。
也许我在你的问题中遗漏了一些重要的东西,但我想说的是,你必须一次写入超过 512 个字节。这就是为什么你的表现如此糟糕。
| 归档时间: |
|
| 查看次数: |
1972 次 |
| 最近记录: |