加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

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

发布时间:2020-12-14 01:42:06 所属栏目:Linux 来源:网络整理
导读:我正在为自定义USB设备编写一个 Linux内核驱动程序,它将使用批量端点,一切似乎工作正常,但是,我的数据速率非常慢.具体来说,写入和读取10MB的数据需要大约25秒.我在嵌入式系统和运行在合理PC上的Linux VM上尝试了这一点,结果相似. 我使用赛普拉斯的EZ-USB FX2
我正在为自定义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);
}

这是端点读取回调函数:

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,usb_sndbulkpipe(uds->udev,uds->ep_out[0]),uds->buf_out,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=%sn",(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=%ldn",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,uds);
                            printk("bulk_io: submitted urb,status=%dn",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,submit)并释放到下半部分,性能相同.

解决方法

根据我的经验,阅读和书写小块并不是很有效.

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个字节.这就是你如此糟糕的表现.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读