Index: benchmark/io/readv.cfa
===================================================================
--- benchmark/io/readv.cfa	(revision cd021085d1b1fd9053f0376b7616c1aaaf7600d8)
+++ benchmark/io/readv.cfa	(revision d9265a22393bce8b8a41fc483ec05caf9784f79c)
@@ -69,82 +69,49 @@
 
 int main(int argc, char * argv[]) {
-	BENCH_DECL
 	unsigned num_io = 1;
-	io_context_params params;
 	int file_flags = 0;
 	unsigned sublen = 16;
 
-	arg_loop:
-	for(;;) {
-		static struct option options[] = {
-			BENCH_OPT_LONG
-			{"bufsize",       required_argument, 0, 'b'},
-			{"submitthread",  no_argument      , 0, 's'},
-			{"eagersubmit",   no_argument      , 0, 'e'},
-			{"kpollsubmit",   no_argument      , 0, 'k'},
-			{"kpollcomplete", no_argument      , 0, 'i'},
-			{"fixed-files",   no_argument      , 0, 'f'},
-			{"open-direct",   no_argument      , 0, 'o'},
-			{"submitlength",  required_argument, 0, 'l'},
-			{0, 0, 0, 0}
-		};
+	bool subthrd = false;
+	bool subeagr = false;
+	bool odirect = false;
+	bool kpollsb = false;
+	bool kpollcp = false;
 
-		int idx = 0;
-		int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "b:sekil:", options, &idx);
+	cfa_option opt[] = {
+		BENCH_OPT_CFA
+		{'b', "bufsize",       "Number of bytes to read per request", buflen},
+		{'s', "submitthread",  "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue},
+		{'e', "eagersubmit",   "If set, cluster submits I/O eagerly but still aggregates submits", subeagr, parse_settrue},
+		{'f', "fixed-files",   "Pre-register files with the io_contexts", fixed_file, parse_settrue},
+		{'o', "open-direct",   "Open files with O_DIRECT flag, bypassing the file cache", odirect, parse_settrue},
+		{'k', "kpollsubmit",   "If set, cluster uses an in kernel thread to poll submission, implies -f, requires elevated permissions", kpollsb, parse_settrue},
+		{'i', "kpollcomplete", "If set, cluster polls fds for completions instead of relying on interrupts to get notifications, implies -o", kpollcp, parse_settrue},
+		{'l', "submitlength",  "Size of the buffer that stores ready submissions", sublen},
+		{'n', "numcontexts",   "Number of io_contexts to the cluster", num_io},
+	};
+	int opt_cnt = sizeof(opt) / sizeof(cfa_option);
 
-		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 's':
-				params.poller_submits = true;
-				break;
-			case 'e':
-				params.eager_submits = true;
-				break;
-			case 'k':
-				params.poll_submit = true;
-			case 'f':
-				fixed_file = true;
-				break;
-			case 'i':
-				params.poll_complete = true;
-			case 'o':
-				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, "  -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);
+	char **left;
+	parse_args( opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
+
+	if(kpollcp || odirect) {
+		if( (buflen % 512) != 0 ) {
+			fprintf(stderr, "Buffer length must be a multiple of 512 when using O_DIRECT, was %lu\n\n", buflen);
+			print_args_usage(opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", true);
 		}
 	}
 
+	io_context_params params;
+
+	if( subthrd ) params.poller_submits = true;
+	if( subeagr ) params.eager_submits  = true;
+	if( kpollsb ) params.poll_submit    = true;
+	if( kpollcp ) params.poll_complete  = true;
+
 	if(params.poll_submit  ) fixed_file = true;
-	if(params.poll_complete) file_flags |= O_DIRECT;
+	if(params.poll_complete) odirect = true;
+
+	if(odirect) file_flags |= O_DIRECT;
 
 	int lfd = open(__FILE__, file_flags);
