Re: Understanding delays in HID driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Alan Stern wrote:
On Mon, 23 Mar 2009, Richard wrote:

Hi,

I have some questions about the HID USB driver in Linux.

Just thought I'd mention that nothing in your message below talks about the HID driver...

I have
a Linux From Scratch LFS 6.2 system, with many additions
according to BLFS 6.2. I am using the 2.6.16.27 kernel.

That's a pretty old kernel.  You should upgrade, if at all possible.

I am communicating with a Cypress PSoc device, part number
CY8C24894, over usb. The device is configured as an HID with
bInterval of 1ms. I am communicating over interrupt in and
out endpoints. Here is the relevant portion from a lsusb
listing which shows how the interrupt endpoints are set up:

---------------------------------------------------------------
       Endpoint Descriptor:
         bLength                 7
         bDescriptorType         5
         bEndpointAddress     0x81  EP 1 IN
         bmAttributes            3
           Transfer Type            Interrupt
           Synch Type               None
           Usage Type               Data
         wMaxPacketSize     0x0040  1x 64 bytes
         bInterval               1
       Endpoint Descriptor:
         bLength                 7
         bDescriptorType         5
         bEndpointAddress     0x02  EP 2 OUT
         bmAttributes            3
           Transfer Type            Interrupt
           Synch Type               None
           Usage Type               Data
         wMaxPacketSize     0x0040  1x 64 bytes
         bInterval               1
Device Status:     0x0000
   (Bus Powered)
-------------------------------------------------------

As you can see the PSoc device is configured with one
interrupt in endpoint and one interrupt out endpoint,
with maximum packet size of 64 bytes and 1ms polling
interval.

My program, which is written in C and uses libusb
calls, is continually sending out usb interrupt
messages with 64 bytes each, and after each message
is sent the program requests a reply from the
PSoc device, which consists of a packet of 62
bytes. I am seeing about an 8ms round trip for
this process, i.e. from the time one 64-byte packet
is sent, the 62-byte reply is received, and the
next 64-byte packet is sent out.

I have enabled debugfs and I've used usbmon to
capture a typical cycle of the usb transactions.
Here is a representative set, where I have added
numbers at the beginning of each line for
reference:

1. dfb324c0 1787068080 S Io:002:02 -115 64 = 043e0100 0c000e0e 00000000 00000000 00000000 00000000 00000000 00000000
2. dfb324c0 1787069920 C Io:002:02 0 64 >
3. dfb324c0 1787069957 S Ii:002:01 -115 62 <
4. dfb324c0 1787072920 C Ii:002:01 0 62 = 01000c00 0e0e0000 00000000 00000000 00000000 00000000 00000000 00000000 5. dfb324c0 1787076043 S Io:002:02 -115 64 = 043e0100 0c001c0e 00000000 00000000 00000000 00000000 00000000 00000000

I don't completely understand this report, so any help with
interpretation will be appreciated.

Line 1 shows your first interrupt-OUT (Io) URB being submitted (S).
Line 2 shows the interrupt-OUT URB completing (C) successfully.
Line 3 shows your interrupt-IN URB (Ii) being submitted.
Line 4 shows the interrupt-IN URB completing successfully.
Line 5 shows a second interrupt-OUT URB being submitted.

 I think it is clear that
line 1 is where the PC sends an interrupt out message to
the PSoc device consisting of 64 bytes.

Not exactly. Line 1 is where the message is _submitted_. It doesn't get sent immediately; there is always a delay between submission and transmission.

This is accomplished
in the program by a libusb usb_interrupt_write() call.
Immediately after that call, the program starts looking
for a 62-byte reply from the PSoc, via a usb_interrupt_read()
call. I am assuming that in line 2 the PC is sending out
a message that it is looking for this reply.

No. See above. The interrupt-IN _submission_ occurs in line 3, and the actual data transmission occurs a little later.

 This occurs
1.84ms after the 64-byte out transaction.

More accurately, your interrupt-OUT URB completes 1.84 ms after it is submitted and your interrupt-IN URB is submitted 0.037 ms afterward.

I'm not sure
what is happening in line 3, I am guessing that the PSoc
device is notifying the PC that it has 62 bytes ready to
send via an in transaction, or maybe it is telling the
PC that the reply is not yet ready. Then on line 4, 3ms after it
was requested in line 2, the 62-byte in transaction is
received from the PSoc device.

Pretty much.  The interrupt-IN URB completes almost 3 ms after it was
submitted (exactly 3 ms after the preceding interrupt-OUT completed).

 Finally in line 5, 3.12ms
after the in transaction is received, the next 64-byte
out transaction in the series is sent.

Right.

My basic question regards some of the delays in this
process. In my program, there should be very little
delay between the time a 62-byte in transaction is
received, and the time when the next 64-byte out
transaction is sent. But it appears that it takes over
3ms before the next out transaction is sent. I wouldn't
expect this delay to be more than 1ms. Does anyone
have an idea why it takes so long to send the next
message?

I don't know.  It seems unlikely that the kernel or a user library is
adding any significant delay.  Maybe your program takes longer than you
expect or maybe some other process is using the CPU.

My understanding is that with a 1ms polling interval,
all usb requested actions should be initiated in at
most 1ms. Does the HID driver strictly enforce this
timing?

If you're using libusb then the HID driver isn't involved at all.

It's worth pointing out that although a 1-ms polling interval
guarantees that ongoing transfers will occur once per millisecond, it
says nothing about how long a new transfer takes to get set up.

Also, my program immediately starts looking for
a 62-byte reply after it sends a 64-byte out
message, however it appears that the usb is
waiting 1.84ms before requesting this reply.
Again, any insight as to why this takes so long?

You have misunderstood the delays.  See above.

The 3ms delay between when the 62-byte in transaction
is requested in line 2, and when it is actually
received in line 4, is understandable because this
is essentially the time it takes the PSoc device
to process the data it has received and to formulate
its reply message, plus some extra delay to coincide
with the next usb frame sync, I would imagine.

That sounds reasonable.

Are the libusb calls good to use for this
application, or should I be using another interface
to the usb system?

libusb is fine.  If you really want to get fancy you can use
asynchronous transfers, which are supported in libusb-1.0. But in this case it's not clear they would help much, since a lot of the delay appears to be caused by the device itself.

In theory you could get some improvement by making the IN transfer
asynchronous and submitting the second OUT transfer before the first IN
transfer finishes.  But your device might not be able to handle this.

Probably the best improvement you could make would be to raise your program's priority. That should help eliminate the nagging 3 ms delay between the IN transfer and the next OUT transfer.


Thanks very much for all your help.

I tried setting the priority of my program with the
setpriority() function, but it made no difference in
the usb timing. Is that how I should change the
program's priority?

I also have a general question - given that this
device enumerates as a HID device, how is it that
the HID driver never enters into the picture?

Thanks again,

Richard

Any help with these timing
issues or suggestions about how I could speed up
the usb communications will be very much appreciated.

Alan Stern

.


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux