lars_the_bear
Posts: 204
Joined: Thu Jan 28, 2021 8:13 pm
Contact: Website

Why is putchar() so slow?

Sun May 09, 2021 7:08 am

Hi

I'm porting a program that does a lot of character-by-character output. I've found that the Pico SDK's built-in putchar() is comparatively slow (with USB). For example, this code:

Code: Select all

  for (int i = 0; i < 200; i++)
      {
      printf ("%d 123456890111111234568902345689023456890234568902345689023456890\n", i);

      for (int j = 0; j < 69; j++)
        ; // Do nothing
      }
runs 15-20 times faster than this code:

Code: Select all

  for (int i = 0; i < 200; i++)
      {
      for (int j = 0; j < 70; j++)
        {
        putchar ('x');
        }
      putchar ('\n');
      }
even though I've tried to make them do the same overall amount of work, and they output the same number of characters. I looked at the implementation of stdio_usb_out_chars(), and there seems to be a fair amount of logic that will be repeated on every character, if characters are output one at a time. I don't know if the slowness is in that logic, in the TinyUSB library, or is an inherent limitation of the way USB-serial works. For all I know, there's some framing in the USB protocol that means that a single character actually takes as long to transmit as many characters.

I really need to find a way around this. If the limitation _isn't_ in USB itself, it would be nice if there were a way, using SDK functions, to output a single character without all the other logic. If the problem is in USB, then the only solution I can think of is to buffer characters myself, and output them in batches. This would require implementing some sort of timer interrupt to flush the buffer is there is no output for a specific period of time. The logic is slightly fiddly, and it would be nice to have to implement it.

Can anybody explain what's going on here, and whether there's likely to be a way to do character-by-character output at reasonable speed, without buffering it in m own code?

Kevin.

danjperron
Posts: 3792
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Why is putchar() so slow?

Sun May 09, 2021 11:04 am

Maybe because a printf will send a packet of bytes on the USB and the put_char will send a packet with only one byte.

I.M.O. Handshake transaction on USB is the culprid!

Try to buffer your single char and use puts or fwrite if you need to send NULL.

incognitum
Posts: 756
Joined: Tue Oct 30, 2018 3:34 pm

Re: Why is putchar() so slow?

Sun May 09, 2021 12:30 pm

Just modify SDK code to only call tud_cdc_write_flush() on \n instead of on any write, to use tinyusb's buffering?

WestfW
Posts: 83
Joined: Tue Nov 01, 2011 9:56 pm

Re: Why is putchar() so slow?

Mon May 10, 2021 7:01 pm

Needs some (generalized) Nagle Algorithm.
https://en.wikipedia.org/wiki/Nagle%27s_algorithm
(briefly: "buffer small writes if a transmission is already in progress.")

Return to “SDK”