#define _GNU_SOURCE #include #include #include extern "C" { #include #include #include #include } #include #include #include #include #include #include #include "../benchcltr.hfa" extern bool traceHeapOn(); extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); extern ssize_t cfa_preadv2_fixed(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); extern void register_fixed_files( cluster &, int *, unsigned count ); int fd; volatile bool run = false; volatile size_t count = 0; unsigned long int buflen = 50; bool fixed_file = false; thread __attribute__((aligned(128))) Reader {}; void ?{}( Reader & this ) { ((thread&)this){ "Reader Thread", *the_benchmark_cluster }; } int do_read(int fd, struct iovec * iov) { if(fixed_file) { return cfa_preadv2_fixed(fd, iov, 1, 0, 0); } else { return cfa_preadv2(fd, iov, 1, 0, 0); } } void main( Reader & ) { park( __cfaabi_dbg_ctx ); /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) ); char data[buflen]; struct iovec iov = { data, buflen }; while(__atomic_load_n(&run, __ATOMIC_RELAXED)) { int r = do_read(fd, &iov); if(r < 0) abort("%s\n", strerror(-r)); __atomic_fetch_add( &count, 1, __ATOMIC_SEQ_CST ); } } int main(int argc, char * argv[]) { BENCH_DECL unsigned flags = 0; int file_flags = 0; unsigned sublen = 16; arg_loop: for(;;) { static struct option options[] = { BENCH_OPT_LONG {"bufsize", required_argument, 0, 'b'}, {"userthread", no_argument , 0, 'u'}, {"submitthread", no_argument , 0, 's'}, {"eagersubmit", no_argument , 0, 'e'}, {"kpollsubmit", no_argument , 0, 'k'}, {"kpollcomplete", no_argument , 0, 'i'}, {"submitlength", required_argument, 0, 'l'}, {0, 0, 0, 0} }; int idx = 0; int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "b:usekil:", options, &idx); const char * arg = optarg ? optarg : ""; char * end; switch(opt) { // Exit Case case -1: break arg_loop; BENCH_OPT_CASE case 'b': buflen = strtoul(arg, &end, 10); if(*end != '\0' && buflen < 10) { fprintf(stderr, "Buffer size must be at least 10, was %s\n", arg); goto usage; } break; case 'u': flags |= CFA_CLUSTER_IO_POLLER_USER_THREAD; break; case 's': flags |= CFA_CLUSTER_IO_POLLER_THREAD_SUBMITS; break; case 'e': flags |= CFA_CLUSTER_IO_EAGER_SUBMITS; break; case 'k': flags |= CFA_CLUSTER_IO_KERNEL_POLL_SUBMITS; fixed_file = true; break; case 'i': flags |= CFA_CLUSTER_IO_KERNEL_POLL_COMPLETES; file_flags |= O_DIRECT; break; case 'l': sublen = strtoul(arg, &end, 10); if(*end != '\0' && sublen < 16) { fprintf(stderr, "Submit length must be at least 16, was %s\n", arg); goto usage; } flags |= (sublen << CFA_CLUSTER_IO_BUFFLEN_OFFSET); break; default: /* ? */ fprintf(stderr, "%d\n", opt); usage: bench_usage( argv ); fprintf( stderr, " -b, --buflen=SIZE Number of bytes to read per request\n" ); fprintf( stderr, " -u, --userthread If set, cluster uses user-thread to poll I/O\n" ); fprintf( stderr, " -s, --submitthread If set, cluster uses polling thread to submit I/O\n" ); fprintf( stderr, " -e, --eagersubmit If set, cluster submits I/O eagerly but still aggregates submits\n" ); fprintf( stderr, " -k, --kpollsubmit If set, cluster uses IORING_SETUP_SQPOLL\n" ); fprintf( stderr, " -i, --kpollcomplete If set, cluster uses IORING_SETUP_IOPOLL\n" ); fprintf( stderr, " -l, --submitlength=LEN Max number of submitions that can be submitted together\n" ); exit(EXIT_FAILURE); } } int lfd = open(__FILE__, file_flags); if(lfd < 0) { fprintf(stderr, "Could not open source file\n"); exit(EXIT_FAILURE); } printf("Running %d threads, reading %lu bytes each, over %d processors for %f seconds\n", nthreads, buflen, nprocs, duration); { Time start, end; BenchCluster cl = { flags, CFA_STATS_READY_Q | CFA_STATS_IO }; if(fixed_file) { fd = 0; register_fixed_files( cl.self, &lfd, 1 ); } else { fd = lfd; } { BenchProc procs[nprocs]; { Reader threads[nthreads]; printf("Starting\n"); bool is_tty = isatty(STDOUT_FILENO); start = getTimeNsec(); run = true; for(i; nthreads) { unpark( threads[i] __cfaabi_dbg_ctx2 ); } wait(duration, start, end, is_tty); run = false; end = getTimeNsec(); printf("\nDone\n"); } } printf("Took %'ld ms\n", (end - start)`ms); printf("Total reads : %'15zu\n", count); printf("Reads per second : %'18.2lf\n", ((double)count) / (end - start)`s); printf("Total read size : %'15zu\n", buflen * count); printf("Bytes per second : %'18.2lf\n", ((double)count * buflen) / (end - start)`s); } close(lfd); }