kernel: scheduling fix for ARM
[minix.git] / benchmarks / unixbench-5.1.2 / src / time-polling.c
blob21fa8b2206186923620b6f19e45756a20c630731
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
9 Extra compile flags:
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.
50 #ifdef UNIXBENCH
51 #define OUT stdout
52 #else
53 #define OUT stderr
54 #endif
55 #include <stdio.h>
56 #include <string.h>
57 #include <sys/time.h>
58 #include <sys/resource.h>
59 #ifdef HAS_POLL
60 # include <sys/poll.h>
61 #endif
62 #ifdef HAS_POLL2
63 # include <linux/poll2.h>
64 #endif
65 #include <unistd.h>
66 #include <errno.h>
67 #include <stdlib.h>
69 #define TRUE 1
70 #define FALSE 0
71 #ifdef UNIXBENCH
72 #define MAX_ITERATIONS 1000
73 #else
74 #define MAX_ITERATIONS 30
75 #endif
76 #define MAX_FDS 40960
77 #define CONST const
78 #define ERRSTRING strerror (errno)
80 typedef int flag;
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
91 is returned.
94 int index;
95 unsigned long word;
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);
105 return (index);
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
116 ignored.
117 [RETURNS] The index of the next set bit. If no more bits are set,
118 <<size>> + 1 is returned.
121 int index, tmp;
122 unsigned long word;
123 unsigned int ul_size = 8 * sizeof (unsigned long);
124 CONST unsigned long *ul_array = array;
126 if (++offset >= size) return (offset);
127 index = offset;
128 /* Jump to the long word containing the next bit */
129 tmp = offset / ul_size;
130 ul_array += tmp;
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
138 position */
139 for (; (word & 1) == 0; word = word >> 1, ++index);
140 return (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);
153 void *info;
156 static int total_bits = 0;
157 struct callback_struct callbacks[MAX_FDS];
160 static void test_func (void *info)
162 ++total_bits;
165 #ifdef HAS_SELECT
166 static void time_select (fd_set *input_fds, fd_set *output_fds,
167 fd_set *exception_fds, int max_fd, int num_iter,
168 long *times)
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.
176 [RETURNS] Nothing.
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);
187 tv.tv_sec = 0;
188 tv.tv_usec = 0;
189 select (max_fd + 1, &i_fds, &o_fds, &e_fds, &tv);
190 for (count = 0; count < num_iter; ++count)
192 total_bits = 0;
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);
197 tv.tv_sec = 0;
198 tv.tv_usec = 0;
199 nready = select (max_fd + 1, &i_fds, &o_fds, &e_fds, &tv);
200 if (nready == -1)
202 fprintf (stderr, "Error selecting\t%s\n", ERRSTRING);
203 exit (2);
205 if (nready < 1)
207 fprintf (stderr, "Error: nready: %d\n", nready);
208 exit (1);
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 */
233 #ifdef HAS_POLL
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.
242 [RETURNS] Nothing.
245 short revents;
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)
254 total_bits = 0;
255 gettimeofday (&time1, NULL);
256 nready = poll (pollfd_array + start_index, num_to_test, 0);
257 if (nready == -1)
259 fprintf (stderr, "Error polling\t%s\n", ERRSTRING);
260 exit (2);
262 if (nready < 1)
264 fprintf (stderr, "Error: nready: %d\n", nready);
265 exit (1);
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;
273 fd = pollfd_ptr->fd;
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 */
289 #ifdef HAS_POLL2
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.
298 [RETURNS] Nothing.
301 short revents;
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)
310 total_bits = 0;
311 gettimeofday (&time1, NULL);
312 nready = poll2 (poll2ifd_array + start_index, poll2ofd_array,
313 num_to_test, 0);
314 if (nready == -1)
316 times[count] = -1;
317 if (errno == ENOSYS) return; /* Must do this first */
318 fprintf (stderr, "Error calling poll2(2)\t%s\n", ERRSTRING);
319 exit (2);
321 if (nready < 1)
323 fprintf (stderr, "Error: nready: %d\n", nready);
324 exit (1);
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)
346 int argc;
347 char *argv[];
349 flag failed = FALSE;
350 flag verbose = FALSE;
351 int first_fd = -1;
352 int fd, max_fd, count, total_fds;
353 int num_to_test, num_active;
354 #ifdef UNIXBENCH
355 int max_iter = 1000;
356 #else
357 int max_iter = 10;
358 #endif
359 #ifdef HAS_SELECT
360 long select_total = 0;
361 fd_set input_fds, output_fds, exception_fds;
362 long select_times[MAX_ITERATIONS];
363 #endif
364 #ifdef HAS_POLL
365 int start_index;
366 long poll_total = 0;
367 struct pollfd pollfd_array[MAX_FDS];
368 long poll_times[MAX_ITERATIONS];
369 #endif
370 #ifdef HAS_POLL2
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];
375 #endif
376 #if 0
377 extern char *sys_errlist[];
378 #endif
380 #ifdef HAS_SELECT
381 FD_ZERO (&input_fds);
382 FD_ZERO (&output_fds);
383 FD_ZERO (&exception_fds);
384 #endif
385 #ifdef HAS_POLL
386 memset (pollfd_array, 0, sizeof pollfd_array);
387 #endif
388 /* Allocate file descriptors */
389 total_fds = 0;
390 max_fd = 0;
391 while (!failed)
393 if ( ( fd = dup (1) ) == -1 )
395 if (errno != EMFILE)
397 fprintf (stderr, "Error dup()ing\t%s\n", ERRSTRING);
398 exit (1);
400 failed = TRUE;
401 continue;
403 if (fd >= MAX_FDS)
405 fprintf (stderr, "File descriptor: %d larger than max: %d\n",
406 fd, MAX_FDS - 1);
407 exit (1);
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;
415 #ifdef HAS_POLL
416 pollfd_array[fd].fd = fd;
417 pollfd_array[fd].events = 0;
418 #endif
419 #ifdef HAS_POLL2
420 poll2ifd_array[fd].fd = fd;
421 poll2ifd_array[fd].events = 0;
422 #endif
424 total_fds = max_fd + 1;
425 /* Process the command-line arguments */
426 if (argc > 5)
428 fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n",
429 stderr);
430 exit (1);
432 if (argc > 1) max_iter = atoi (argv[1]);
433 if (max_iter > MAX_ITERATIONS)
435 fprintf (stderr, "num_iter too large\n");
436 exit (1);
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]);
441 else num_active = 1;
442 if (argc > 4)
444 if (strcmp (argv[4], "-v") != 0)
446 fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n",
447 stderr);
448 exit (1);
450 verbose = TRUE;
453 /* Sanity tests */
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)
459 #ifdef HAS_SELECT
460 FD_SET (fd, &exception_fds);
461 FD_SET (fd, &input_fds);
462 #endif
463 #ifdef HAS_POLL
464 pollfd_array[fd].events = POLLPRI | POLLIN;
465 #endif
466 #ifdef HAS_POLL2
467 poll2ifd_array[fd].events = POLLPRI | POLLIN;
468 #endif
470 for (fd = total_fds - num_active; fd < total_fds; ++fd)
472 #ifdef HAS_SELECT
473 FD_SET (fd, &output_fds);
474 #endif
475 #ifdef HAS_POLL
476 pollfd_array[fd].events |= POLLOUT;
477 #endif
478 #ifdef HAS_POLL2
479 poll2ifd_array[fd].events |= POLLOUT;
480 #endif
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 */
485 #ifdef HAS_SELECT
486 time_select (&input_fds, &output_fds, &exception_fds, max_fd, max_iter,
487 select_times);
488 #endif
489 #ifdef HAS_POLL
490 start_index = total_fds - num_to_test;
491 time_poll (pollfd_array, start_index, num_to_test, max_iter, poll_times);
492 #endif
493 #ifdef HAS_POLL2
494 start_index = total_fds - num_to_test;
495 time_poll2 (poll2ifd_array, start_index, num_to_test, max_iter,
496 poll2_times);
497 #endif
498 /* Now print out all the times */
499 fputs ("All times in microseconds\n", OUT);
500 fputs ("ITERATION\t", OUT);
501 #ifdef HAS_SELECT
502 fprintf (OUT, "%-12s", "select(2)");
503 #endif
504 #ifdef HAS_POLL
505 fprintf (OUT, "%-12s", "poll(2)");
506 #endif
507 #ifdef HAS_POLL2
508 if (poll2_times[0] >= 0) fprintf (OUT, "%-12s", "poll2(2)");
509 #endif
510 for (count = 0; count < max_iter; ++count)
512 if (verbose) fprintf (OUT, "\n%d\t\t", count);
513 #ifdef HAS_SELECT
514 if (verbose) fprintf (OUT, "%-12ld", select_times[count]);
515 select_total += select_times[count];
516 #endif
517 #ifdef HAS_POLL
518 if (verbose) fprintf (OUT, "%-12ld", poll_times[count]);
519 poll_total += poll_times[count];
520 #endif
521 #ifdef HAS_POLL2
522 if ( verbose && (poll2_times[0] >= 0) )
523 fprintf (OUT, "%-12ld", poll2_times[count]);
524 poll2_total += poll2_times[count];
525 #endif
527 fputs ("\n\naverage\t\t", OUT);
528 #ifdef HAS_SELECT
529 fprintf (OUT, "%-12ld", select_total / max_iter);
530 #endif
531 #ifdef HAS_POLL
532 fprintf (OUT, "%-12ld", poll_total / max_iter);
533 #endif
534 #ifdef HAS_POLL2
535 if (poll2_times[0] >= 0)
536 fprintf (OUT, "%-12ld", poll2_total / max_iter);
537 #endif
538 putc ('\n', OUT);
539 fputs ("Per fd\t\t", OUT);
540 #ifdef HAS_SELECT
541 fprintf (OUT, "%-12.2f",
542 (float) select_total / (float) max_iter / (float) num_to_test);
543 #ifdef UNIXBENCH
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);
547 #endif
548 #endif
549 #ifdef HAS_POLL
550 fprintf (OUT, "%-12.2f",
551 (float) poll_total / (float) max_iter / (float) num_to_test);
552 #ifdef UNIXBENCH
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);
556 #endif
557 #endif
558 #ifdef HAS_POLL2
559 if (poll2_times[0] >= 0) {
560 fprintf (OUT, "%-12.2f",
561 (float) poll2_total / (float) max_iter / (float) num_to_test);
562 #ifdef UNIXBENCH
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);
566 #endif
569 #endif
570 fputs ("<- the most important value\n", OUT);
572 exit(0);
573 } /* End Function main */