| 1 | #include <assert.h>
 | 
|---|
| 2 | #include <stdlib.h>
 | 
|---|
| 3 | #include <stdio.h>
 | 
|---|
| 4 | #include <string.h>
 | 
|---|
| 5 | 
 | 
|---|
| 6 | extern "C" {
 | 
|---|
| 7 |         #include <locale.h>
 | 
|---|
| 8 |         #include <getopt.h>
 | 
|---|
| 9 |         #include <fcntl.h>
 | 
|---|
| 10 |         #include <sys/uio.h>
 | 
|---|
| 11 | }
 | 
|---|
| 12 | 
 | 
|---|
| 13 | #include <unistd.h>
 | 
|---|
| 14 | 
 | 
|---|
| 15 | #include <pthread.h>
 | 
|---|
| 16 | 
 | 
|---|
| 17 | #include "../benchcltr.hfa"
 | 
|---|
| 18 | 
 | 
|---|
| 19 | int fd;
 | 
|---|
| 20 | volatile bool run = false;
 | 
|---|
| 21 | volatile size_t count = 0;
 | 
|---|
| 22 | 
 | 
|---|
| 23 | unsigned long int buflen = 50;
 | 
|---|
| 24 | 
 | 
|---|
| 25 | void * reader_main( void * arg ) {
 | 
|---|
| 26 |       pthread_barrier_wait( (pthread_barrier_t*) arg );
 | 
|---|
| 27 |         /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) );
 | 
|---|
| 28 | 
 | 
|---|
| 29 |         char data[buflen];
 | 
|---|
| 30 |         struct iovec iov = { data, buflen };
 | 
|---|
| 31 | 
 | 
|---|
| 32 |         while(__atomic_load_n(&run, __ATOMIC_RELAXED)) {
 | 
|---|
| 33 |                 int r = preadv2(fd, &iov, 1, 0, 0);
 | 
|---|
| 34 |                 if(r < 0) {
 | 
|---|
| 35 |                   fprintf(stderr, "%s\n", strerror(-r));
 | 
|---|
| 36 |                   abort();
 | 
|---|
| 37 |             }
 | 
|---|
| 38 | 
 | 
|---|
| 39 |                 __atomic_fetch_add( &count, 1, __ATOMIC_SEQ_CST );
 | 
|---|
| 40 |         }
 | 
|---|
| 41 | 
 | 
|---|
| 42 |       return NULL;
 | 
|---|
| 43 | }
 | 
|---|
| 44 | 
 | 
|---|
| 45 | int main(int argc, char * argv[]) {
 | 
|---|
| 46 |         unsigned flags = 0;
 | 
|---|
| 47 |         unsigned sublen = 16;
 | 
|---|
| 48 | 
 | 
|---|
| 49 |       setlocale(LC_ALL, "");
 | 
|---|
| 50 | 
 | 
|---|
| 51 |         for(;;) {
 | 
|---|
| 52 |                 static struct option options[] = {
 | 
|---|
| 53 |                         BENCH_OPT_LONG
 | 
|---|
| 54 |                         {"polled-io",    required_argument, 0, 'i'},
 | 
|---|
| 55 |                         {"bufsize",      required_argument, 0, 'b'},
 | 
|---|
| 56 |                         {0, 0, 0, 0}
 | 
|---|
| 57 |                 };
 | 
|---|
| 58 | 
 | 
|---|
| 59 |                 int idx = 0;
 | 
|---|
| 60 |                 int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "ib:", options, &idx);
 | 
|---|
| 61 | 
 | 
|---|
| 62 |                 const char * arg = optarg ? optarg : "";
 | 
|---|
| 63 |                 char * end;
 | 
|---|
| 64 |                 switch(opt) {
 | 
|---|
| 65 |                         // Exit Case
 | 
|---|
| 66 |                         case -1:
 | 
|---|
| 67 |                                 goto arg_loop;
 | 
|---|
| 68 |                         BENCH_OPT_CASE
 | 
|---|
| 69 |                         case 'i':
 | 
|---|
| 70 |                                 flags |= O_DIRECT;
 | 
|---|
| 71 |                                 break;
 | 
|---|
| 72 |                         case 'b':
 | 
|---|
| 73 |                                 buflen = strtoul(arg, &end, 10);
 | 
|---|
| 74 |                                 if(*end != '\0' && buflen < 10) {
 | 
|---|
| 75 |                                         fprintf(stderr, "Buffer size must be at least 10, was %s\n", arg);
 | 
|---|
| 76 |                                         goto usage;
 | 
|---|
| 77 |                                 }
 | 
|---|
| 78 |                                 break;
 | 
|---|
| 79 |                         default: /* ? */
 | 
|---|
| 80 |                                 fprintf(stderr, "%d\n", opt);
 | 
|---|
| 81 |                         usage:
 | 
|---|
| 82 |                                 bench_usage( argv );
 | 
|---|
| 83 |                                 fprintf( stderr, "  -i, --polled-io          If set opens the file with O_DIRECT\n" );
 | 
|---|
| 84 |                                 fprintf( stderr, "  -b, --buflen=SIZE        Number of bytes to read per request\n" );
 | 
|---|
| 85 |                                 exit(EXIT_FAILURE);
 | 
|---|
| 86 |                 }
 | 
|---|
| 87 |         }
 | 
|---|
| 88 |       arg_loop:
 | 
|---|
| 89 | 
 | 
|---|
| 90 |         fd = open(__FILE__, flags);
 | 
|---|
| 91 |         if(fd < 0) {
 | 
|---|
| 92 |                 fprintf(stderr, "Could not open source file\n");
 | 
|---|
| 93 |                 exit(EXIT_FAILURE);
 | 
|---|
| 94 |         }
 | 
|---|
| 95 | 
 | 
|---|
| 96 |         printf("Running %d threads, reading %lu bytes each, over %d processors for %f seconds\n", nthreads, buflen, nprocs, duration);
 | 
|---|
| 97 | 
 | 
|---|
| 98 |         {
 | 
|---|
| 99 |                 uint64_t start, end;
 | 
|---|
| 100 |                 {
 | 
|---|
| 101 |                         pthread_barrier_t barrier;
 | 
|---|
| 102 |                   pthread_barrier_init(&barrier, NULL, nthreads + 1);
 | 
|---|
| 103 |                         {
 | 
|---|
| 104 |                                 pthread_t threads[nthreads];
 | 
|---|
| 105 |                         for(int i = 0; i < nthreads; i++) {
 | 
|---|
| 106 |                                 pthread_attr_t attr;
 | 
|---|
| 107 |                               pthread_attr_init( &attr );
 | 
|---|
| 108 |                               pthread_create( &threads[i], &attr, reader_main, &barrier );
 | 
|---|
| 109 |                         }
 | 
|---|
| 110 | 
 | 
|---|
| 111 |                                 printf("Starting\n");
 | 
|---|
| 112 |                                 bool is_tty = isatty(STDOUT_FILENO);
 | 
|---|
| 113 |                                 start = timeHiRes();
 | 
|---|
| 114 |                                 run = true;
 | 
|---|
| 115 | 
 | 
|---|
| 116 |                                 pthread_barrier_wait( &barrier );
 | 
|---|
| 117 |                                 wait_duration(duration, start, end, is_tty);
 | 
|---|
| 118 | 
 | 
|---|
| 119 |                                 run = false;
 | 
|---|
| 120 |                                 end = timeHiRes();
 | 
|---|
| 121 |                                 printf("\nDone\n");
 | 
|---|
| 122 | 
 | 
|---|
| 123 |                         for(int i = 0; i < nthreads; i++) {
 | 
|---|
| 124 |                               void * ret;
 | 
|---|
| 125 |                               pthread_join( threads[i], &ret );
 | 
|---|
| 126 |                         }
 | 
|---|
| 127 |                         }
 | 
|---|
| 128 |                   pthread_barrier_destroy(&barrier);
 | 
|---|
| 129 |                 }
 | 
|---|
| 130 |                 printf("Took %'ld ms\n", to_miliseconds(end - start));
 | 
|---|
| 131 |                 printf("Total reads      : %'15zu\n", count);
 | 
|---|
| 132 |                 printf("Reads per second : %'18.2lf\n", ((double)count) / to_fseconds(end - start));
 | 
|---|
| 133 |                 printf("Total read size  : %'15zu\n", buflen * count);
 | 
|---|
| 134 |                 printf("Bytes per second : %'18.2lf\n", ((double)count * buflen) / to_fseconds(end - start));
 | 
|---|
| 135 |         }
 | 
|---|
| 136 | 
 | 
|---|
| 137 |         close(fd);
 | 
|---|
| 138 | }
 | 
|---|