gvanem / Watt-32

Watt-32 TCP/IP library and samples.
https://www.watt-32.net/
18 stars 8 forks source link

Improve `poll()`/`select()` #87

Closed jwt27 closed 1 year ago

jwt27 commented 1 year ago

Now poll() no longer calls select_s(), so the whole fd_set dance is avoided. Should be significantly faster, and saves a good 30KB (!) of stack space.

The POLLNVAL/POLLHUP/POLLERR flags are now also used, in accordance with the Linux manpage.

gvanem commented 1 year ago

The CI completed fine now. This looks effin awesome. So poll.c now gets removed since it needs internals in select.c or what? Seems OK by me.

jwt27 commented 1 year ago

The CI completed fine now. This looks effin awesome.

Thanks!

So poll.c now gets removed since it needs internals in select.c or what? Seems OK by me.

Yes, I moved poll() to select.c since there is a lot of shared code.

I did some benchmarking by connecting to an invalid TCP port, and then counting the number of calls to poll() while waiting for the 30 second timeout to expire. Like so:

  int i = 0;
  struct pollfd pfd;
  do
  {
    pfd.fd = fd;
    pfd.events = POLLOUT;
    pfd.revents = 0;
    if (poll(&pfd, 1, 0) < 0)
    {
      perror("poll()");
      goto fail;
    }
    ++i;
  } while (pfd.revents == 0);

The result is somewhat surprising:

- old poll() via select_s():
42498
33644
19915
76479
75630
63016
65807
60339
47633
50679

- new poll():
108432
104442
107909
107820
108115
108166
108024
106090
108581
108567

So the select_s() code is highly variable for some reason. Might be worth looking into why that is. The good news is, the new poll() is more consistent, and up to 445% faster :)

gvanem commented 1 year ago

while waiting for the 30 second timeout to expire

Those numbers are i after the loops has finished? I assume those 30 sec are set in some test-program of your, which protocol? And you're sure 30 sec elapsed in both tests?

BTW, from Linux' man select:

 On Linux, select() modifies timeout to reflect the amount of time not slept;

(or remaining) I implemented that once. Hope this still holds with this PR.

jwt27 commented 1 year ago

while waiting for the 30 second timeout to expire

Those numbers are i after the loops has finished? I assume those 30 sec are set in some test-program of your, which protocol? And you're sure 30 sec elapsed in both tests?

It just waits for socket->nb_timer to expire (from here). Accuracy depends on the rdtsc code in gettimeofday2(), but I thought 10 runs should produce a usable average.

BTW, from Linux' man select:

 On Linux, select() modifies timeout to reflect the amount of time not slept;

(or remaining) I implemented that once. Hope this still holds with this PR.

Should still work, I didn't touch it.