extern int plot_io_action;
extern int io_per_process;
-static const int line_len = 1024;
-static char line[1024];
-
/*
* Trace categories
*/
trace->io = (struct blk_io_trace *)trace->cur;
}
-int is_io_event(struct blk_io_trace *test)
+static int is_io_event(struct blk_io_trace *test)
{
char *message;
if (!(test->action & BLK_TC_ACT(BLK_TC_NOTIFY)))
return found;
}
-int parse_fio_bank_message(struct trace *trace, u64 *bank_ret, u64 *offset_ret,
+static int parse_fio_bank_message(struct trace *trace, u64 *bank_ret, u64 *offset_ret,
u64 *num_banks_ret)
{
char *s;
}
}
-u64 map_io(struct trace *trace, struct blk_io_trace *io)
+static u64 map_io(struct trace *trace, struct blk_io_trace *io)
{
struct dev_info *di = lookup_dev(trace, io);
u64 val = trace->io->sector << 9;
}
static char footer[] = ".blktrace.0";
-static int footer_len = sizeof(footer);
+static int footer_len = sizeof(footer) - 1;
-static void match_trace(char *name, char **traces)
+static int match_trace(char *name, int *len)
{
int match_len;
- char *match;
int footer_start;
match_len = strlen(name);
if (match_len <= footer_len)
- return;
+ return 0;
footer_start = match_len - footer_len;
- if (strcmp(name + footer_start + 1, footer) != 0)
- return;
-
- match = strdup(name);
- if (!match)
- goto enomem;
-
- match[footer_start + 1] = '\0';
- snprintf(line, line_len, "%s -i '%s'", *traces ? *traces : "", match);
- free(match);
-
- match = strdup(line);
- if (!match)
- goto enomem;
-
- free(*traces);
- *traces = match;
- return;
+ if (strcmp(name + footer_start, footer) != 0)
+ return 0;
-enomem:
- perror("memory allocation failed");
- exit(1);
- return;
+ if (len)
+ *len = match_len;
+ return 1;
}
-static char *combine_blktrace_devs(char *dir_name)
-{
- DIR *dir;
- char *traces = NULL;
- struct dirent *d;
- int len;
- int ret;
+struct tracelist {
+ struct tracelist *next;
+ char *name;
+};
- dir = opendir(dir_name);
+static struct tracelist *traces_list(char *dir_name, int *len)
+{
+ int count = 0;
+ struct tracelist *traces = NULL;
+ int dlen = strlen(dir_name);
+ DIR *dir = opendir(dir_name);
if (!dir)
return NULL;
while (1) {
- d = readdir(dir);
+ int n = 0;
+ struct tracelist *tl;
+ struct dirent *d = readdir(dir);
if (!d)
break;
- len = strlen(d->d_name);
- if (len > footer_len)
- match_trace(d->d_name, &traces);
+ if (!match_trace(d->d_name, &n))
+ continue;
+
+ n += dlen + 1; /* dir + '/' + file */
+ /* Allocate space for tracelist + filename */
+ tl = calloc(1, sizeof(struct tracelist) + (sizeof(char) * (n + 1)));
+ if (!tl) {
+ closedir(dir);
+ return NULL;
+ }
+ tl->next = traces;
+ tl->name = (char *)(tl + 1);
+ snprintf(tl->name, n, "%s/%s", dir_name, d->d_name);
+ traces = tl;
+ count++;
}
closedir(dir);
- if (!traces)
- return NULL;
+ if (len)
+ *len = count;
- snprintf(line, line_len, "blkparse -O %s -D %s -d '%s.%s'",
- traces, dir_name, dir_name, "dump");
+ return traces;
+}
- ret = system(line);
- if (ret) {
- fprintf(stderr, "blkparse failure %s\n", line);
- exit(1);
+static void traces_free(struct tracelist *traces)
+{
+ while (traces) {
+ struct tracelist *tl = traces;
+ traces = traces->next;
+ free(tl);
}
- snprintf(line, line_len, "%s.%s", dir_name, "dump");
- return strdup(line);
+}
+
+static int dump_traces(struct tracelist *traces, int count, char *dumpfile)
+{
+ struct tracelist *tl;
+ char **argv = NULL;
+ int argc = 0;
+ int i;
+ int err = 0;
+
+ argc = count * 2; /* {"-i", trace } */
+ argc += 4; /* See below */
+ argv = calloc(argc + 1, sizeof(char *));
+ if (!argv)
+ return -errno;
+
+ i = 0;
+ argv[i++] = "blkparse";
+ argv[i++] = "-O";
+ argv[i++] = "-d";
+ argv[i++] = dumpfile;
+ for (tl = traces; tl != NULL; tl = tl->next) {
+ argv[i++] = "-i";
+ argv[i++] = tl->name;
+ }
+
+ err = run_program(argc, argv, 1, NULL, NULL);
+ if (err)
+ fprintf(stderr, "%s exited with %d, expected 0\n", argv[0], err);
+ free(argv);
+ return err;
}
static char *find_trace_file(char *filename)
int ret;
struct stat st;
char *dot;
- char *try;
int found_dir = 0;
+ char *dumpfile;
+ int len = strlen(filename);
/* look for an exact match of whatever they pass in.
* If it is a file, assume it is the dump file.
found_dir = 1;
}
+ if (found_dir) {
+ int i;
+ /* Eat up trailing '/'s */
+ for (i = len - 1; filename[i] == '/'; i--)
+ filename[i] = '\0';
+ }
+
/*
* try tacking .dump onto the end and see if that already
* has been generated
*/
- snprintf(line, line_len, "%s.%s", filename, "dump");
- ret = stat(line, &st);
+ ret = asprintf(&dumpfile, "%s.dump", filename);
+ if (ret == -1) {
+ perror("Error building dump file name");
+ return NULL;
+ }
+ ret = stat(dumpfile, &st);
if (ret == 0)
- return strdup(line);
+ return dumpfile;
/*
* try to generate the .dump from all the traces in
* a single dir.
*/
if (found_dir) {
- try = combine_blktrace_devs(filename);
- if (try)
- return try;
+ int count;
+ struct tracelist *traces = traces_list(filename, &count);
+ if (traces) {
+ ret = dump_traces(traces, count, dumpfile);
+ traces_free(traces);
+ if (ret == 0)
+ return dumpfile;
+ }
}
+ free(dumpfile);
/*
* try to generate the .dump from all the blktrace
* files for a named trace
*/
- try = strdup(filename);
- dot = strrchr(try, '.');
+ dot = strrchr(filename, '.');
if (!dot || strcmp(".dump", dot) != 0) {
- if (dot && dot != try)
- *dot = '\0';
- snprintf(line, line_len, "%s%s", try, ".blktrace.0");
- ret = stat(line, &st);
+ struct tracelist trace = {0 ,NULL};
+ if (dot && dot != filename)
+ len = dot - filename;
+
+ ret = asprintf(&trace.name, "%*s.blktrace.0", len, filename);
+ if (ret == -1)
+ return NULL;
+ ret = asprintf(&dumpfile, "%*s.dump", len, filename);
+ if (ret == -1) {
+ free(trace.name);
+ return NULL;
+ }
+
+ ret = dump_traces(&trace, 1, dumpfile);
if (ret == 0) {
- blktrace_to_dump(try);
- snprintf(line, line_len, "%s.%s", try, "dump");
- ret = stat(line, &st);
- if (ret == 0) {
- free(try);
- return strdup(line);
- }
+ free(trace.name);
+ return dumpfile;
}
+ free(trace.name);
+ free(dumpfile);
}
- free(try);
return NULL;
}
struct trace *open_trace(char *filename)
return;
if (action == __BLK_TA_QUEUE) {
- if (trace->found_issue || trace->found_completion)
- hash_queued_io(trace->io);
+ if (io->sector == 0)
+ return;
+ /*
+ * If D (issue) events are available, use them for I/O
+ * accounting. Nothing needs to be done for Q.
+ */
+ if (trace->found_issue)
+ return;
+ /*
+ * If there are no D or C events, then all that can be
+ * done is to account the Q event (and make sure not to
+ * add the I/O to the hash, because it will never be
+ * removed).
+ */
+ if (!trace->found_completion)
+ goto account_io;
+ /*
+ * When there are no ISSUE events, count depth and
+ * latency from queue events.
+ */
+ pio = hash_queued_io(trace->io);
+ if (pio) {
+ pio->dispatch_time = io->time;
+ goto account_io;
+ }
+ return;
+ }
+ if (action == __BLK_TA_REQUEUE) {
+ if (ios_in_flight > 0)
+ ios_in_flight--;
return;
}
if (action != __BLK_TA_ISSUE)
free(pio);
}
+account_io:
ios_in_flight++;
seconds = SECONDS(io->time);