diff --git a/mboxd.c b/mboxd.c index 2026023d5904fff3b4fa343d81898817d78e7229..3f784102b86bf79fdcb35b71eb6849b2756c4671 100644 --- a/mboxd.c +++ b/mboxd.c @@ -54,7 +54,8 @@ const char* USAGE = "\t\t\t\t(default: fill the reserved memory region)\n" "\t-w | --window-size\tThe window size (power of 2) in MB\n" "\t\t\t\t(default: 1MB)\n" - "\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"; + "\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n" + "\t-t | --trace\t\tFile to write trace data to (in blktrace format)\n\n"; static int dbus_init(struct mbox_context *context, const struct transport_ops **ops) @@ -236,6 +237,7 @@ static bool parse_cmdline(int argc, char **argv, { "window-num", optional_argument, 0, 'n' }, { "verbose", no_argument, 0, 'v' }, { "syslog", no_argument, 0, 's' }, + { "trace", optional_argument, 0, 't' }, { "version", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } @@ -309,6 +311,17 @@ static bool parse_cmdline(int argc, char **argv, case 'V': printf("%s V%s\n", THIS_NAME, PACKAGE_VERSION); exit(0); + case 't': + context->blktracefd = open(argv[optind], + O_CREAT|O_TRUNC|O_WRONLY, + 0666); + MSG_INFO("Recording blktrace output to %s\n", + argv[optind]); + if (context->blktracefd == -1) { + perror("Couldn't open blktrace file for writing"); + exit(2); + } + break; case 'h': return false; /* This will print the usage message */ default: diff --git a/mboxd.h b/mboxd.h index 96235d7b78fce5fe87f1d8d6067fae22482b99ef..6b14a242a8d7cce9d387d862d1cde6b65b61442b 100644 --- a/mboxd.h +++ b/mboxd.h @@ -5,6 +5,7 @@ #define MBOX_H #include +#include #include #include #include @@ -101,6 +102,11 @@ struct mbox_context { uint32_t mem_size; /* LPC Bus Base Address (bytes) */ uint32_t lpc_base; + + /* Tracing */ + int blktracefd; + struct blk_io_trace trace; + int64_t blktrace_start; }; #endif /* MBOX_H */ diff --git a/protocol.c b/protocol.c index 7158bfcd5f1bcb0790d7ea03fe5e4b725bfd950e..8f2f7422437e82bae64f7f641a0d37029e27eefe 100644 --- a/protocol.c +++ b/protocol.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "backend.h" #include "common.h" @@ -13,6 +14,7 @@ #include "protocol.h" #include "windows.h" + #define BLOCK_SIZE_SHIFT_V1 12 /* 4K */ static inline uint8_t protocol_get_bmc_event_mask(struct mbox_context *context) @@ -155,6 +157,108 @@ static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context) return lpc_addr >> context->backend.block_size_shift; } +static inline int64_t blktrace_gettime(void) +{ + struct timespec ts; + int64_t n; + + clock_gettime(CLOCK_REALTIME, &ts); + n = (int64_t)(ts.tv_sec) * (int64_t)1000000000 + (int64_t)(ts.tv_nsec); + + return n; +} + +static void blktrace_flush_start(struct mbox_context *context) +{ + struct blk_io_trace *trace = &context->trace; + struct timespec now; + + if (!context->blktracefd) + return; + + if (!context->blktrace_start) { + clock_gettime(CLOCK_REALTIME, &now); + context->blktrace_start = blktrace_gettime(); + } + + trace->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; + trace->sequence++; + trace->time = blktrace_gettime() - context->blktrace_start; + trace->sector = context->current->flash_offset / 512; + trace->bytes = context->current->size; + if (context->current_is_write) + trace->action = BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_WRITE); + else + trace->action = BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_READ); + trace->pid = 0; + trace->device = 0; + trace->cpu = 0; + trace->error = 0; + trace->pdu_len = 0; + write(context->blktracefd, &trace, sizeof(trace)); + trace->sequence++; + trace->time = blktrace_gettime() - context->blktrace_start; + trace->action &= ~BLK_TA_QUEUE; + trace->action |= BLK_TA_ISSUE; + write(context->blktracefd, &trace, sizeof(trace));} + +static void blktrace_flush_done(struct mbox_context *context) +{ + struct blk_io_trace *trace = &context->trace; + + if (!context->blktracefd) + return; + + trace->sequence++; + trace->time = blktrace_gettime() - context->blktrace_start; + trace->action &= ~BLK_TA_ISSUE; + trace->action |= BLK_TA_COMPLETE; + write(context->blktracefd, &trace, sizeof(trace)); +} + +static void blktrace_window_start(struct mbox_context *context) +{ + struct blk_io_trace *trace = &context->trace; + + if (!context->blktracefd) + return; + + if (!context->blktrace_start) + context->blktrace_start = blktrace_gettime(); + + trace->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; + trace->sequence++; + trace->time = blktrace_gettime() - context->blktrace_start; + trace->action = BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_READ); + trace->pid = 0; + trace->device = 0; + trace->cpu = 0; + trace->error = 0; + trace->pdu_len = 0; +} + +static void blktrace_window_done(struct mbox_context *context) +{ + struct blk_io_trace *trace = &context->trace; + + if (!context->blktracefd) + return; + + trace->sector = context->current->flash_offset / 512; + trace->bytes = context->current->size; + write(context->blktracefd, &trace, sizeof(trace)); + trace->sequence++; + trace->action &= ~BLK_TA_QUEUE; + trace->action |= BLK_TA_ISSUE; + write(context->blktracefd, &trace, sizeof(trace)); + + trace->sequence++; + trace->time = blktrace_gettime() - context->blktrace_start; + trace->action &= ~BLK_TA_ISSUE; + trace->action |= BLK_TA_COMPLETE; + write(context->blktracefd, &trace, sizeof(trace)); +} + static int protocol_v1_create_window(struct mbox_context *context, struct protocol_create_window *io) { @@ -180,7 +284,9 @@ static int protocol_v1_create_window(struct mbox_context *context, * write_flush() to make sure we pick the right one. */ if (context->current_is_write) { + blktrace_flush_start(context); rc = context->protocol->flush(context, NULL); + blktrace_flush_done(context); if (rc < 0) { MSG_ERR("Couldn't Flush Write Window\n"); return rc; @@ -192,6 +298,7 @@ static int protocol_v1_create_window(struct mbox_context *context, /* Offset the host has requested */ MSG_INFO("Host requested flash @ 0x%.8x\n", offset); /* Check if we have an existing window */ + blktrace_window_start(context); context->current = windows_search(context, offset, context->version == API_VERSION_1); @@ -206,6 +313,7 @@ static int protocol_v1_create_window(struct mbox_context *context, return rc; } } + blktrace_window_done(context); context->current_is_write = !io->req.ro;