Sto scrivendo un driver del kernel Linux per un dispositivo USB personalizzata che utilizzerà gli endpoint di massa, tutto sembra funzionare bene, però, ho sto ottenendo dati molto lenti. In particolare, ci vogliono circa 25 secondi per scrivere e leggere 10 MB di dati. Ho provato questo su un sistema embedded e una VM Linux in esecuzione su un PC ragionevole con risultati simili.molto scarso rendimento (~ 0.4MB/s) con Linux massa USB driver del kernel di trasferimento e l'hardware di loopback
Sto usando un kit di sviluppo FX2 EZ-USB da Cypress come il bordo di destinazione. È in esecuzione il firmware del bulkloop che imposta due endpoint in e due out. Ogni endpoint ha un doppio buffer e supporta finestre a 512 byte. I sondaggi firmware fuori endpoint tramite un po '(1) loop in main(), senza dormire, e copia i dati da fuori al endpoint quando tali dati sono disponibili utilizzando autopointers. Mi è stato detto che questo può spostare i dati abbastanza su Windows utilizzando la loro applicazione specifica ma non hanno avuto la possibilità di verificarlo.
Il mio codice (porzioni rilevanti sotto) chiama una funzione chiamata bulk_io nella routine della sonda dispositivo. Questa funzione crea un numero (URB_SETS) di out urbs che tenta di scrivere 512 byte sul dispositivo. La modifica di questo numero tra 1 e 32 non modifica le prestazioni. Stanno tutti copiando dallo stesso buffer. Il gestore di callback per ciascuna operazione di scrittura su un endpoint esterno viene utilizzato per creare una lettura urb sull'endpoint corrispondente. Il callback letto crea un'altra scrittura fino a quando non ho raggiunto il numero totale di richieste di scrittura/lettura che voglio eseguire contemporaneamente (20.000). Sto lavorando ora per trasferire la maggior parte delle operazioni nelle funzioni di callback nelle metà inferiori nel caso in cui stiano bloccando altri interrupt. Sto anche pensando di riscrivere il firmware bulk-loop per Cypress FX2 per utilizzare gli interrupt anziché il polling. C'è qualcosa qui che sembra fuori dall'ordinario per rendere la performance così bassa? Grazie in anticipo. Per favore fatemi sapere se volete vedere più codice, questo è solo un driver bare-bone per testare l'I/O sul Cypress FX2.
Questo è il out endpoint funzione di callback scrittura:
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);
}
Questo è il nel endpoint funzione di callback leggere:
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);
}
Questa funzione viene chiamata per impostare i urbs iniziali:
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);
}
Edit 1 I verifi Ed che udev-> velocità == 3, così USB_SPEED_HIGH, il che significa questo non è perché Linux pensa che questo è un dispositivo lento ....
Edit 2 ho spostato tutto nelle callback relative alla creazione urb (kmalloc, inviare) e liberare nelle metà inferiori, stessa prestazione.
Quindi il mistero non c'è più. Ho modificato il firmware "bulkloop" del CY7C68013A per attivare o disattivare un GPIO quando si spostano i punti finali di inserimento/inserimento dati e ha trascorso circa l'80% dei suoi cicli facendo questa funzione. Sembra che avere il core 8051 tocca i buffer USB per ridurre il throughput a ~ 0,5 MB/s come mostrato sopra. Sono andato avanti e confrontato con la loro dimostrazione di Bulloop lib windows CyUSB e ho ottenuto prestazioni molto peggiori, circa 0,1 MB/s. In conclusione, l'utilizzo del firmware del bulkloop non è un buon test delle prestazioni del driver USB. Lo proveremo con un FPGA che alimenterà i dati del CY7C68013A. – armguy
solo un piccolo punto qui, dovresti mantenere le callback URB il più piccolo possibile (ad esempio, basta impostare una bandiera) –