poll(2) slower than select(2)

I have a program that creates a TCP server socket and listens on it.

When the program accepts a connection from a client, it calls poll(2) repeatedly to see if there is any input available, like this:

for (int i = 0; i < 1000000; i++) {
  struct pollfd fds[] = {{ .fd = clientfd, .events = POLLIN, .revents = 0 }};
  int r = poll(fds, 1, 0);
  if (r < 0) {
    perror("poll");
    exit(1);
  }
}    

On my Intel iMac, this takes about 15 seconds. If I use select(2) instead, as follows, it takes about 550ms.

for (int i = 0; i < 1000000; i++) {
  struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
  fd_set infds;
  FD_ZERO(&infds);
  FD_SET(clientfd, &infds);
  int r = select(1, &infds, 0, 0, &timeout);
  if (r < 0) {
    perror("select");
    exit(1);
  }
}

https://gist.github.com/xrme/cd42d3d753ac00861e439e012366f2cf is a C source file that contains a complete example.

If you're inclined to take a look, please download the file from the gist and do cc poll-test.c and then ./a.out. Connect to it with nc 127.0.0.1 6444 and observe that it will take quite a while. (Activity Monitor will show a large number of "idle wake ups", but I'm not clear what that signifies.)

Recompile with cc -DUSE_SELECT, run ./a.out and connect again, and it will complete in under a second.

Advisability of this usage aside (which is adapted from a much larger system), is there anything here to be done to make poll faster? Other systems I have looked at (FreeBSD, OmniOS, Linux) do not exhibit the same slowdown with poll.

macOS, with its BSD heritage, has always treated poll as a bit of compatibility interface. Still, the result you’re seeing is quite surprising, and I encourage you to file a bug about that. Please post your bug number, just for the record.

However, this is a very unrealistic microbenchmark. Most networking code doesn’t call poll in a tight loop with a zero timeout. Moreover, the semantics of poll, and select for that matter, are really quite bad. You’re likely to see much better results with kqueues.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I made FB15286484 about this issue.

Thank you for your reply.

poll(2) slower than select(2)
 
 
Q