summaryrefslogtreecommitdiff
path: root/ioreplay/src/main.c
diff options
context:
space:
mode:
authorPaul Bütow <pbuetow@mimecast.com>2018-03-01 11:21:26 +0000
committerPaul Bütow <pbuetow@mimecast.com>2018-03-01 11:21:26 +0000
commit56f8cdff9aaa9bf00c5dc9441a7569374f2cbafb (patch)
treeb5b440b504b9879e241733fa38d19089fb3377b2 /ioreplay/src/main.c
initial commit0.1
Diffstat (limited to 'ioreplay/src/main.c')
-rw-r--r--ioreplay/src/main.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/ioreplay/src/main.c b/ioreplay/src/main.c
new file mode 100644
index 0000000..4a65de3
--- /dev/null
+++ b/ioreplay/src/main.c
@@ -0,0 +1,275 @@
+// Copyright 2018 Mimecast Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @file main.c
+ * @author Paul Buetow
+ *
+ * @brief The entry point of the I/O Replay program.
+ */
+
+#include <signal.h>
+#include <fcntl.h>
+
+#include "capture/capture.h"
+#include "cleanup/cleanup.h"
+#include "generate/generate.h"
+#include "init/init.h"
+#include "mounts.h"
+#include "options.h"
+#include "replay/replay.h"
+#include "utests.h"
+#include "utils/utils.h"
+
+/**
+ * @brief Do some architecture checks
+ *
+ * To ensure that I/O replay works correctly we have to check whether some
+ * data types are atomic or not. This is what this function does!
+ */
+static void _arch_check_atomic(void)
+{
+ if (sizeof(int) > sizeof(sig_atomic_t)) {
+ Error("int data type is not atomic on this architecture: %ld > %ld",
+ sizeof(int), sizeof(sig_atomic_t));
+
+ } else if (sizeof(bool) > sizeof(sig_atomic_t)) {
+ Error("bool data type is not atomic on this architecture: %ld > %ld",
+ sizeof(bool), sizeof(sig_atomic_t));
+ }
+}
+
+/**
+ * @brief Prints out version and copyright information
+ */
+static void _print_version(void)
+{
+ Put("This is I/O Replay %s - %s", IOREPLAY_VERSION, IOREPLAY_COPYRIGHT);
+}
+
+/**
+ * @brief Print the synopsis
+ */
+static void _print_synopsis(void)
+{
+ _print_version();
+
+ Put("Synopsis:");
+ Put("\tioreplay -c io.capture [-x PID] [-m MODULE]");
+ Put("\tioreplay -c io.capture -r io.replay [-n str] [-u str] [-w str]");
+ Put("\tioreplay -i io.replay");
+ Put("\tioreplay -r io.replay [-p #] [-t #] [-D] [-s #]");
+ Put("\tioreplay -R io.replay [-p #] [-t #] [-D] [-s #]");
+ Put("\tioreplay -d");
+ Put("\tioreplay -P");
+ Put("\tioreplay -T [-n NAME]");
+ Put("\tioreplay -V");
+}
+
+/**
+ * @brief Print a brief help
+ */
+static void _print_help(void)
+{
+ _print_synopsis();
+
+ Put("Help:");
+ Put("\t-d Drop all Linux/FS caches and exit ioreplay");
+ Put("\t-D Don't drop all caches (in conjunction with -r/-R):");
+ Put("\t-s SPEED The speed factor (default: 0 [as fast as possible])");
+ Put("\t-h Print this help");
+ Put("\t-c FILE The capture file");
+ Put("\t-n NAME The name (default: test0)");
+ Put("\t-u USER The test run user (default: mcuser)");
+ Put("\t-p #WORKERS Amount of of parallel worker processes (default: 4)");
+ Put("\t-t #THREADS Threads per worker process (default: 128)");
+ Put("\t-i REPLAYFILE The replay file to be initialised");
+ Put("\t-r REPLAYFILE The replay file to be replayed");
+ Put("\t-R REPLAYFILE Init and replay in one run (-i and -r combined)");
+ Put("\t-S STATSFILE Write a stats file at the end of a test");
+ Put("\t-T Trash data directories");
+ Put("\t-P Purge all trash directories of all tests)");
+ Put("\t-V Print I/O replay program version");
+ Put("\t-w WD_BASE The working directory's base path");
+ Put("\t (default: /usr/local/ioreplay)");
+ Put("\t-x PID To specify a process ID (in conjunction with -c)");
+ Put("\t-m MODULE To specify a module (in conjunction with -c)");
+ Put("\nExample (run these commands one after another):");
+ Put("\t 1.) sudo ioreplay -c io.capture");
+ Put("\t 2.) sudo ioreplay -r io.replay -c io.capture -u paul -n test1");
+ Put("\t 3.) sudo ioreplay -i io.replay");
+ Put("\t 4.) sudo ioreplay -r io.replay -S");
+}
+
+/**
+ * @brief I/O Replay's entry point
+ *
+ * Not much more to document here though!
+ * @return The exit code
+ */
+int main(int argc, char **argv)
+{
+ _arch_check_atomic();
+ status_e ret = UNKNOWN;
+
+ bool dont_drop_caches = false;
+ options_s *opts = options_new();
+ int opt = 0;
+
+ while ((opt = getopt(argc, argv, "Vr:R:S:c:u:i:hw:n:dDs:w:p:t:UPTx:m:")) != -1) {
+ switch (opt) {
+ case 'U':
+ utests_run();
+ Cleanup(SUCCESS);
+ break;
+ case 'V':
+ _print_version();
+ Cleanup(SUCCESS);
+ break;
+ case 'd':
+ drop_caches();
+ Cleanup(SUCCESS);
+ break;
+ case 'D':
+ dont_drop_caches = true;
+ break;
+ case 'c':
+ opts->capture_file = absolute_path(optarg);
+ Put("Capture file: %s", opts->capture_file);
+ break;
+ case 'P':
+ opts->purge = true;
+ Put("Purge option set");
+ break;
+ case 'T':
+ opts->trash = true;
+ Put("Trash option set");
+ break;
+ case 'i':
+ opts->init = true;
+ if (!opts->replay_file) {
+ opts->replay_file = absolute_path(optarg);
+ Put("Replay file: %s", opts->replay_file);
+ }
+ break;
+ case 'R':
+ opts->init = true;
+ opts->replay = true;
+ if (!opts->replay_file) {
+ opts->replay_file = absolute_path(optarg);
+ Put("Replay file: %s", opts->replay_file);
+ }
+ break;
+ case 'r':
+ opts->replay = true;
+ if (!opts->replay_file) {
+ opts->replay_file = absolute_path(optarg);
+ Put("Replay file: %s", opts->replay_file);
+ }
+ break;
+ case 'S':
+ opts->stats_file = Clone(optarg);
+ Put("Stats output file: %s", opts->stats_file);
+ break;
+ case 'w':
+ opts->wd_base = optarg;
+ Put("WD base: %s", opts->wd_base);
+ break;
+ case 'u':
+ opts->user = optarg;
+ Put("User: %s", opts->user);
+ break;
+ case 'm':
+ opts->module = Clone(optarg);
+ Put("Module: %s", opts->module);
+ break;
+ case 'n':
+ opts->name = optarg;
+ Put("Name: %s", opts->name);
+ break;
+ case 'h':
+ _print_help();
+ Cleanup(SUCCESS);
+ case 's':
+ sscanf(optarg, "%lf", &opts->speed_factor);
+ Put("Speed factor: %lf", opts->speed_factor);
+ break;
+ case 'p':
+ opts->num_workers = atoi(optarg);
+ if (opts->num_workers < 1)
+ opts->num_workers = 1;
+ Put("Num worker processes: %d", opts->num_workers);
+ break;
+ case 't':
+ opts->num_threads_per_worker = atoi(optarg);
+ if (opts->num_threads_per_worker < 1)
+ opts->num_threads_per_worker = 1;
+ Put("Num threads per worker: %d", opts->num_threads_per_worker);
+ break;
+ case 'x':
+ opts->pid = atoi(optarg);
+ Put("PID: %d", opts->pid);
+ break;
+ default:
+ _print_help();
+ Cleanup(ERROR);
+ }
+ }
+
+ if (opts->purge || opts->trash) {
+ // Clean up all temp data of previous test runs
+ Cleanup(cleanup_run(opts));
+
+ } else if (opts->capture_file && !opts->replay_file) {
+ // We are going to capture I/O
+ Cleanup(capture_run(opts));
+
+ } else if (opts->capture_file && opts->replay_file) {
+ // We are going to generate a .replay file from the .capture file
+ Cleanup(generate_run(opts));
+
+ } else if (opts->replay_file && opts->init && !opts->replay) {
+ // We are going to initialise the test from the .replay file!
+ Cleanup(init_run(opts));
+
+ } else if (opts->replay_file && opts->init && opts->replay) {
+ // We are going to initialise the test and run the test! Run the
+ // initialiser in a sub-process, as it drops root privileges!
+ pid_t pid = fork();
+ if (pid == 0) {
+ Cleanup(init_run(opts));
+ } else {
+ opts->drop_caches = !dont_drop_caches;
+ int init_status;
+ waitpid(pid, &init_status, 0);
+ // Only proceed if initialisation was successfull!
+ Cleanup_unless(SUCCESS, init_status);
+ Cleanup(replay_run(opts));
+ }
+
+ } else if (opts->replay_file && !opts->init && opts->replay) {
+ // We are going to replay the I/O
+ opts->drop_caches = !dont_drop_caches;
+ Cleanup(replay_run(opts));
+
+ } else {
+ _print_help();
+ Cleanup(ERROR);
+ }
+
+cleanup:
+ options_destroy(opts);
+
+ return ret;
+}