10 #define NELEMS(pfi) ((pfi)->stat.st_size / sizeof(struct blk_io_trace))
12 #define MAX_CPUS (512)
14 struct per_file_info {
26 unsigned long long start_time;
29 struct per_file_info per_file_info[MAX_CPUS];
30 struct per_file_info *current;
32 static unsigned long qreads, qwrites, creads, cwrites, mreads, mwrites;
33 static unsigned long long qread_kb, qwrite_kb, cread_kb, cwrite_kb;
34 static unsigned long long events, missed_events;
36 static inline void account_m(int rw, unsigned int bytes)
40 qwrite_kb += bytes >> 10;
43 qread_kb += bytes >> 10;
47 static inline void account_q(int rw, unsigned int bytes)
51 qwrite_kb += bytes >> 10;
54 qread_kb += bytes >> 10;
58 static inline void account_c(int rw, unsigned int bytes)
62 cwrite_kb += bytes >> 10;
65 cread_kb += bytes >> 10;
72 fprintf(current->ofp,"%s",s);
78 inline char *setup_header(struct blk_io_trace *t, char act)
80 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
81 int b = t->action & BLK_TC_ACT(BLK_TC_BARRIER);
82 int s = t->action & BLK_TC_ACT(BLK_TC_SYNC);
97 sprintf(hstring, "%3d %15ld %12Lu %5u %c %3s", current->cpu,
98 (unsigned long)t->sequence, (unsigned long long)t->time, t->pid,
104 void log_complete(struct blk_io_trace *t, char act)
106 sprintf(tstring,"%s %Lu + %u [%d]\n", setup_header(t, act),
107 (unsigned long long)t->sector, t->bytes >> 9, t->error);
111 void log_queue(struct blk_io_trace *t, char act)
113 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
114 (unsigned long long)t->sector, t->bytes >> 9);
118 void log_issue(struct blk_io_trace *t, char act)
120 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
121 (unsigned long long)t->sector, t->bytes >> 9);
125 void log_merge(struct blk_io_trace *t, char act)
127 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
128 (unsigned long long)t->sector, t->bytes >> 9);
132 void log_generic(struct blk_io_trace *t, char act)
134 sprintf(tstring,"%s %Lu + %u\n", setup_header(t, act),
135 (unsigned long long)t->sector, t->bytes >> 9);
139 void log_pc(struct blk_io_trace *t, char act)
142 unsigned char buf[64];
144 sprintf(tstring,"%s\n", setup_header(t, act));
147 if (t->pdu_len > sizeof(buf)) {
148 fprintf(stderr, "Payload too large %d\n", t->pdu_len);
152 ret = read(current->dfd, buf, t->pdu_len);
153 if (ret != t->pdu_len) {
154 fprintf(stderr,"read(%d) failed on %s - %d\n", t->pdu_len,
155 current->dname, ret);
159 for (i = 0; i < t->pdu_len; i++) {
160 sprintf(tstring,"%02x ", buf[i]);
165 sprintf(tstring,"[%d]", t->error);
172 void dump_trace_pc(struct blk_io_trace *t)
174 switch (t->action & 0xffff) {
181 case __BLK_TA_SLEEPRQ:
184 case __BLK_TA_REQUEUE:
190 case __BLK_TA_COMPLETE:
194 fprintf(stderr, "Bad pc action %x\n", t->action);
201 void dump_trace_fs(struct blk_io_trace *t)
203 int w = t->action & BLK_TC_ACT(BLK_TC_WRITE);
205 switch (t->action & 0xffff) {
207 account_q(w, t->bytes);
210 case __BLK_TA_BACKMERGE:
211 account_m(w, t->bytes);
214 case __BLK_TA_FRONTMERGE:
215 account_m(w, t->bytes);
221 case __BLK_TA_SLEEPRQ:
224 case __BLK_TA_REQUEUE:
230 case __BLK_TA_COMPLETE:
231 account_c(w, t->bytes);
232 log_complete(t, 'C');
235 fprintf(stderr, "Bad fs action %x\n", t->action);
242 void dump_trace(struct blk_io_trace *t)
244 if (t->action & BLK_TC_ACT(BLK_TC_PC))
250 void show_stats(void)
253 printf("\tQueued: %'8lu, %'8LuKiB\n", qreads, qread_kb);
254 printf("\tCompleted: %'8lu, %'8LuKiB\n", creads, cread_kb);
255 printf("\tMerges: %'8lu\n", mreads);
258 printf("\tQueued: %'8lu, %'8LuKiB\n", qwrites, qwrite_kb);
259 printf("\tCompleted: %'8lu, %'8LuKiB\n", cwrites, cwrite_kb);
260 printf("\tMerges: %'8lu\n", mwrites);
262 printf("Events: %'Lu\n", events);
263 printf("Missed events: %'Lu\n", missed_events);
266 int compar(const void *t1, const void *t2)
268 long v1 = (long)(((struct blk_io_trace *)t1)->sequence);
269 long v2 = (long)(((struct blk_io_trace *)t2)->sequence);
274 int main(int argc, char *argv[])
277 int i, nfiles, nelems, nb, ret;
278 struct per_file_info *pfi;
279 struct blk_io_trace *traces, *tip;
282 fprintf(stderr, "Usage %s <dev>\n", argv[0]);
288 printf("First pass:\n");
290 for (i = 0, pfi = &per_file_info[0]; i < MAX_CPUS; i++, pfi++) {
294 pfi->fname = malloc(128);
295 sprintf(pfi->fname, "%s_out.%d", dev, i);
296 if (stat(pfi->fname, &pfi->stat) < 0)
298 if (!S_ISREG(pfi->stat.st_mode)) {
299 fprintf(stderr, "Bad file type %s\n", pfi->fname);
304 pfi->nelems = NELEMS(pfi);
305 nelems += pfi->nelems;
306 printf("\t%2d %10s %15d\n", i, pfi->fname, pfi->nelems);
309 printf("\t %15d\n", nelems);
312 fprintf(stderr, "No files found\n");
316 traces = malloc(nelems * sizeof(struct blk_io_trace));
317 if (traces == NULL) {
318 fprintf(stderr, "Can not allocate %d\n",
319 nelems * (int) sizeof(struct blk_io_trace));
323 printf("Second pass:\n");
325 for (i = 0, pfi = per_file_info; i < nfiles; i++, pfi++) {
326 pfi->fd = open(pfi->fname, O_RDONLY);
332 pfi->dname = malloc(128);
333 snprintf(pfi->dname, 127, "%s_dat.%d", dev, i);
334 pfi->dfd = open(pfi->dname, O_RDONLY);
340 pfi->ofname = malloc(128);
341 snprintf(pfi->ofname, 127, "%s_log.%d", dev, i);
342 pfi->ofp = fopen(pfi->ofname, "w");
343 if (pfi->ofp == NULL) {
348 printf("\tProcessing %s...", pfi->fname); fflush(stdout);
349 nb = pfi->stat.st_size;
350 ret = read(pfi->fd, p, nb);
353 fprintf(stderr,"\nFATAL: read(%d) -> %d\n", nb, ret);
356 printf("\n"); fflush(stdout);
361 printf("Sorting..."); fflush(stdout);
362 qsort(traces, nelems, sizeof(struct blk_io_trace), compar);
365 for (i = 0, tip = traces; i < nelems; i++, tip++) {
366 int cpu = tip->magic;
368 if (cpu >= MAX_CPUS) {
369 fprintf(stderr, "CPU number too large (%d)\n", cpu);
373 current = &per_file_info[cpu];
376 * offset time by first trace event.
378 * NOTE: This is *cpu* relative, thus you can not
379 * compare times ACROSS cpus.
381 if (current->start_time == 0)
382 current->start_time = tip->time;
384 tip->time -= current->start_time;