linux - Linux USB 批量传输内核驱动程序和硬件环回的性能非常差(~0.4MB/s)

标签 linux performance usb kernel driver

我正在为将使用批量端点的自定义 USB 设备编写 Linux 内核驱动程序,一切似乎都运行良好,但是,我的数据速率非常慢。具体来说,写入和读取 10MB 的数据大约需要 25 秒。我在嵌入式系统和运行在合理 PC 上的 Linux VM 上进行了尝试,结果相似。

我使用 Cypress 的 EZ-USB FX2 开发套件作为目标板。它正在运行设置两个输入和两个输出端点的 bulkloop 固件。每个端点都是双缓冲的并支持 512 字节窗口。固件通过 main() 中的 while(1) 循环轮询端点,不休眠,并在这些数据使用自动指针可用时将数据从端点复制到端点。有人告诉我,这可以使用他们的特定应用程序在 Windows 上公平地移动数据,但还没有机会验证这一点。

我的代码(下面的相关部分)在设备探测例程中调用了一个名为 bulk_io 的函数。这个函数创建了一个数字(URB_SETS)out urbs,它试图将 512 字节写入设备。在 1 到 32 之间更改此数字不会改变性能。它们都是从同一个缓冲区复制的。每个对 out 端点的写操作的回调处理程序用于在相应的 in 端点上创建一个读取 urb。读取回调创建另一个写入 urb,直到我达到我想要一次运行的写入/读取请求总数 (20,000)。我现在正在努力将回调函数中的大部分操作插入下半部分,以防它们阻塞其他中断。我也在考虑为 Cypress FX2 重写批量循环固件以使用中断而不是轮询。是不是这里有什么看起来不正常的东西让性能这么低?先感谢您。如果您想查看更多代码,请告诉我,这只是用于测试 Cypress FX2 的 I/O 的基本驱动程序。

这是输出端点写回调函数:

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 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 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 我验证了 udev->speed == 3,所以 USB_SPEED_HIGH,这意味着这不是因为 Linux 认为这是一个慢设备....

编辑 2 我将与 urb 创建(kmalloc、提交)和释放相关的回调中的所有内容都移到了下半部分,性能相同。

最佳答案

根据我的经验,小块阅读和写作不是很有效。

I am using a EZ-USB FX2 development kit from Cypress as the target board. It is running the bulkloop firmware which sets up two in and two out endpoints. Each endpoint is double buffered and supports 512 byte windows.

这并不意味着您一次只能写入 512 个字节。

我会尝试一次写入不少于 4096 字节,因为这是标准页面大小(在嵌入式系统中可能不是那么标准)。如果可行,我会尝试一次写入 1/4 兆字节,如果可行的话甚至更多。

这里的关键点是知道设备的写入窗口何时已满。如果是 - 它会调用任何回调,或者您通过任何其他方式获取该信息并使用它来通知您的应用程序停止写入。

请注意,在您“给设备”512 字节后窗口不会填满,因为只要有任何内容可读,设备就会从该窗口开始读取。

也许我在你的问题中遗漏了一些重要的东西,但我的意思是基本上你必须一次写入超过 512 个字节。这就是为什么你的表现如此糟糕。

关于linux - Linux USB 批量传输内核驱动程序和硬件环回的性能非常差(~0.4MB/s),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7962182/

相关文章:

linux - 哪个 linux 风格正在运行

linux - 进程名称长度的最大允许限制是多少?

java - 调用 Class.isAnnotationPresent(...) 有多昂贵?

c - 检测 USB HID 设备何时模拟键盘的可靠方法

linux - 适用于 Linux 的最佳开源软件负载均衡器

linux - 我想用树莓派创建一个无线局域网,它将运行nodejsexpress框架来在浏览器中播放视频

python numpy 加速 2d 重复搜索

performance - Fortran 暗示做写加速

java - 通过 USB 的 Android 智能卡读卡器错误 : PROCEDURE BYTE CONFLICT

java - 通过 USB 进行 Android Java 通信