Optimization doubts with USB driver

Report here problems in any of ChibiOS components. This forum is NOT for support.
Ceco
Posts: 40
Joined: Tue Nov 27, 2012 12:16 pm
Been thanked: 3 times

Optimization doubts with USB driver

Post by Ceco »

Hello. I'm using STM32F439 with external PHY USB3320C. The OS version is 18.2.0. The driver is configured for HS mode. CPU clock is 168MHz.

I'm trying to implement MSD mode with maximum performance. After a digging in the code, I found one potential performance limitation.

In file hal_usb_lld.c, there are a functions to read and write the USB FIFO. Normally these functions are implemented as simple loops, so they consume CPU time. There is a lack of information about dedicated DMA in HS mode, so I understand this implementation. But after some measurements, I was surprised from the big difference in CPU load of both functions. Here are my measurements, with 512 bytes transfer:

- without code optimization (-O0):
otg_fifo_write_from_buffer() -> takes 18us
otg_fifo_read_to_buffer() -> takes 110us

- with code optimization (-O2):
otg_fifo_write_from_buffer() -> takes 5us
otg_fifo_read_to_buffer() -> takes 40us

I'm using a GPIO and oscilloscope for measurements. The phenomenon has an explanation of course, the FIFO read code is much more complicate than FIFO write code.

By my opinion - there are some exceptional cases coded inside the loop, which makes it slower. But in fact in case of fast transfers, most of the time these exceptional cases are not relevant: So I tried to optimize a bit the otg_fifo_read_to_buffer() function as follow:

Code: Select all

static void otg_fifo_read_to_buffer(volatile uint32_t *fifop,
                                    uint8_t *buf,
                                    size_t n,
                                    size_t max) {
   uint32_t w;
   size_t cnt = n;

   while(cnt)
   {
      w = *fifop;
      if(cnt <= 4)
      {
         /* Slower but it happens just once! */
         while(cnt)
         {
            /* Take the small parts... */
            *buf++ = (uint8_t)w;
            w >>= 8;
            cnt--;
         }
         if(n > max)
         {
            /* When this happens??? */
            n -= max;
            while(n)
            {
               w = *fifop;
               if(n <= 4)
                  break;
               else
                  n -= 4;
            }
         }
      }
      else
      {
         /* Most of the time we play here */
         *((uint32_t *)buf) = w;
         cnt -= 4;
         buf += 4;
      }
   }
}


with this code I measured the following:

- without code optimization (-O0):
otg_fifo_read_to_buffer() -> takes 24us

- with code optimization (-O2):
otg_fifo_read_to_buffer() -> takes 8us

Which is 5 times faster :)

My point of view is the MSD driver, it uses large blocks almost all the time. Probably such an implementation will not be useful for other cases.

It's sure the best is to use DMA. But there is a lack of documentation according dedicated DMA in OTG_HS. I'm thinking about using of standard DMA in memory to memory mode... But I'm not sure is it possible and how much CPU time we will gain....

I'm open for comments.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Optimization doubts with USB driver

Post by Giovanni »

Hi,

Moving this topic in "bug reports".

Giovanni
Ceco
Posts: 40
Joined: Tue Nov 27, 2012 12:16 pm
Been thanked: 3 times

Re: Optimization doubts with USB driver

Post by Ceco »

Giovanni, currently it not looks like a bug, the original code works just fine. The idea is to achieve highest performance, normally this is not a issue for most of the user cases.

Meanwhile, can you give me a bit more information for your code:

Code: Select all

static void otg_fifo_read_to_buffer(volatile uint32_t *fifop,
                                    uint8_t *buf,
                                    size_t n,
                                    size_t max) {
  uint32_t w = 0;
  size_t i = 0;

  while (i < n) {
    if ((i & 3) == 0){
      w = *fifop;
    }
    if (i < max) {
      *buf++ = (uint8_t)w;
      w >>= 8;
    }
    i++;
  }
}


As I understand, in this code you "expect" a possible case when (n > max) on function calling. When this happens? By my mind, this is a situation when we have a given amount of data inside the IN endpoint (n), but we request to "take" less bytes (max). In this case we are "flushing" the RX FIFO and we are "dumping" the useless data.

Is this correct (what I wrote)?

I found one more interesting point. If the function "otg_fifo_read_to_buffer()" is NOT declared as inline, the compiler do not inline it, even on -O2 optimization. This is strange, since the function looks like a perfect candidate for inline, and I expected that compiler will inline it by itself. When I declared it like a inline manually - I gained a small improvement in execution. In fact it is really small, but the overall write performance on SD card was improved with 1-2%.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Optimization doubts with USB driver

Post by Giovanni »

Hi,

Correct, the function has to empty the FIFO even if the requested size is less than the available data.

About the compiler, it does inline functions regardless of the "inline" specifier.

Giovanni
Ceco
Posts: 40
Joined: Tue Nov 27, 2012 12:16 pm
Been thanked: 3 times

Re: Optimization doubts with USB driver

Post by Ceco »

Giovanni wrote:Correct, the function has to empty the FIFO even if the requested size is less than the available data.


Ok, but how this can happen? I mean what a user case? And why we dump the data, maybe it will be requested with the next function invoking? Sorry if the question is strange, but in my head the dumping of data is something bad, or let's say it softly - exceptional.

Giovanni wrote:About the compiler, it does inline functions regardless of the "inline" specifier.


In the exact case - if there is NO inline directive on function declaration - the compiler DON'T makes the function inline even if a maximal level of optimization is selected. If the function is declared like inline - compiler makes it inline when a maximum level of optimization is selected.

I'm also expecting a different behavior of compiler, but this is the case.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Optimization doubts with USB driver

Post by Giovanni »

It can happen if the host sends more data than the device is waiting for.

Giovanni
Ceco
Posts: 40
Joined: Tue Nov 27, 2012 12:16 pm
Been thanked: 3 times

Re: Optimization doubts with USB driver

Post by Ceco »

Ok, I will leave it as it is. In my implementation it is coded as exceptional case at the end of the loop, so it not affects the performance of the loop at all.

With this small correction the write speed of the MSD driver raised twice, so I'm pretty happy with the results. I will post some report in Mass Storage thread, just for information.

For the moment I will not deal with the DMA. The dedicated DMA is not well documented. A standard DMA channel in memory-to-memory transfer is not so easy to be implemented. The both read and write FIFO functions works in interrupt context. So normally we should use DMA in pooling mode, which is not really cool... For real performance gain, I need to redesign a big part of usb driver - but I don't feel enough knowledge for such a task.

Thanks for the support, Giovani, hope this thread will be useful for future improvement of the USB driver, too.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Optimization doubts with USB driver

Post by Giovanni »

DMA support will be introduced, it is already planned.

It is missing in the current implementation because there are devices with asymmetric peripherals, FS without DMA and HS with DMA.

Giovanni
Ceco
Posts: 40
Joined: Tue Nov 27, 2012 12:16 pm
Been thanked: 3 times

Re: Optimization doubts with USB driver

Post by Ceco »

Super. :D
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Optimization doubts with USB driver

Post by Giovanni »

Hi,

Do you have a final recommended optimization about this? I am trying to close as many tickets as possible before next release.

Giovanni
Post Reply