1 /* Programme to test how long it takes to select(2), poll(2) and poll2(2) a
2 large number of file descriptors.
4 Copyright 1997 Richard Gooch rgooch@atnf.csiro.au
5 Distributed under the GNU General Public License.
7 To compile this programme, use gcc -O2 -o time-polling time-polling.c
11 Add -DHAS_SELECT if your operating system has the select(2) system call
12 Add -DHAS_POLL if your operating system has the poll(2) system call
13 Add -DHAS_POLL2 if your operating system has the poll2(2) system call
15 Usage: time-polling [num_iter] [num_to_test] [num_active] [-v]
17 NOTE: on many systems the default limit on file descriptors is less than
18 1024. You should try to increase this limit to 1024 before doing the test.
19 Something like "limit descriptors 1024" or "limit openfiles 1024" should do
20 the trick. On some systems (like IRIX), doing the test on a smaller number
21 gives a *much* smaller time per descriptor, which shows that time taken
22 does not scale linearly with number of descriptors, which is non-optimal.
23 In the tests I've done, I try to use 1024 descriptors.
24 The benchmark results are available at:
25 http://www.atnf.csiro.au/~rgooch/benchmarks.html
26 If you want to contribute results, please email them to me. Please specify
27 if you want to be acknowledged.
30 This program is free software; you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation; either version 2 of the License, or
33 (at your option) any later version.
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details.
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
44 Richard Gooch may be reached by email at rgooch@atnf.csiro.au
45 The postal address is:
46 Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
58 #include <sys/resource.h>
60 # include <sys/poll.h>
63 # include <linux/poll2.h>
72 #define MAX_ITERATIONS 1000
74 #define MAX_ITERATIONS 30
78 #define ERRSTRING strerror (errno)
84 static inline int find_first_set_bit (CONST void *array, int size)
86 static int find_first_set_bit (CONST
void *array
, int size
)
87 /* [SUMMARY] Find the first bit set in a bitfield.
88 <array> A pointer to the bitfield. This must be aligned on a long boundary.
89 <size> The number of bits in the bitfield.
90 [RETURNS] The index of the first set bit. If no bits are set, <<size>> + 1
96 unsigned int ul_size
= 8 * sizeof (unsigned long);
97 CONST
unsigned long *ul_array
= array
;
99 /* Find first word with any bit set */
100 for (index
= 0; (*ul_array
== 0) && (index
< size
);
101 index
+= ul_size
, ++ul_array
);
102 /* Find first bit set in word */
103 for (word
= *ul_array
; !(word
& 1) && (index
< size
);
104 ++index
, word
= word
>> 1);
106 } /* End Function find_first_set_bit */
109 static inline int find_next_set_bit (CONST void *array, int size, int offset)
111 static int find_next_set_bit (CONST
void *array
, int size
, int offset
)
112 /* [SUMMARY] Find the next bit set in a bitfield.
113 <array> A pointer to the bitfield. This must be aligned on a long boundary.
114 <size> The number of bits in the bitfield.
115 <offset> The offset of the current bit in the bitfield. The current bit is
117 [RETURNS] The index of the next set bit. If no more bits are set,
118 <<size>> + 1 is returned.
123 unsigned int ul_size
= 8 * sizeof (unsigned long);
124 CONST
unsigned long *ul_array
= array
;
126 if (++offset
>= size
) return (offset
);
128 /* Jump to the long word containing the next bit */
129 tmp
= offset
/ ul_size
;
131 offset
-= tmp
* ul_size
;
132 if ( (offset
== 0) || (*ul_array
== 0) )
133 return (find_first_set_bit (ul_array
, size
- index
) + index
);
134 /* There is a bit set somewhere in this word */
135 if ( ( (word
= *ul_array
) != 0 ) && ( (word
= word
>> offset
) != 0 ) )
137 /* There is a bit set somewhere in this word at or after the offset
139 for (; (word
& 1) == 0; word
= word
>> 1, ++index
);
142 /* Have to go to subsequent word(s) */
143 index
+= ul_size
- offset
;
144 return (find_first_set_bit (++ul_array
, size
- index
) + index
);
145 } /* End Function find_next_set_bit */
148 struct callback_struct
150 void (*input_func
) (void *info
);
151 void (*output_func
) (void *info
);
152 void (*exception_func
) (void *info
);
156 static int total_bits
= 0;
157 struct callback_struct callbacks
[MAX_FDS
];
160 static void test_func (void *info
)
166 static void time_select (fd_set
*input_fds
, fd_set
*output_fds
,
167 fd_set
*exception_fds
, int max_fd
, int num_iter
,
169 /* [SUMMARY] Time how long it takes to select(2) file descriptors.
170 <input_fds> The input masks.
171 <output_fds> The output masks.
172 <exception_fds> The exception masks.
173 <max_fd> The highest file descriptor in the fd_sets.
174 <num_iter> The number of iterations.
175 <times> The time taken (in microseconds) for each iteration.
179 int fd
, count
, nready
;
180 fd_set i_fds
, o_fds
, e_fds
;
181 struct timeval time1
, time2
, tv
;
183 /* Warm the cache a bit */
184 memcpy (&i_fds
, input_fds
, sizeof i_fds
);
185 memcpy (&o_fds
, output_fds
, sizeof i_fds
);
186 memcpy (&e_fds
, exception_fds
, sizeof i_fds
);
189 select (max_fd
+ 1, &i_fds
, &o_fds
, &e_fds
, &tv
);
190 for (count
= 0; count
< num_iter
; ++count
)
193 gettimeofday (&time1
, NULL
);
194 memcpy (&i_fds
, input_fds
, sizeof i_fds
);
195 memcpy (&o_fds
, output_fds
, sizeof i_fds
);
196 memcpy (&e_fds
, exception_fds
, sizeof i_fds
);
199 nready
= select (max_fd
+ 1, &i_fds
, &o_fds
, &e_fds
, &tv
);
202 fprintf (stderr
, "Error selecting\t%s\n", ERRSTRING
);
207 fprintf (stderr
, "Error: nready: %d\n", nready
);
210 /* Scan the output */
211 for (fd
= find_first_set_bit (&e_fds
, sizeof e_fds
* 8); fd
<= max_fd
;
212 fd
= find_next_set_bit (&e_fds
, sizeof e_fds
* 8, fd
) )
214 (*callbacks
[fd
].exception_func
) (callbacks
[fd
].info
);
216 for (fd
= find_first_set_bit (&i_fds
, sizeof i_fds
* 8); fd
<= max_fd
;
217 fd
= find_next_set_bit (&i_fds
, sizeof i_fds
* 8, fd
) )
219 (*callbacks
[fd
].input_func
) (callbacks
[fd
].info
);
221 for (fd
= find_first_set_bit (&o_fds
, sizeof o_fds
* 8); fd
<= max_fd
;
222 fd
= find_next_set_bit (&o_fds
, sizeof o_fds
* 8, fd
) )
224 (*callbacks
[fd
].output_func
) (callbacks
[fd
].info
);
226 gettimeofday (&time2
, NULL
);
227 times
[count
] = (time2
.tv_sec
- time1
.tv_sec
) * 1000000;
228 times
[count
] += time2
.tv_usec
- time1
.tv_usec
;
230 } /* End Function time_select */
231 #endif /* HAS_SELECT */
234 static void time_poll (struct pollfd
*pollfd_array
, int start_index
,
235 int num_to_test
, int num_iter
, long *times
)
236 /* [SUMMARY] Time how long it takes to poll(2) file descriptors.
237 <pollfd_array> The array of pollfd structures.
238 <start_index> The start index in the array of pollfd structures.
239 <num_to_test> The number of file descriptors to test.
240 <num_iter> The number of iterations.
241 <times> The time taken (in microseconds) for each iteration.
246 int fd
, count
, nready
;
247 struct timeval time1
, time2
;
248 struct pollfd
*pollfd_ptr
, *stop_pollfd
;
250 /* Warm the cache a bit */
251 poll (pollfd_array
+ start_index
, num_to_test
, 0);
252 for (count
= 0; count
< num_iter
; ++count
)
255 gettimeofday (&time1
, NULL
);
256 nready
= poll (pollfd_array
+ start_index
, num_to_test
, 0);
259 fprintf (stderr
, "Error polling\t%s\n", ERRSTRING
);
264 fprintf (stderr
, "Error: nready: %d\n", nready
);
267 stop_pollfd
= pollfd_array
+ start_index
+ num_to_test
;
268 for (pollfd_ptr
= pollfd_array
+ start_index
; TRUE
; ++pollfd_ptr
)
270 if (pollfd_ptr
->revents
== 0) continue;
271 /* Have an active descriptor */
272 revents
= pollfd_ptr
->revents
;
274 if (revents
& POLLPRI
)
275 (*callbacks
[fd
].exception_func
) (callbacks
[fd
].info
);
276 if (revents
& POLLIN
)
277 (*callbacks
[fd
].input_func
) (callbacks
[fd
].info
);
278 if (revents
& POLLOUT
)
279 (*callbacks
[fd
].output_func
) (callbacks
[fd
].info
);
280 if (--nready
== 0) break;
282 gettimeofday (&time2
, NULL
);
283 times
[count
] = (time2
.tv_sec
- time1
.tv_sec
) * 1000000;
284 times
[count
] += time2
.tv_usec
- time1
.tv_usec
;
286 } /* End Function time_poll */
287 #endif /* HAS_POLL */
290 static void time_poll2 (struct poll2ifd
*poll2ifd_array
, int start_index
,
291 int num_to_test
, int num_iter
, long *times
)
292 /* [SUMMARY] Time how long it takes to poll2(2) file descriptors.
293 <poll2ifd_array> The array of poll2ifd structures.
294 <start_index> The start index in the array of pollfd structures.
295 <num_to_test> The number of file descriptors to test.
296 <num_iter> The number of iterations.
297 <times> The time taken (in microseconds) for each iteration.
302 int fd
, count
, nready
, i
;
303 struct timeval time1
, time2
;
304 struct poll2ofd poll2ofd_array
[MAX_FDS
];
306 /* Warm the cache a bit */
307 poll2 (poll2ifd_array
+ start_index
, poll2ofd_array
, num_to_test
, 0);
308 for (count
= 0; count
< num_iter
; ++count
)
311 gettimeofday (&time1
, NULL
);
312 nready
= poll2 (poll2ifd_array
+ start_index
, poll2ofd_array
,
317 if (errno
== ENOSYS
) return; /* Must do this first */
318 fprintf (stderr
, "Error calling poll2(2)\t%s\n", ERRSTRING
);
323 fprintf (stderr
, "Error: nready: %d\n", nready
);
326 for (i
= 0; i
< nready
; ++i
)
328 revents
= poll2ofd_array
[i
].revents
;
329 fd
= poll2ofd_array
[i
].fd
;
330 if (revents
& POLLPRI
)
331 (*callbacks
[fd
].exception_func
) (callbacks
[fd
].info
);
332 if (revents
& POLLIN
)
333 (*callbacks
[fd
].input_func
) (callbacks
[fd
].info
);
334 if (revents
& POLLOUT
)
335 (*callbacks
[fd
].output_func
) (callbacks
[fd
].info
);
337 gettimeofday (&time2
, NULL
);
338 times
[count
] = (time2
.tv_sec
- time1
.tv_sec
) * 1000000;
339 times
[count
] += time2
.tv_usec
- time1
.tv_usec
;
341 } /* End Function time_poll2 */
342 #endif /* HAS_POLL2 */
345 int main (argc
, argv
)
350 flag verbose
= FALSE
;
352 int fd
, max_fd
, count
, total_fds
;
353 int num_to_test
, num_active
;
360 long select_total
= 0;
361 fd_set input_fds
, output_fds
, exception_fds
;
362 long select_times
[MAX_ITERATIONS
];
367 struct pollfd pollfd_array
[MAX_FDS
];
368 long poll_times
[MAX_ITERATIONS
];
371 long poll2_total
= 0;
372 struct poll2ifd poll2ifd_array
[MAX_FDS
];
373 struct poll2ofd poll2ofd_array
[MAX_FDS
];
374 long poll2_times
[MAX_ITERATIONS
];
377 extern char *sys_errlist
[];
381 FD_ZERO (&input_fds
);
382 FD_ZERO (&output_fds
);
383 FD_ZERO (&exception_fds
);
386 memset (pollfd_array
, 0, sizeof pollfd_array
);
388 /* Allocate file descriptors */
393 if ( ( fd
= dup (1) ) == -1 )
397 fprintf (stderr
, "Error dup()ing\t%s\n", ERRSTRING
);
405 fprintf (stderr
, "File descriptor: %d larger than max: %d\n",
409 callbacks
[fd
].input_func
= test_func
;
410 callbacks
[fd
].output_func
= test_func
;
411 callbacks
[fd
].exception_func
= test_func
;
412 callbacks
[fd
].info
= NULL
;
413 if (fd
> max_fd
) max_fd
= fd
;
414 if (first_fd
< 0) first_fd
= fd
;
416 pollfd_array
[fd
].fd
= fd
;
417 pollfd_array
[fd
].events
= 0;
420 poll2ifd_array
[fd
].fd
= fd
;
421 poll2ifd_array
[fd
].events
= 0;
424 total_fds
= max_fd
+ 1;
425 /* Process the command-line arguments */
428 fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n",
432 if (argc
> 1) max_iter
= atoi (argv
[1]);
433 if (max_iter
> MAX_ITERATIONS
)
435 fprintf (stderr
, "num_iter too large\n");
438 if (argc
> 2) num_to_test
= atoi (argv
[2]);
439 else num_to_test
= total_fds
- first_fd
;
440 if (argc
> 3) num_active
= atoi (argv
[3]);
444 if (strcmp (argv
[4], "-v") != 0)
446 fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n",
454 if (num_to_test
> total_fds
- first_fd
) num_to_test
= total_fds
- first_fd
;
455 if (num_active
> total_fds
- first_fd
) num_active
= total_fds
- first_fd
;
456 /* Set activity monitoring flags */
457 for (fd
= total_fds
- num_to_test
; fd
< total_fds
; ++fd
)
460 FD_SET (fd
, &exception_fds
);
461 FD_SET (fd
, &input_fds
);
464 pollfd_array
[fd
].events
= POLLPRI
| POLLIN
;
467 poll2ifd_array
[fd
].events
= POLLPRI
| POLLIN
;
470 for (fd
= total_fds
- num_active
; fd
< total_fds
; ++fd
)
473 FD_SET (fd
, &output_fds
);
476 pollfd_array
[fd
].events
|= POLLOUT
;
479 poll2ifd_array
[fd
].events
|= POLLOUT
;
482 fprintf (OUT
, "Num fds: %d, polling descriptors %d-%d\n",
483 total_fds
, total_fds
- num_to_test
, max_fd
);
484 /* First do all the tests, then print the results */
486 time_select (&input_fds
, &output_fds
, &exception_fds
, max_fd
, max_iter
,
490 start_index
= total_fds
- num_to_test
;
491 time_poll (pollfd_array
, start_index
, num_to_test
, max_iter
, poll_times
);
494 start_index
= total_fds
- num_to_test
;
495 time_poll2 (poll2ifd_array
, start_index
, num_to_test
, max_iter
,
498 /* Now print out all the times */
499 fputs ("All times in microseconds\n", OUT
);
500 fputs ("ITERATION\t", OUT
);
502 fprintf (OUT
, "%-12s", "select(2)");
505 fprintf (OUT
, "%-12s", "poll(2)");
508 if (poll2_times
[0] >= 0) fprintf (OUT
, "%-12s", "poll2(2)");
510 for (count
= 0; count
< max_iter
; ++count
)
512 if (verbose
) fprintf (OUT
, "\n%d\t\t", count
);
514 if (verbose
) fprintf (OUT
, "%-12ld", select_times
[count
]);
515 select_total
+= select_times
[count
];
518 if (verbose
) fprintf (OUT
, "%-12ld", poll_times
[count
]);
519 poll_total
+= poll_times
[count
];
522 if ( verbose
&& (poll2_times
[0] >= 0) )
523 fprintf (OUT
, "%-12ld", poll2_times
[count
]);
524 poll2_total
+= poll2_times
[count
];
527 fputs ("\n\naverage\t\t", OUT
);
529 fprintf (OUT
, "%-12ld", select_total
/ max_iter
);
532 fprintf (OUT
, "%-12ld", poll_total
/ max_iter
);
535 if (poll2_times
[0] >= 0)
536 fprintf (OUT
, "%-12ld", poll2_total
/ max_iter
);
539 fputs ("Per fd\t\t", OUT
);
541 fprintf (OUT
, "%-12.2f",
542 (float) select_total
/ (float) max_iter
/ (float) num_to_test
);
544 fprintf (stderr
, "lps\t%.2f\t%.1f\n",
545 1000000 * (float) max_iter
* (float) num_to_test
546 / (float) select_total
, (float)select_total
/ 1000000);
550 fprintf (OUT
, "%-12.2f",
551 (float) poll_total
/ (float) max_iter
/ (float) num_to_test
);
553 fprintf (stderr
, "lps\t%.2f\t%.1f\n",
554 1000000 * (float) max_iter
* (float) num_to_test
555 / (float) poll_total
, (float)poll_total
/ 1000000);
559 if (poll2_times
[0] >= 0) {
560 fprintf (OUT
, "%-12.2f",
561 (float) poll2_total
/ (float) max_iter
/ (float) num_to_test
);
563 fprintf (stderr
, "lps\t%.2f\t%.1f\n",
564 1000000 * (float) max_iter
* (float) num_to_test
565 / (float) poll2_total
, (float)poll2_total
/ 1000000);
570 fputs ("<- the most important value\n", OUT
);
573 } /* End Function main */