Don't like btrecord against libaio and librt, as it doesn't use any of their symbols
[blktrace.git] / blktrace.c
index c8ec9ab03a649650a5b74b4643672e1fcc9127c5..4d458acc8e26065e31eaabaf9a47051a968e0760 100644 (file)
@@ -2,6 +2,7 @@
  * block queue tracing application
  *
  * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -46,7 +47,7 @@
 #include "blktrace.h"
 #include "barrier.h"
 
-static char blktrace_version[] = "0.99.1";
+static char blktrace_version[] = "0.99.3";
 
 /*
  * You may want to increase this even more, if you are logging at a high
@@ -59,7 +60,7 @@ static char blktrace_version[] = "0.99.1";
 
 #define DEBUGFS_TYPE   0x64626720
 
-#define S_OPTS "d:a:A:r:o:kw:Vb:n:D:lh:p:s"
+#define S_OPTS "d:a:A:r:o:kw:Vb:n:D:lh:p:sI:"
 static struct option l_opts[] = {
        {
                .name = "dev",
@@ -67,6 +68,12 @@ static struct option l_opts[] = {
                .flag = NULL,
                .val = 'd'
        },
+       {
+               .name = "input-devs",
+               .has_arg = required_argument,
+               .flag = NULL,
+               .val = 'I'
+       },
        {
                .name = "act-mask",
                .has_arg = required_argument,
@@ -221,6 +228,9 @@ struct device_information {
        volatile int trace_started;
        unsigned long drop_count;
        struct thread_information *threads;
+       unsigned long buf_size;
+       unsigned long buf_nr;
+       unsigned int page_size;
 
        struct cl_host *ch;
        u32 cl_id;
@@ -284,6 +294,9 @@ struct blktrace_net_hdr {
        u32 max_cpus;
        u32 len;                /* length of following trace data */
        u32 cl_id;              /* id for set of client per-cpu connections */
+       u32 buf_size;           /* client buf_size for this trace  */
+       u32 buf_nr;             /* client buf_nr for this trace  */
+       u32 page_size;          /* client page_size for this trace  */
 };
 
 #define TRACE_NET_PORT         (8462)
@@ -382,8 +395,8 @@ static int start_trace(struct device_information *dip)
        struct blk_user_trace_setup buts;
 
        memset(&buts, 0, sizeof(buts));
-       buts.buf_size = buf_size;
-       buts.buf_nr = buf_nr;
+       buts.buf_size = dip->buf_size;
+       buts.buf_nr = dip->buf_nr;
        buts.act_mask = act_mask;
 
        if (ioctl(dip->fd, BLKTRACESETUP, &buts) < 0) {
@@ -543,19 +556,21 @@ static int mmap_subbuf(struct thread_information *tip, unsigned int maxlen)
 {
        int ofd = fileno(tip->ofile);
        int ret;
+       unsigned long nr;
 
        /*
         * extend file, if we have to. use chunks of 16 subbuffers.
         */
-       if (tip->fs_off + buf_size > tip->fs_buf_len) {
+       if (tip->fs_off + maxlen > tip->fs_buf_len) {
                if (tip->fs_buf) {
                        munlock(tip->fs_buf, tip->fs_buf_len);
                        munmap(tip->fs_buf, tip->fs_buf_len);
                        tip->fs_buf = NULL;
                }
 
-               tip->fs_off = tip->fs_size & (page_size - 1);
-               tip->fs_buf_len = (16 * buf_size) - tip->fs_off;
+               tip->fs_off = tip->fs_size & (tip->device->page_size - 1);
+               nr = max(16, tip->device->buf_nr);
+               tip->fs_buf_len = (nr * tip->device->buf_size) - tip->fs_off;
                tip->fs_max_size += tip->fs_buf_len;
 
                if (ftruncate(ofd, tip->fs_max_size) < 0) {
@@ -591,7 +606,7 @@ static int get_subbuf(struct thread_information *tip, unsigned int maxlen)
        struct tip_subbuf *ts = malloc(sizeof(*ts));
        int ret;
 
-       ts->buf = malloc(buf_size);
+       ts->buf = malloc(tip->device->buf_size);
        ts->max_len = maxlen;
 
        ret = tip->read_data(tip, ts->buf, ts->max_len);
@@ -599,7 +614,12 @@ static int get_subbuf(struct thread_information *tip, unsigned int maxlen)
                ts->len = ret;
                tip->data_read += ret;
                if (subbuf_fifo_queue(tip, ts))
-                       return -1;
+                       ret = -1;
+       }
+
+       if (ret <= 0) {
+               free(ts->buf);
+               free(ts);
        }
 
        return ret;
@@ -662,14 +682,14 @@ static void *thread_main(void *arg)
        }
 
        while (!is_done()) {
-               if (tip->get_subbuf(tip, buf_size) < 0)
+               if (tip->get_subbuf(tip, tip->device->buf_size) < 0)
                        break;
        }
 
        /*
         * trace is stopped, pull data until we get a short read
         */
-       while (tip->get_subbuf(tip, buf_size) > 0)
+       while (tip->get_subbuf(tip, tip->device->buf_size) > 0)
                ;
 
        tip_ftrunc_final(tip);
@@ -706,7 +726,10 @@ static int net_send_header(struct thread_information *tip, unsigned int len)
        hdr.max_cpus = ncpus;
        hdr.len = len;
        hdr.cl_id = getpid();
-
+       hdr.buf_size = tip->device->buf_size;
+       hdr.buf_nr = tip->device->buf_nr;
+       hdr.page_size = tip->device->page_size;
+       
        return write_data_net(net_out_fd[tip->cpu], &hdr, sizeof(hdr));
 }
 
@@ -726,6 +749,9 @@ static void net_client_send_close(void)
                strcpy(hdr.buts_name, dip->buts_name);
                hdr.cpu = get_dropped_count(dip->buts_name);
                hdr.cl_id = getpid();
+               hdr.buf_size = dip->buf_size;
+               hdr.buf_nr = dip->buf_nr;
+               hdr.page_size = dip->page_size;
 
                write_data_net(net_out_fd[0], &hdr, sizeof(hdr));
        }
@@ -771,7 +797,6 @@ static int flush_subbuf_sendfile(struct thread_information *tip,
                goto err;
 
        tip->data_read += ts->len;
-       tip->ofile_offset += buf_size;
        ret = 1;
 err:
        free(ts);
@@ -785,7 +810,7 @@ static int get_subbuf_sendfile(struct thread_information *tip,
        struct stat sb;
        unsigned int ready;
 
-       wait_for_data(tip, 250);
+       wait_for_data(tip, -1);
 
        if (fstat(tip->fd, &sb) < 0) {
                perror("trace stat");
@@ -818,15 +843,11 @@ static int write_data(struct thread_information *tip, void *buf,
        if (!buf_len)
                return 0;
 
-       while (1) {
-               ret = fwrite(buf, buf_len, 1, tip->ofile);
-               if (ret == 1)
-                       break;
-
-               if (ret < 0) {
-                       perror("write");
-                       return 1;
-               }
+       ret = fwrite(buf, buf_len, 1, tip->ofile);
+       if (ferror(tip->ofile) || ret != 1) {
+               perror("fwrite");
+               clearerr(tip->ofile);
+               return 1;
        }
 
        if (tip->ofile_stdout)
@@ -1184,6 +1205,9 @@ static int open_devices(void)
                        perror(dip->path);
                        return 1;
                }
+               dip->buf_size = buf_size;
+               dip->buf_nr = buf_nr;
+               dip->page_size = page_size;
        }
 
        return 0;
@@ -1200,6 +1224,7 @@ static int start_devices(void)
                fprintf(stderr, "Out of memory, threads (%d)\n", size * ndevs);
                return 1;
        }
+       memset(thread_information, 0, size * ndevs);
 
        for_each_dip(dip, i) {
                if (start_trace(dip)) {
@@ -1279,7 +1304,7 @@ static void show_stats(struct device_information *dips, int ndips, int cpus)
 }
 
 static struct device_information *net_get_dip(struct net_connection *nc,
-                                             char *buts_name, u32 cl_id)
+                                             struct blktrace_net_hdr *bnh)
 {
        struct device_information *dip, *cl_dip = NULL;
        struct cl_host *ch = nc->ch;
@@ -1288,10 +1313,10 @@ static struct device_information *net_get_dip(struct net_connection *nc,
        for (i = 0; i < ch->ndevs; i++) {
                dip = &ch->device_information[i];
 
-               if (!strcmp(dip->buts_name, buts_name))
+               if (!strcmp(dip->buts_name, bnh->buts_name))
                        return dip;
 
-               if (dip->cl_id == cl_id)
+               if (dip->cl_id == bnh->cl_id)
                        cl_dip = dip;
        }
 
@@ -1300,13 +1325,17 @@ static struct device_information *net_get_dip(struct net_connection *nc,
        memset(dip, 0, sizeof(*dip));
        dip->fd = -1;
        dip->ch = ch;
-       dip->cl_id = cl_id;
+       dip->cl_id = bnh->cl_id;
+       dip->buf_size = bnh->buf_size;
+       dip->buf_nr = bnh->buf_nr;
+       dip->page_size = bnh->page_size;
+
        if (cl_dip)
                dip->cl_connect_time = cl_dip->cl_connect_time;
        else
                dip->cl_connect_time = nc->connect_time;
-       strcpy(dip->buts_name, buts_name);
-       dip->path = strdup(buts_name);
+       strcpy(dip->buts_name, bnh->buts_name);
+       dip->path = strdup(bnh->buts_name);
        dip->trace_started = 1;
        ch->ndevs++;
        dip->threads = malloc(nc->ncpus * sizeof(struct thread_information));
@@ -1338,7 +1367,7 @@ static struct thread_information *net_get_tip(struct net_connection *nc,
        struct device_information *dip;
        struct thread_information *tip;
 
-       dip = net_get_dip(nc, bnh->buts_name, bnh->cl_id);
+       dip = net_get_dip(nc, bnh);
        if (!dip->trace_started) {
                fprintf(stderr, "Events for closed devices %s\n", dip->buts_name);
                return NULL;
@@ -1484,6 +1513,9 @@ static int net_client_data(struct net_connection *nc)
                bnh.max_cpus = be32_to_cpu(bnh.max_cpus);
                bnh.len = be32_to_cpu(bnh.len);
                bnh.cl_id = be32_to_cpu(bnh.cl_id);
+               bnh.buf_size = be32_to_cpu(bnh.buf_size);
+               bnh.buf_nr = be32_to_cpu(bnh.buf_nr);
+               bnh.page_size = be32_to_cpu(bnh.page_size);
        }
 
        if ((bnh.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
@@ -1503,7 +1535,7 @@ static int net_client_data(struct net_connection *nc)
                 */
                struct device_information *dip;
 
-               dip = net_get_dip(nc, bnh.buts_name, bnh.cl_id);
+               dip = net_get_dip(nc, &bnh);
                dip->drop_count = bnh.cpu;
                dip->trace_started = 0;
 
@@ -1550,13 +1582,14 @@ static void net_add_connection(int listen_fd, struct sockaddr_in *addr)
                memset(ch, 0, sizeof(*ch));
                ch->cl_in_addr = addr->sin_addr;
                net_add_client_host(ch);
+
+               printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
        }
 
        ch->net_connections = realloc(ch->net_connections, (ch->nconn + 1) * sizeof(*nc));
        nc = &ch->net_connections[ch->nconn++];
        memset(nc, 0, sizeof(*nc));
 
-       printf("server: connection from %s\n", inet_ntoa(addr->sin_addr));
        time(&nc->connect_time);
        nc->ch = ch;
        nc->in_fd = in_fd;
@@ -1723,9 +1756,9 @@ static int net_setup_client(void)
 
 static char usage_str[] = \
        "-d <dev> [ -r debugfs path ] [ -o <output> ] [-k ] [ -w time ]\n" \
-       "[ -a action ] [ -A action mask ] [ -v ]\n\n" \
+       "[ -a action ] [ -A action mask ] [ -I  <devs file> ] [ -v ]\n\n" \
        "\t-d Use specified device. May also be given last after options\n" \
-       "\t-r Path to mounted debugfs, defaults to /debug\n" \
+       "\t-r Path to mounted debugfs, defaults to /sys/kernel/debug\n" \
        "\t-o File(s) to send output to\n" \
        "\t-D Directory to prepend to output file names\n" \
        "\t-k Kill a running trace\n" \
@@ -1738,6 +1771,7 @@ static char usage_str[] = \
        "\t-h Run in network client mode, connecting to the given host\n" \
        "\t-p Network port to use (default 8462)\n" \
        "\t-s Make the network client NOT use sendfile() to transfer data\n" \
+       "\t-I Add devices found in <devs file>\n" \
        "\t-V Print program version info\n\n";
 
 static void show_usage(char *program)
@@ -1747,7 +1781,7 @@ static void show_usage(char *program)
 
 int main(int argc, char *argv[])
 {
-       static char default_debugfs_path[] = "/debug";
+       static char default_debugfs_path[] = "/sys/kernel/debug";
        struct statfs st;
        int i, c;
        int stop_watch = 0;
@@ -1781,6 +1815,24 @@ int main(int argc, char *argv[])
                                return 1;
                        break;
 
+               case 'I': {
+                       char dev_line[256];
+                       FILE *ifp = fopen(optarg, "r");
+
+                       if (!ifp) {
+                               fprintf(stderr, 
+                                       "Invalid file for devices %s\n", 
+                                       optarg);
+                               return 1;
+                       }
+
+                       while (fscanf(ifp, "%s\n", dev_line) == 1)
+                               if (resize_devices(strdup(dev_line)) != 0)
+                                       return 1;
+                       break;
+               }
+                       
+
                case 'r':
                        debugfs_path = optarg;
                        break;
@@ -1846,8 +1898,14 @@ int main(int argc, char *argv[])
 
        page_size = getpagesize();
 
-       if (net_mode == Net_server)
+       if (net_mode == Net_server) {
+               if (output_name) {
+                       fprintf(stderr, "-o ignored in server mode\n");
+                       output_name = NULL;
+               }
+
                return net_server();
+       }
 
        while (optind < argc) {
                if (resize_devices(argv[optind++]) != 0)
@@ -1894,6 +1952,7 @@ int main(int argc, char *argv[])
        signal(SIGHUP, handle_sigint);
        signal(SIGTERM, handle_sigint);
        signal(SIGALRM, handle_sigint);
+       signal(SIGPIPE, SIG_IGN);
 
        if (net_mode == Net_client && net_setup_client())
                return 1;