+ if (end.tv_usec < start.tv_usec) {
+ end.tv_usec += 1000000;
+ end.tv_sec--;
+ }
+ diff.tv_sec = end.tv_sec - start.tv_sec;
+ diff.tv_usec = end.tv_usec - start.tv_usec;
+ return diff;
+}
+
+int main(int argc, char *argv[])
+{
+ struct timeval diff;
+ unsigned int i, num_ops[argc], hashsize[argc], tdb_flags[argc], open_flags[argc];
+ struct op *op[argc];
+ int fds[2];
+
+ if (argc < 3)
+ errx(1, "Usage: %s <tdbfile> <tracefile>...", argv[0]);
+
+ pipes = talloc_array(NULL, struct pipe, argc - 1);
+ for (i = 0; i < argc - 2; i++) {
+ printf("Loading tracefile %s...", argv[2+i]);
+ fflush(stdout);
+ op[i] = load_tracefile(argv[2+i], &num_ops[i], &hashsize[i],
+ &tdb_flags[i], &open_flags[i]);
+ if (pipe(pipes[i].fd) != 0)
+ err(1, "creating pipe");
+ printf("done\n");
+ }
+
+ printf("Calculating inter-dependencies...");
+ fflush(stdout);
+ derive_dependencies(argv+2, op, num_ops, i);
+ printf("done\n");
+
+ /* Don't fork for single arg case: simple debugging. */
+ if (argc == 3) {
+ struct tdb_context *tdb;
+ tdb = tdb_open_ex(argv[1], hashsize[0], tdb_flags[0]|TDB_NOSYNC,
+ open_flags[0], 0600, NULL, hash_key);
+ printf("Single threaded run...");
+ fflush(stdout);
+
+ run_ops(tdb, pipes[0].fd[0], argv+2, op, 0, 1, num_ops[0],
+ false);
+ check_deps(argv[2], op[0], num_ops[0]);
+
+ printf("done\n");
+ exit(0);
+ }
+
+ if (pipe(fds) != 0)
+ err(1, "creating pipe");
+
+#if TRAVERSALS_TAKE_TRANSACTION_LOCK
+ if (pipe(pipes[argc-2].fd) != 0)
+ err(1, "creating pipe");
+ backoff_fd = pipes[argc-2].fd[1];
+ set_nonblock(pipes[argc-2].fd[1]);
+ set_nonblock(pipes[argc-2].fd[0]);
+#endif
+
+ do {
+ diff = run_test(argv, num_ops, hashsize, tdb_flags, open_flags,
+ op, fds);
+ } while (handle_backoff(op, pipes[argc-2].fd[0]));
+