+
+/*
+ * open iolog, check version, and call appropriate parser
+ */
+static int init_iolog_read(struct thread_data *td)
+{
+ char buffer[256], *p;
+ FILE *f;
+ int ret;
+
+ f = fopen(td->o.read_iolog_file, "r");
+ if (!f) {
+ perror("fopen read iolog");
+ return 1;
+ }
+
+ p = fgets(buffer, sizeof(buffer), f);
+ if (!p) {
+ td_verror(td, errno, "iolog read");
+ log_err("fio: unable to read iolog\n");
+ fclose(f);
+ return 1;
+ }
+
+ /*
+ * version 2 of the iolog stores a specific string as the
+ * first line, check for that
+ */
+ if (!strncmp(iolog_ver2, buffer, strlen(iolog_ver2)))
+ ret = read_iolog2(td, f);
+ else {
+ log_err("fio: iolog version 1 is no longer supported\n");
+ ret = 1;
+ }
+
+ fclose(f);
+ return ret;
+}
+
+/*
+ * Set up a log for storing io patterns.
+ */
+static int init_iolog_write(struct thread_data *td)
+{
+ struct fio_file *ff;
+ FILE *f;
+ unsigned int i;
+
+ f = fopen(td->o.write_iolog_file, "a");
+ if (!f) {
+ perror("fopen write iolog");
+ return 1;
+ }
+
+ /*
+ * That's it for writing, setup a log buffer and we're done.
+ */
+ td->iolog_f = f;
+ td->iolog_buf = malloc(8192);
+ setvbuf(f, td->iolog_buf, _IOFBF, 8192);
+
+ /*
+ * write our version line
+ */
+ if (fprintf(f, "%s\n", iolog_ver2) < 0) {
+ perror("iolog init\n");
+ return 1;
+ }
+
+ /*
+ * add all known files
+ */
+ for_each_file(td, ff, i)
+ log_file(td, ff, FIO_LOG_ADD_FILE);
+
+ return 0;
+}
+
+int init_iolog(struct thread_data *td)
+{
+ int ret = 0;
+
+ if (td->o.read_iolog_file) {
+ /*
+ * Check if it's a blktrace file and load that if possible.
+ * Otherwise assume it's a normal log file and load that.
+ */
+ if (is_blktrace(td->o.read_iolog_file))
+ ret = load_blktrace(td, td->o.read_iolog_file);
+ else
+ ret = init_iolog_read(td);
+ } else if (td->o.write_iolog_file)
+ ret = init_iolog_write(td);
+
+ return ret;
+}
+
+void setup_log(struct io_log **log)
+{
+ struct io_log *l = malloc(sizeof(*l));
+
+ l->nr_samples = 0;
+ l->max_samples = 1024;
+ l->log = malloc(l->max_samples * sizeof(struct io_sample));
+ *log = l;
+}
+
+void __finish_log(struct io_log *log, const char *name)
+{
+ unsigned int i;
+ FILE *f;
+
+ f = fopen(name, "a");
+ if (!f) {
+ perror("fopen log");
+ return;
+ }
+
+ for (i = 0; i < log->nr_samples; i++) {
+ fprintf(f, "%lu, %lu, %u, %u\n", log->log[i].time,
+ log->log[i].val,
+ log->log[i].ddir,
+ log->log[i].bs);
+ }
+
+ fclose(f);
+ free(log->log);
+ free(log);
+}
+
+void finish_log_named(struct thread_data *td, struct io_log *log,
+ const char *prefix, const char *postfix)
+{
+ char file_name[256], *p;
+
+ snprintf(file_name, 200, "%s_%s.log", prefix, postfix);
+ p = basename(file_name);
+ __finish_log(log, p);
+}
+
+void finish_log(struct thread_data *td, struct io_log *log, const char *name)
+{
+ finish_log_named(td, log, td->o.name, name);
+}