ChangeSet 1.1094.6.2, 2003/03/11 17:13:26-08:00, baldrick@wanadoo.fr [PATCH] USB speedtouch: send path optimization Write multiple cells in one function call, rather than one cell per function call. Under maximum send load, this reduces cell writing CPU usage from 0.0095% to 0.0085% on my machine. A 10% improvement! :) drivers/usb/misc/speedtouch.c | 68 +++++++++++++++++++++++++----------------- 1 files changed, 41 insertions(+), 27 deletions(-) diff -Nru a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtouch.c --- a/drivers/usb/misc/speedtouch.c Mon Mar 17 11:47:32 2003 +++ b/drivers/usb/misc/speedtouch.c Mon Mar 17 11:47:32 2003 @@ -273,39 +273,60 @@ ctrl->aal5_trailer [7] = crc; } -static char *udsl_write_cell (struct sk_buff *skb, char *target) { +unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p) { struct udsl_control *ctrl = UDSL_SKB (skb); + unsigned char *target = *target_p; + unsigned int nc, ne, i; - ctrl->num_cells--; + dbg ("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding); - memcpy (target, ctrl->cell_header, ATM_CELL_HEADER); - target += ATM_CELL_HEADER; + nc = ctrl->num_cells; + ne = min (howmany, ctrl->num_entire); - if (ctrl->num_entire) { - ctrl->num_entire--; + for (i = 0; i < ne; i++) { + memcpy (target, ctrl->cell_header, ATM_CELL_HEADER); + target += ATM_CELL_HEADER; memcpy (target, skb->data, ATM_CELL_PAYLOAD); target += ATM_CELL_PAYLOAD; __skb_pull (skb, ATM_CELL_PAYLOAD); - return target; } + ctrl->num_entire -= ne; + + if (!(ctrl->num_cells -= ne) || !(howmany -= ne)) + goto out; + + memcpy (target, ctrl->cell_header, ATM_CELL_HEADER); + target += ATM_CELL_HEADER; memcpy (target, skb->data, skb->len); target += skb->len; __skb_pull (skb, skb->len); - memset (target, 0, ctrl->pdu_padding); target += ctrl->pdu_padding; - if (ctrl->num_cells) { - ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER; - } else { - memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER); - target += ATM_AAL5_TRAILER; - /* set pti bit in last cell */ - *(target + 3 - ATM_CELL_SIZE) |= 0x2; + if (--ctrl->num_cells) { + if (!--howmany) { + ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER; + goto out; + } + + memcpy (target, ctrl->cell_header, ATM_CELL_HEADER); + target += ATM_CELL_HEADER; + memset (target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER); + target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER; + + if (--ctrl->num_cells) + BUG(); } - return target; + memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER); + target += ATM_AAL5_TRAILER; + /* set pti bit in last cell */ + *(target + 3 - ATM_CELL_SIZE) |= 0x2; + +out: + *target_p = target; + return nc - ctrl->num_cells; } @@ -500,14 +521,12 @@ static void udsl_process_send (unsigned long data) { struct udsl_send_buffer *buf; - unsigned int cells_to_write; int err; unsigned long flags; - unsigned int i; struct udsl_instance_data *instance = (struct udsl_instance_data *) data; + unsigned int num_written; struct sk_buff *skb; struct udsl_sender *snd; - unsigned char *target; dbg ("udsl_process_send entered"); @@ -577,16 +596,11 @@ instance->current_buffer = buf; } - cells_to_write = min (buf->free_cells, UDSL_SKB (skb)->num_cells); - target = buf->free_start; - - dbg ("writing %u cells from skb 0x%p to buffer 0x%p", cells_to_write, skb, buf); + num_written = udsl_write_cells (buf->free_cells, skb, &buf->free_start); - for (i = 0; i < cells_to_write; i++) - target = udsl_write_cell (skb, target); + dbg ("wrote %u cells from skb 0x%p to buffer 0x%p", num_written, skb, buf); - buf->free_start = target; - if (!(buf->free_cells -= cells_to_write)) { + if (!(buf->free_cells -= num_written)) { list_add_tail (&buf->list, &instance->filled_buffers); instance->current_buffer = NULL; dbg ("queued filled buffer");