Estoy escribiendo un controlador kernel de Linux para un dispositivo USB personalizado que usará puntos finales masivos, todo parece funcionar bien, sin embargo, estoy obteniendo velocidades de datos muy lentas Específicamente, toma ~ 25 segundos escribir y leer datos de 10MB. Intenté esto con un sistema integrado y una VM Linux ejecutándose en una PC razonable con resultados similares.rendimiento muy pobre (~ 0.4MB/s) con Linux usb controlador de kernel de transferencia masiva y hardware loopback
Estoy utilizando un kit de desarrollo EZ-USB FX2 de Cypress como placa objetivo. Está ejecutando el firmware bulkloop que establece dos puntos finales de entrada y dos de salida. Cada punto final tiene doble buffer y admite ventanas de 512 bytes. El firmware sondea los puntos finales a través de un ciclo while (1) en main(), sin reposo, y copia los datos de out en los puntos finales cuando esos datos están disponibles usando autoposicionamientos. Me han dicho que esto puede mover los datos de manera justa en Windows utilizando su aplicación específica, pero no ha tenido la oportunidad de verificar esto.
Mi código (porciones relevantes a continuación) llama a una función llamada bulk_io en la rutina de sonda del dispositivo. Esta función crea un número (URB_SETS) de out urbs que intentan escribir 512 bytes en el dispositivo. Cambiar este número entre 1 y 32 no cambia el rendimiento. Todos están copiando desde el mismo buffer. El controlador de devolución de llamada para cada operación de escritura a un punto final externo se utiliza para crear una urb de lectura en el punto final correspondiente. La devolución de llamada de lectura crea otra urb de escritura hasta que haya alcanzado el número total de solicitudes de escritura/lectura que quiero ejecutar a la vez (20,000). Estoy trabajando ahora para insertar la mayoría de las operaciones en las funciones de devolución de llamada en las mitades inferiores en caso de que estén bloqueando otras interrupciones. También estoy pensando en reescribir el firmware bulk-loop para que Cypress FX2 use interrupciones en lugar de sondeo. ¿Hay algo aquí que parece fuera de lo normal para hacer que el rendimiento sea tan bajo? Gracias de antemano. Por favor, avíseme si desea ver más código, este es solo un controlador básico para probar E/S al Cypress FX2.
Ésta es la salida de punto final la función de devolución de llamada de escritura:
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);
}
Esta es la de punto final función de devolución de leer:
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);
}
Esta función se llama a la creación de la urbs iniciales:
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);
}
Editar 1 I verifi ed que udev-> == velocidad 3, por lo USB_SPEED_HIGH, significando esto no se debe a Linux piensa que esto es un dispositivo lento ....
Editar 2 me movía todo en las devoluciones de llamada relacionados con la creación urb (kmalloc, enviar) y la liberación en las mitades inferiores, el mismo rendimiento.
Así que el misterio ya no existe. Modifiqué el firmware CY7C68013A 'bulkloop' para alternar un GPIO cuando está moviendo data/arming endpoints y estaba gastando ~ 80% de sus ciclos en esa función. Parece que el 8051 core touch de los búferes USB reduce el rendimiento a ~ 0.5MB/s como se muestra arriba. Seguí adelante y comparé con su demo de CylusB lib Windows bulkloop y obtuve un desempeño mucho peor, alrededor de 0.1MB/s. En conclusión, usar el firmware bulkloop no es una buena prueba del rendimiento del controlador USB. Lo intentaré con un FPGA alimentando los datos del CY7C68013A a continuación. – armguy
solo un pequeño punto aquí, debe mantener las devoluciones de llamada URB lo más pequeñas posible (por ejemplo, simplemente establecer una bandera) –