/* * blktrace output analysis: generate a timeline & gather statistics * * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com> * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <string.h> #include "blktrace.h" #include "globals.h" #define DEF_LEN (16 * 1024 * 1024) static int fd; static void *cur_map = MAP_FAILED; static off_t cur_min, cur, cur_max, total_size; static size_t len; static struct blk_io_trace *next_t; static long pgsz; int data_is_native = -1; static inline size_t min_len(size_t a, size_t b) { return a < b ? a : b; } static inline size_t convert_to_cpu(struct blk_io_trace *t, struct blk_io_trace *tp, void **pdu) { if (data_is_native == -1) check_data_endianness(t->magic); if (data_is_native) memcpy(tp, t, sizeof(*tp)); else { tp->magic = be32_to_cpu(t->magic); tp->sequence = be32_to_cpu(t->sequence); tp->time = be64_to_cpu(t->time); tp->sector = be64_to_cpu(t->sector); tp->bytes = be32_to_cpu(t->bytes); tp->action = be32_to_cpu(t->action); tp->pid = be32_to_cpu(t->pid); tp->device = be32_to_cpu(t->device); tp->cpu = be16_to_cpu(t->cpu); tp->error = be16_to_cpu(t->error); tp->pdu_len = be16_to_cpu(t->pdu_len); } if (tp->pdu_len) { *pdu = malloc(tp->pdu_len); memcpy(*pdu, t+1, tp->pdu_len); } else *pdu = NULL; return sizeof(*tp) + tp->pdu_len; } static int move_map(void) { if (cur_map != MAP_FAILED) munmap(cur_map, len); cur_min = (cur & ~(pgsz-1)); len = min_len(DEF_LEN, total_size - cur_min); if (len < sizeof(*next_t)) return 0; cur_map = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, cur_min); if (cur_map == MAP_FAILED) { perror("mmap"); exit(1); } cur_max = cur_min + len; return (cur < cur_max); } void setup_ifile(char *fname) { struct stat buf; pgsz = sysconf(_SC_PAGESIZE); fd = my_open(fname, O_RDONLY); if (fd < 0) { perror(fname); exit(1); } if (fstat(fd, &buf) < 0) { perror(fname); exit(1); } total_size = buf.st_size; if (!move_map()) exit(0); } void cleanup_ifile(void) { if (cur_map != MAP_FAILED) munmap(cur_map, len); close(fd); } int next_trace(struct blk_io_trace *t, void **pdu) { size_t this_len; if ((cur + 512) > cur_max) if (!move_map()) { cleanup_ifile(); return 0; } next_t = cur_map + (cur - cur_min); this_len = convert_to_cpu(next_t, t, pdu); cur += this_len; return 1; } double pct_done(void) { return 100.0 * ((double)cur / (double)total_size); }