Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package blktrace for openSUSE:Factory checked in at 2021-10-16 22:47:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/blktrace (Old) and /work/SRC/openSUSE:Factory/.blktrace.new.1890 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "blktrace" Sat Oct 16 22:47:14 2021 rev:36 rq:925611 version:1.3.0+git.20210628 Changes: -------- --- /work/SRC/openSUSE:Factory/blktrace/blktrace.changes 2018-06-08 23:15:09.756720392 +0200 +++ /work/SRC/openSUSE:Factory/.blktrace.new.1890/blktrace.changes 2021-10-16 22:47:49.600701345 +0200 @@ -1,0 +2,20 @@ +Mon Oct 11 13:08:42 UTC 2021 - dd...@suse.com + +- Update to version 1.3.0+git.20210628: + * blktrace: exit directly when nthreads_running != ncpus in run_tracers() + * blktrace 1.3.0 + * blkparse: Print time when trace was started + * blktrace: inclusive terminology + * blkparse: Print PID information for TN_MESSAGE events + * iowatcher: Handle cgroup information + * iowatcher: Use blktrace_api.h + * blkparse: Handle cgroup information + * blkparse: Fix up the sector and length of split completions + * blkparse: Initialize and test for undefined request tracking timestamps + +------------------------------------------------------------------- +Mon Oct 11 11:43:50 UTC 2021 - David Disseldorp <dd...@suse.com> + +- UsrMerge: relocate blktrace, blkparse and btrace (bsc#1191056) + +------------------------------------------------------------------- Old: ---- blktrace-1.2.0+git.20180516.tar.xz New: ---- blktrace-1.3.0+git.20210628.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ blktrace.spec ++++++ --- /var/tmp/diff_new_pack.UQdZRT/_old 2021-10-16 22:47:50.112701777 +0200 +++ /var/tmp/diff_new_pack.UQdZRT/_new 2021-10-16 22:47:50.116701780 +0200 @@ -1,7 +1,7 @@ # # spec file for package blktrace # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,18 +12,18 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # %{!?_without_docs: %global with_docs 1} Name: blktrace -Version: 1.2.0+git.20180516 +Version: 1.3.0+git.20210628 Release: 0 Summary: Block IO tracer -License: GPL-2.0 +License: GPL-2.0-only Group: Development/Tools/Other -Url: http://git.kernel.dk/?p=blktrace.git;a=summary +URL: http://git.kernel.dk/?p=blktrace.git;a=summary Source0: %{name}-%{version}.tar.xz Patch0: blkparse-track-smallest-sequence-read-per-device.patch BuildRequires: gcc @@ -64,17 +64,13 @@ %install make DESTDIR=%{buildroot} prefix=%{_prefix} mandir=%{_mandir} install -# move blktrace to /bin (bug #300186) -mkdir -p %{buildroot}/bin -mv %{buildroot}%{_bindir}/{blktrace,blkparse,btrace} \ - %{buildroot}/bin %files %defattr(-,root,root) %doc README %{?with_docs: doc/blktrace.pdf btreplay/doc/btreplay.pdf btt/doc/btt.pdf} -/bin/blktrace -/bin/blkparse -/bin/btrace +%{_bindir}/blktrace +%{_bindir}/blkparse +%{_bindir}/btrace %{_bindir}/blkrawverify %{_bindir}/bno_plot.py %{_bindir}/btt ++++++ _service ++++++ --- /var/tmp/diff_new_pack.UQdZRT/_old 2021-10-16 22:47:50.148701807 +0200 +++ /var/tmp/diff_new_pack.UQdZRT/_new 2021-10-16 22:47:50.152701811 +0200 @@ -1,10 +1,10 @@ <services> <service mode="disabled" name="tar_scm"> - <param name="url">git://git.kernel.dk/blktrace.git</param> + <param name="url">https://git.kernel.dk/blktrace.git</param> <param name="scm">git</param> <param name="changesgenerate">enable</param> <param name="filename">blktrace</param> - <param name="versionformat">1.2.0+git.%cd</param> + <param name="versionformat">1.3.0+git.%cd</param> </service> <service mode="disabled" name="recompress"> <param name="file">*.tar</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.UQdZRT/_old 2021-10-16 22:47:50.176701831 +0200 +++ /var/tmp/diff_new_pack.UQdZRT/_new 2021-10-16 22:47:50.176701831 +0200 @@ -1,4 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">git://git.kernel.dk/blktrace.git</param> - <param name="changesrevision">70d5ca2d5f3d6b97c11c641b7e0c5836983219a0</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">70d5ca2d5f3d6b97c11c641b7e0c5836983219a0</param></service><service name="tar_scm"> + <param name="url">https://git.kernel.dk/blktrace.git</param> + <param name="changesrevision">3a1b1366d30375cdb0f5b299df4edda0c8ba3bcc</param></service></servicedata> \ No newline at end of file ++++++ blktrace-1.2.0+git.20180516.tar.xz -> blktrace-1.3.0+git.20210628.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/Makefile new/blktrace-1.3.0+git.20210628/Makefile --- old/blktrace-1.2.0+git.20180516/Makefile 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/Makefile 2021-06-28 21:41:32.000000000 +0200 @@ -14,7 +14,7 @@ # We always descend into subdirs because they contain their own dependency # information which we don't track in this top level Makefile. -$(SUBDIRS): +$(SUBDIRS): $(PROGS) $(MAKE) -C $@ .PHONY: $(SUBDIRS) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/blkparse.c new/blktrace-1.3.0+git.20210628/blkparse.c --- old/blktrace-1.2.0+git.20180516/blkparse.c 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/blkparse.c 2021-06-28 21:41:32.000000000 +0200 @@ -25,18 +25,20 @@ #include <stdio.h> #include <fcntl.h> #include <stdlib.h> +#include <stdarg.h> #include <string.h> #include <getopt.h> #include <errno.h> #include <signal.h> #include <locale.h> #include <libgen.h> +#include <time.h> #include "blktrace.h" #include "rbtree.h" #include "jhash.h" -static char blkparse_version[] = "1.2.0"; +static char blkparse_version[] = "1.3.0"; struct skip_info { unsigned long start, end; @@ -100,6 +102,19 @@ #define PPI_HASH_SHIFT (8) #define PPI_HASH_SIZE (1 << PPI_HASH_SHIFT) #define PPI_HASH_MASK (PPI_HASH_SIZE - 1) + +enum { + SORT_PROG_EVENT_N, /* Program Name */ + SORT_PROG_EVENT_QKB, /* KB: Queued read and write */ + SORT_PROG_EVENT_RKB, /* KB: Queued Read */ + SORT_PROG_EVENT_WKB, /* KB: Queued Write */ + SORT_PROG_EVENT_CKB, /* KB: Complete */ + SORT_PROG_EVENT_QIO, /* IO: Queued read and write */ + SORT_PROG_EVENT_RIO, /* IO: Queued Read */ + SORT_PROG_EVENT_WIO, /* IO: Queued Write */ + SORT_PROG_EVENT_CIO, /* IO: Complete */ +}; + static struct per_process_info *ppi_hash_table[PPI_HASH_SIZE]; static struct per_process_info *ppi_list; static int ppi_list_entries; @@ -190,6 +205,12 @@ .val = 's' }, { + .name = "sort-program-stats", + .has_arg = required_argument, + .flag = NULL, + .val = 'S' + }, + { .name = "track-ios", .has_arg = no_argument, .flag = NULL, @@ -242,17 +263,21 @@ /* * for tracking individual ios */ -struct io_track { - struct rb_node rb_node; - +struct io_track_req { struct process_pid_map *ppm; - __u64 sector; unsigned long long allocation_time; unsigned long long queue_time; unsigned long long dispatch_time; unsigned long long completion_time; }; +struct io_track { + struct rb_node rb_node; + struct io_track_req *req; + struct io_track *next; + __u64 sector; +}; + static int ndevices; static struct per_dev_info *devices; static char *get_dev_name(struct per_dev_info *, char *, int); @@ -269,6 +294,7 @@ static unsigned long read_sequence; static int per_process_stats; +static int per_process_stats_event = SORT_PROG_EVENT_N; static int per_device_and_cpu_stats = 1; static int track_ios; static int ppi_hash_by_pid = 1; @@ -306,6 +332,21 @@ #define CPU_IDX(cpu) ((cpu) / CPUS_PER_LONG) #define CPU_BIT(cpu) ((cpu) & (CPUS_PER_LONG - 1)) +static void io_warn_unless(struct blk_io_trace *t, int condition, + const char *fmt, ...) +{ + va_list ap; + + if (condition) + return; + va_start(ap, fmt); + printf("(%d,%d) request %llu + %u: ", + MAJOR(t->device), MINOR(t->device), + t->sector, t->bytes); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + static void output_binary(void *buf, int len) { if (dump_binary) { @@ -577,7 +618,7 @@ void *payload = (caddr_t) bit + sizeof(*bit); __u32 two32[2]; - switch (bit->action) { + switch (bit->action & ~__BLK_TN_CGROUP) { case BLK_TN_PROCESS: add_ppm_hash(bit->pid, payload); break; @@ -603,16 +644,27 @@ case BLK_TN_MESSAGE: if (bit->pdu_len > 0) { char msg[bit->pdu_len+1]; + int len = bit->pdu_len; + char cgidstr[24]; - memcpy(msg, (char *)payload, bit->pdu_len); - msg[bit->pdu_len] = '\0'; + cgidstr[0] = 0; + if (bit->action & __BLK_TN_CGROUP) { + struct blk_io_cgroup_payload *cgid = payload; + + sprintf(cgidstr, "%x,%x ", cgid->ino, + cgid->gen); + payload += sizeof(struct blk_io_cgroup_payload); + len -= sizeof(struct blk_io_cgroup_payload); + } + memcpy(msg, (char *)payload, len); + msg[len] = '\0'; fprintf(ofp, - "%3d,%-3d %2d %8s %5d.%09lu %5u %2s %3s %s\n", + "%3d,%-3d %2d %8s %5d.%09lu %5u %s%2s %3s %s\n", MAJOR(bit->device), MINOR(bit->device), - bit->cpu, "0", (int) SECONDS(bit->time), - (unsigned long) NANO_SECONDS(bit->time), - 0, "m", "N", msg); + bit->cpu, "0", (int)SECONDS(bit->time), + (unsigned long)NANO_SECONDS(bit->time), + bit->pid, cgidstr, "m", "N", msg); } break; @@ -956,6 +1008,11 @@ return NULL; } +static inline struct io_track *first_iot(struct io_track_req *req) +{ + return (struct io_track *)(req + 1); +} + static struct io_track *find_track(struct per_dev_info *pdi, pid_t pid, __u64 sector) { @@ -963,10 +1020,19 @@ iot = __find_track(pdi, sector); if (!iot) { - iot = malloc(sizeof(*iot)); - iot->ppm = find_ppm(pid); - if (!iot->ppm) - iot->ppm = add_ppm_hash(pid, "unknown"); + struct io_track_req *req; + + req = malloc(sizeof(*req) + sizeof(*iot)); + req->ppm = find_ppm(pid); + if (!req->ppm) + req->ppm = add_ppm_hash(pid, "unknown"); + req->allocation_time = -1ULL; + req->queue_time = -1ULL; + req->dispatch_time = -1ULL; + req->completion_time = -1ULL; + iot = first_iot(req); + iot->req = req; + iot->next = NULL; iot->sector = sector; track_rb_insert(pdi, iot); } @@ -986,7 +1052,7 @@ if (!iot) { if (verbose) fprintf(stderr, "merge not found for (%d,%d): %llu\n", - MAJOR(pdi->dev), MINOR(pdi->dev), + MAJOR(t->device), MINOR(t->device), (unsigned long long) t->sector + t_sec(t)); return; } @@ -999,19 +1065,16 @@ static void log_track_getrq(struct per_dev_info *pdi, struct blk_io_trace *t) { struct io_track *iot; + struct io_track_req *req; if (!track_ios) return; iot = find_track(pdi, t->pid, t->sector); - iot->allocation_time = t->time; -} - -static inline int is_remapper(struct per_dev_info *pdi) -{ - int major = MAJOR(pdi->dev); - - return (major == 253 || major == 9); + req = iot->req; + io_warn_unless(t, req->allocation_time == -1ULL, + "confused about %s time", "allocation"); + req->allocation_time = t->time; } /* @@ -1021,14 +1084,34 @@ static void log_track_queue(struct per_dev_info *pdi, struct blk_io_trace *t) { struct io_track *iot; + struct io_track_req *req; if (!track_ios) return; - if (!is_remapper(pdi)) - return; iot = find_track(pdi, t->pid, t->sector); - iot->dispatch_time = t->time; + req = iot->req; + io_warn_unless(t, req->dispatch_time == -1ULL, + "confused about %s time", "dispatch"); + req->dispatch_time = t->time; +} + +static void log_track_split(struct per_dev_info *pdi, struct blk_io_trace *t) +{ + struct io_track *iot, *split; + + /* + * With a split request, the completion event will refer to the last + * part of the original request, but other events might refer to other + * parts. + */ + iot = find_track(pdi, t->pid, t->sector); + split = malloc(sizeof(*iot)); + split->req = iot->req; + split->next = iot->next; + iot->next = split; + split->sector = iot->sector + t_sec(t); + track_rb_insert(pdi, split); } /* @@ -1039,20 +1122,24 @@ { unsigned long long elapsed; struct io_track *iot; + struct io_track_req *req; if (!track_ios) return -1; iot = find_track(pdi, t->pid, t->sector); - iot->queue_time = t->time; + req = iot->req; + io_warn_unless(t, req->queue_time == -1ULL, + "confused about %s time", "queue"); + req->queue_time = t->time; - if (!iot->allocation_time) + if (req->allocation_time == -1ULL) return -1; - elapsed = iot->queue_time - iot->allocation_time; + elapsed = req->queue_time - req->allocation_time; if (per_process_stats) { - struct per_process_info *ppi = find_ppi(iot->ppm->pid); + struct per_process_info *ppi = find_ppi(req->ppm->pid); int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0; if (ppi && elapsed > ppi->longest_allocation_wait[w]) @@ -1068,8 +1155,9 @@ static unsigned long long log_track_issue(struct per_dev_info *pdi, struct blk_io_trace *t) { - unsigned long long elapsed; + unsigned long long elapsed = -1ULL; struct io_track *iot; + struct io_track_req *req; if (!track_ios) return -1; @@ -1080,16 +1168,20 @@ if (!iot) { if (verbose) fprintf(stderr, "issue not found for (%d,%d): %llu\n", - MAJOR(pdi->dev), MINOR(pdi->dev), + MAJOR(t->device), MINOR(t->device), (unsigned long long) t->sector); return -1; } - iot->dispatch_time = t->time; - elapsed = iot->dispatch_time - iot->queue_time; + req = iot->req; + io_warn_unless(t, req->dispatch_time == -1ULL, + "confused about %s time", "dispatch"); + req->dispatch_time = t->time; + if (req->queue_time != -1ULL) + elapsed = req->dispatch_time - req->queue_time; - if (per_process_stats) { - struct per_process_info *ppi = find_ppi(iot->ppm->pid); + if (elapsed != -1ULL && per_process_stats) { + struct per_process_info *ppi = find_ppi(req->ppm->pid); int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0; if (ppi && elapsed > ppi->longest_dispatch_wait[w]) @@ -1099,14 +1191,34 @@ return elapsed; } +static void fixup_complete(struct per_dev_info *pdi, struct blk_io_trace *t) +{ + struct io_track *iot; + __u64 start_sector; + + iot = __find_track(pdi, t->sector); + if (!iot) + return; + + /* + * When a split io completes, the sector and length of the completion + * refer to the last part of the original request. Fix the sector and + * length of the complete event to match the original request. + */ + start_sector = first_iot(iot->req)->sector; + t->bytes += (t->sector - start_sector) << 9; + t->sector = start_sector; +} + /* * return time between dispatch and complete */ static unsigned long long log_track_complete(struct per_dev_info *pdi, struct blk_io_trace *t) { - unsigned long long elapsed; - struct io_track *iot; + unsigned long long elapsed = -1ULL; + struct io_track *iot, *next; + struct io_track_req *req; if (!track_ios) return -1; @@ -1115,16 +1227,20 @@ if (!iot) { if (verbose) fprintf(stderr,"complete not found for (%d,%d): %llu\n", - MAJOR(pdi->dev), MINOR(pdi->dev), + MAJOR(t->device), MINOR(t->device), (unsigned long long) t->sector); return -1; } - iot->completion_time = t->time; - elapsed = iot->completion_time - iot->dispatch_time; + req = iot->req; + io_warn_unless(t, req->completion_time == -1ULL, + "confused about %s time", "completion"); + req->completion_time = t->time; + if (req->dispatch_time != -1ULL) + elapsed = req->completion_time - req->dispatch_time; - if (per_process_stats) { - struct per_process_info *ppi = find_ppi(iot->ppm->pid); + if (elapsed != -1ULL && per_process_stats) { + struct per_process_info *ppi = find_ppi(req->ppm->pid); int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0; if (ppi && elapsed > ppi->longest_completion_wait[w]) @@ -1134,8 +1250,13 @@ /* * kill the trace, we don't need it after completion */ - rb_erase(&iot->rb_node, &pdi->rb_track); - free(iot); + for (iot = first_iot(req); iot; iot = next) { + next = iot->next; + rb_erase(&iot->rb_node, &pdi->rb_track); + if (iot != first_iot(req)) + free(iot); + } + free(req); return elapsed; } @@ -1491,7 +1612,7 @@ struct per_cpu_info *pci) { int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0; - int act = t->action & 0xffff; + int act = (t->action & 0xffff) & ~__BLK_TA_CGROUP; switch (act) { case __BLK_TA_QUEUE: @@ -1540,7 +1661,7 @@ struct per_cpu_info *pci) { int w = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0; - int act = t->action & 0xffff; + int act = (t->action & 0xffff) & ~__BLK_TA_CGROUP; switch (act) { case __BLK_TA_QUEUE: @@ -1586,6 +1707,7 @@ case __BLK_TA_COMPLETE: if (pdi->cur_depth[w]) pdi->cur_depth[w]--; + fixup_complete(pdi, t); account_c(t, pci, w, t->bytes); log_complete(pdi, pci, t, "C"); break; @@ -1601,6 +1723,7 @@ log_unplug(pci, t, "UT"); break; case __BLK_TA_SPLIT: + log_track_split(pdi, t); log_split(pci, t, "X"); break; case __BLK_TA_BOUNCE: @@ -1623,7 +1746,7 @@ struct per_dev_info *pdi) { if (text_output) { - if (t->action == BLK_TN_MESSAGE) + if ((t->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE) handle_notify(t); else if (t->action & BLK_TC_ACT(BLK_TC_PC)) dump_trace_pc(t, pdi, pci); @@ -1638,7 +1761,7 @@ if (bin_output_msgs || !(t->action & BLK_TC_ACT(BLK_TC_NOTIFY) && - t->action == BLK_TN_MESSAGE)) + (t->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE)) output_binary(t, sizeof(*t) + t->pdu_len); } @@ -1758,6 +1881,88 @@ return res; } +static int ppi_event_compare(const void *p1, const void *p2) +{ + struct per_process_info *ppi1 = *((struct per_process_info **) p1); + struct per_process_info *ppi2 = *((struct per_process_info **) p2); + struct io_stats *ios1 = &ppi1->io_stats; + struct io_stats *ios2 = &ppi2->io_stats; + unsigned long io1, io2; + unsigned long long kb1,kb2; + int sort_by_kb = 1; + + io1 = io2 = 0; + kb1 = kb2 = 0; + + switch (per_process_stats_event) { + case SORT_PROG_EVENT_QKB: /* KB: Queued read and write */ + kb1 = ios1->qwrite_kb + (ios1->qwrite_b>>10) + + ios1->qread_kb + (ios1->qread_b>>10); + kb2 = ios2->qwrite_kb + (ios2->qwrite_b>>10) + + ios2->qread_kb + (ios2->qread_b>>10); + break; + case SORT_PROG_EVENT_RKB: /* KB: Queued Read */ + kb1 = ios1->qread_kb + (ios1->qread_b>>10); + kb2 = ios2->qread_kb + (ios2->qread_b>>10); + break; + case SORT_PROG_EVENT_WKB: /* KB: Queued Write */ + kb1 = ios1->qwrite_kb + (ios1->qwrite_b>>10); + kb2 = ios2->qwrite_kb + (ios2->qwrite_b>>10); + break; + case SORT_PROG_EVENT_CKB: /* KB: Complete */ + kb1 = ios1->cwrite_kb + (ios1->cwrite_b>>10) + + ios1->cread_kb + (ios1->cread_b>>10); + kb2 = ios2->cwrite_kb + (ios2->cwrite_b>>10) + + ios2->cread_kb + (ios2->cread_b>>10); + break; + case SORT_PROG_EVENT_QIO: /* IO: Queued read and write */ + sort_by_kb = 0; + io1 = ios1->qreads + ios1->qwrites; + io2 = ios2->qreads + ios2->qwrites; + break; + case SORT_PROG_EVENT_RIO: /* IO: Queued Read */ + sort_by_kb = 0; + io1 = ios1->qreads; + io2 = ios2->qreads; + break; + case SORT_PROG_EVENT_WIO: /* IO: Queued Write */ + sort_by_kb = 0; + io1 = ios1->qwrites; + io2 = ios2->qwrites; + break; + case SORT_PROG_EVENT_CIO: /* IO: Complete */ + sort_by_kb = 0; + io1 = ios1->creads + ios1->cwrites; + io2 = ios2->creads + ios2->cwrites; + break; + } + + + /* compare kb */ + if (sort_by_kb) { + if (kb1 > kb2) + return 1; + else if (kb1 == kb2) + return 0; + return -1; + } + + /* compare io */ + if (io1 > io2) + return 1; + else if (io1 == io2) + return 0; + return -1; +} + +static int ppi_compare(const void *p1, const void *p2) +{ + if (per_process_stats_event == SORT_PROG_EVENT_N) + return ppi_name_compare(p1, p2); + + return ppi_event_compare(p1, p2); +} + static void sort_process_list(void) { struct per_process_info **ppis; @@ -1772,7 +1977,7 @@ ppi = ppi->list_next; } - qsort(ppis, ppi_list_entries, sizeof(ppi), ppi_name_compare); + qsort(ppis, ppi_list_entries, sizeof(ppi), ppi_compare); i = ppi_list_entries - 1; ppi_list = NULL; @@ -1920,6 +2125,22 @@ } } +static void correct_abs_start_time(void) +{ + long delta = genesis_time - start_timestamp; + + abs_start_time.tv_sec += SECONDS(delta); + abs_start_time.tv_nsec += NANO_SECONDS(delta); + if (abs_start_time.tv_nsec < 0) { + abs_start_time.tv_nsec += 1000000000; + abs_start_time.tv_sec -= 1; + } else + if (abs_start_time.tv_nsec > 1000000000) { + abs_start_time.tv_nsec -= 1000000000; + abs_start_time.tv_sec += 1; + } +} + static void find_genesis(void) { struct trace *t = trace_list; @@ -1937,18 +2158,7 @@ */ if (start_timestamp && start_timestamp != genesis_time) { - long delta = genesis_time - start_timestamp; - - abs_start_time.tv_sec += SECONDS(delta); - abs_start_time.tv_nsec += NANO_SECONDS(delta); - if (abs_start_time.tv_nsec < 0) { - abs_start_time.tv_nsec += 1000000000; - abs_start_time.tv_sec -= 1; - } else - if (abs_start_time.tv_nsec > 1000000000) { - abs_start_time.tv_nsec -= 1000000000; - abs_start_time.tv_sec += 1; - } + correct_abs_start_time(); } } @@ -2127,7 +2337,7 @@ break; } - if (!(bit->action == BLK_TN_MESSAGE) && + if (!((bit->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE) && check_sequence(pdi, t, force)) break; @@ -2139,7 +2349,7 @@ if (!pci || pci->cpu != bit->cpu) pci = get_cpu_info(pdi, bit->cpu); - if (!(bit->action == BLK_TN_MESSAGE)) + if (!((bit->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE)) pci->last_sequence = bit->sequence; pci->nelems++; @@ -2273,7 +2483,7 @@ /* * not a real trace, so grab and handle it here */ - if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && bit->action != BLK_TN_MESSAGE) { + if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && (bit->action & ~__BLK_TN_CGROUP) != BLK_TN_MESSAGE) { handle_notify(bit); output_binary(bit, sizeof(*bit) + bit->pdu_len); continue; @@ -2422,7 +2632,7 @@ continue; } - if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && bit->action != BLK_TN_MESSAGE) { + if (bit->action & BLK_TC_ACT(BLK_TC_NOTIFY) && (bit->action & ~__BLK_TN_CGROUP) != BLK_TN_MESSAGE) { handle_notify(bit); output_binary(bit, sizeof(*bit) + bit->pdu_len); bit_free(bit); @@ -2603,6 +2813,14 @@ genesis_time = ms_peek_time(ms_head); /* + * Correct abs_start_time if necessary + */ + if (start_timestamp + && start_timestamp != genesis_time) { + correct_abs_start_time(); + } + + /* * Keep processing traces while any are left */ while (!is_done() && ms_head && handle(ms_head)) @@ -2671,6 +2889,7 @@ if (per_device_and_cpu_stats) show_device_and_cpu_stats(); + fprintf(ofp, "Trace started at %s\n", ctime(&abs_start_time.tv_sec)); fflush(ofp); } @@ -2730,7 +2949,46 @@ return 0; } -#define S_OPTS "a:A:b:D:d:f:F:hi:o:Oqstw:vVM" +static int get_program_sort_event(const char *str) +{ + char evt = str[0]; + + switch (evt) { + case 'N': + per_process_stats_event = SORT_PROG_EVENT_N; + break; + case 'Q': + per_process_stats_event = SORT_PROG_EVENT_QKB; + break; + case 'q': + per_process_stats_event = SORT_PROG_EVENT_QIO; + break; + case 'R': + per_process_stats_event = SORT_PROG_EVENT_RKB; + break; + case 'r': + per_process_stats_event = SORT_PROG_EVENT_RIO; + break; + case 'W': + per_process_stats_event = SORT_PROG_EVENT_WKB; + break; + case 'w': + per_process_stats_event = SORT_PROG_EVENT_WIO; + break; + case 'C': + per_process_stats_event = SORT_PROG_EVENT_CKB; + break; + case 'c': + per_process_stats_event = SORT_PROG_EVENT_CIO; + break; + default: + return 1; + } + + return 0; +} + +#define S_OPTS "a:A:b:D:d:f:F:hi:o:OqsS:tw:vVM" static char usage_str[] = "\n\n" \ "-i <file> | --input=<file>\n" \ "[ -a <action field> | --act-mask=<action field> ]\n" \ @@ -2745,6 +3003,7 @@ "[ -O | --no-text-output ]\n" \ "[ -q | --quiet ]\n" \ "[ -s | --per-program-stats ]\n" \ + "[ -S <event> | --sort-program-stats=<event> ]\n" \ "[ -t | --track-ios ]\n" \ "[ -w <time> | --stopwatch=<time> ]\n" \ "[ -M | --no-msgs\n" \ @@ -2764,6 +3023,11 @@ "\t-O Do NOT output text data\n" \ "\t-q Quiet. Don't display any stats at the end of the trace\n" \ "\t-s Show per-program io statistics\n" \ + "\t-S Show per-program io statistics sorted by N/Q/q/R/r/W/w/C/c\n" \ + "\t N:Name, Q/q:Queued(read & write), R/r:Queued Read, W/w:Queued Write, C/c:Complete.\n" \ + "\t Sort programs by how much data(KB): Q,R,W,C.\n" \ + "\t Sort programs by how many IO operations: q,r,w,c.\n" \ + "\t if -S was used, the -s parameter will be ignored.\n" \ "\t-t Track individual ios. Will tell you the time a request took\n" \ "\t to get queued, to get dispatched, and to get completed\n" \ "\t-w Only parse data between the given time interval in seconds.\n" \ @@ -2830,6 +3094,11 @@ case 's': per_process_stats = 1; break; + case 'S': + per_process_stats = 1; + if (get_program_sort_event(optarg)) + return 1; + break; case 't': track_ios = 1; break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/blkparse_fmt.c new/blktrace-1.3.0+git.20210628/blkparse_fmt.c --- old/blktrace-1.2.0+git.20180516/blkparse_fmt.c 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/blkparse_fmt.c 2021-06-28 21:41:32.000000000 +0200 @@ -205,6 +205,21 @@ case 'e': fprintf(ofp, strcat(format, "d"), t->error); break; + case 'g': { + char cgidstr[24]; + u32 ino = 0, gen = 0; + + if (t->action & __BLK_TA_CGROUP) { + struct blk_io_cgroup_payload *cgid = + (struct blk_io_cgroup_payload *)pdu_buf; + + ino = cgid->ino; + gen = cgid->gen; + } + sprintf(cgidstr, "%x,%x", ino, gen); + fprintf(ofp, strcat(format, "s"), cgidstr); + break; + } case 'M': fprintf(ofp, strcat(format, "d"), MAJOR(t->device)); break; @@ -261,12 +276,12 @@ static char *parse_field(char *act, struct per_cpu_info *pci, struct blk_io_trace *t, unsigned long long elapsed, int pdu_len, unsigned char *pdu_buf, - char *master_format) + char *primary_format) { int minus = 0; int has_w = 0; int width = 0; - char *p = master_format; + char *p = primary_format; if (*p == '-') { minus = 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/blktrace.c new/blktrace-1.3.0+git.20210628/blktrace.c --- old/blktrace-1.2.0+git.20180516/blktrace.c 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/blktrace.c 2021-06-28 21:41:32.000000000 +0200 @@ -307,7 +307,7 @@ static volatile int dp_entries; /* - * These synchronize master / thread interactions. + * These synchronize main / thread interactions. */ static pthread_cond_t mt_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t mt_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -2705,8 +2705,10 @@ printf("blktrace: connected!\n"); if (stop_watch) alarm(stop_watch); - } else + } else { stop_tracers(); + done = 1; + } wait_tracers(); if (nthreads_running == ncpus) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/blktrace_api.h new/blktrace-1.3.0+git.20210628/blktrace_api.h --- old/blktrace-1.2.0+git.20180516/blktrace_api.h 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/blktrace_api.h 2021-06-28 21:41:32.000000000 +0200 @@ -51,6 +51,7 @@ __BLK_TA_REMAP, /* bio was remapped */ __BLK_TA_ABORT, /* request aborted */ __BLK_TA_DRV_DATA, /* binary driver data */ + __BLK_TA_CGROUP = 1 << 8, }; /* @@ -60,6 +61,7 @@ __BLK_TN_PROCESS = 0, /* establish pid/name mapping */ __BLK_TN_TIMESTAMP, /* include system clock */ __BLK_TN_MESSAGE, /* Character string message */ + __BLK_TN_CGROUP = __BLK_TA_CGROUP, }; /* @@ -117,6 +119,14 @@ }; /* + * Payload with originating cgroup info + */ +struct blk_io_cgroup_payload { + __u32 ino; + __u32 gen; +}; + +/* * User setup structure passed with BLKSTARTTRACE */ struct blk_user_trace_setup { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/btreplay/btreplay.c new/blktrace-1.3.0+git.20210628/btreplay/btreplay.c --- old/blktrace-1.2.0+git.20180516/btreplay/btreplay.c 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/btreplay/btreplay.c 2021-06-28 21:41:32.000000000 +0200 @@ -645,7 +645,7 @@ static void read_map_devs(char *file_name) { FILE *fp; - char from_dev[256], to_dev[256]; + char *from_dev, *to_dev; fp = fopen(file_name, "r"); if (!fp) { @@ -653,7 +653,7 @@ /*NOTREACHED*/ } - while (fscanf(fp, "%s %s", from_dev, to_dev) == 2) { + while (fscanf(fp, "%ms %ms", &from_dev, &to_dev) == 2) { struct map_dev *mdp = malloc(sizeof(*mdp)); mdp->from_dev = from_dev; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/btt/bno_plot.py new/blktrace-1.3.0+git.20210628/btt/bno_plot.py --- old/blktrace-1.2.0+git.20180516/btt/bno_plot.py 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/btt/bno_plot.py 2021-06-28 21:41:32.000000000 +0200 @@ -40,7 +40,7 @@ from __future__ import absolute_import from __future__ import print_function -import getopt, glob, os, sys, tempfile +import getopt, glob, os, sys, tempfile, shutil verbose = 0 cmds = """ @@ -76,7 +76,7 @@ elif o in ('-K', '--keys-below'): keys_below = True - if len(args) > 0: bnos = args + if args: bnos = args else: bnos = glob.glob('blknos*[rw].dat') return (bnos, keys_below) @@ -98,21 +98,20 @@ for f in bnos: t = '%s/%s' % (tmpdir, f) - fo = open(t, 'w') - for line in open(f, 'r'): - fld = line.split(None) - print(fld[0], fld[1], int(fld[2])-int(fld[1]), file=fo) - fo.close() + with open(t, 'w') as fo: + with open(f, 'r') as fi: + for line in fi: + fld = line.split(None) + print(fld[0], fld[1], int(fld[2])-int(fld[1]), file=fo) t = t[t.rfind('/')+1:] - if plot_cmd == None: plot_cmd = "splot '%s'" % t + if plot_cmd is None: plot_cmd = "splot '%s'" % t else: plot_cmd = "%s,'%s'" % (plot_cmd, t) - fo = open('%s/plot.cmds' % tmpdir, 'w') - print(cmds, file=fo) - if len(bnos) > 10 or keys_below: print('set key below', file=fo) - print(plot_cmd, file=fo) - fo.close() + with open('%s/plot.cmds' % tmpdir, 'w') as fo: + print(cmds, file=fo) + if len(bnos) > 10 or keys_below: print('set key below', file=fo) + print(plot_cmd, file=fo) pid = os.fork() if pid == 0: @@ -125,4 +124,4 @@ sys.exit(1) os.waitpid(pid, 0) - os.system('/bin/rm -rf ' + tmpdir) + shutil.rmtree(tmpdir) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/btt/btt_plot.py new/blktrace-1.3.0+git.20210628/btt/btt_plot.py --- old/blktrace-1.2.0+git.20180516/btt/btt_plot.py 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/btt/btt_plot.py 2021-06-28 21:41:32.000000000 +0200 @@ -57,6 +57,7 @@ from __future__ import absolute_import from __future__ import print_function +import getopt, glob, os, sys import six from six.moves import range __author__ = 'Alan D. Brunelle <alan.brune...@hp.com>' @@ -65,7 +66,6 @@ import matplotlib matplotlib.use('Agg') -import getopt, glob, os, sys import matplotlib.pyplot as plt plot_size = [10.9, 8.4] # inches... @@ -113,8 +113,8 @@ """Returns new min, max, and float value for those passed in""" v = float(v) - if mn == None or v < mn: mn = v - if mx == None or v > mx: mx = v + if mn is None or v < mn: mn = v + if mx is None or v > mx: mx = v return mn, mx, v #-------------------------------------------------------------- @@ -125,10 +125,7 @@ def _avg(vals): """Computes average for array of values passed""" - total = 0.0 - for val in vals: - total += val - return total / len(vals) + return sum(vals) / len(vals) #------------------------------------------------------ if len(xs) < 1000: @@ -171,14 +168,15 @@ xs = [] ys = [] - for line in open(file, 'r'): - f = line.rstrip().split(None) - if line.find('#') == 0 or len(f) < 2: - continue - (min_x, max_x, x) = check(min_x, max_x, f[0]) - (min_y, max_y, y) = check(min_y, max_y, f[1]) - xs.append(x) - ys.append(y) + with open(file, 'r') as fi: + for line in fi: + f = line.rstrip().split(None) + if line.find('#') == 0 or len(f) < 2: + continue + (min_x, max_x, x) = check(min_x, max_x, f[0]) + (min_y, max_y, y) = check(min_y, max_y, f[1]) + xs.append(x) + ys.append(y) db[file] = {'x':xs, 'y':ys} if len(xs) > 10: @@ -238,7 +236,7 @@ elif o in ('-v', '--verbose'): verbose = True - if type == None and not generate_all: + if type is None and not generate_all: fatal('Need type of data files to process - (-t <type>)') return args @@ -247,7 +245,7 @@ def gen_title(fig, type, title_str): """Sets the title for the figure based upon the type /or/ user title""" - if title_str != None: + if title_str is not None: pass elif type == 'aqd': title_str = 'Average Queue Depth' @@ -312,7 +310,7 @@ #---------------------------------------------------------------------- global add_legend, output_file, title_str, verbose - if output_file != None: + if output_file is not None: ofile = output_file else: ofile = '%s.png' % type @@ -343,7 +341,7 @@ if type == 'bnos': ax.plot(dat['x'], dat['y'], color(idx, 'marker'), markersize=1) - elif dat['ax'] == None: + elif dat['ax'] is None: continue # Don't add legend else: ax.plot(dat['ax'], dat['ay'], color(idx, 'line'), @@ -352,7 +350,7 @@ legends.append(get_base(file)) idx += 1 - if add_legend and len(legends) > 0: + if add_legend and legends: gen_legends(ax, legends) plt.savefig(ofile) @@ -388,23 +386,23 @@ def get_live_data(fn): xs = [] ys = [] - for line in open(fn, 'r'): - f = line.rstrip().split() - if f[0] != '#' and len(f) == 2: - xs.append(float(f[0])) - ys.append(float(f[1])) + with open(fn, 'r') as fi: + for line in fi: + f = line.rstrip().split() + if f[0] != '#' and len(f) == 2: + xs.append(float(f[0])) + ys.append(float(f[1])) return xs, ys #---------------------------------------------------------------------- def live_sort(a, b): if a[0] == 'sys' and b[0] == 'sys': return 0 - elif a[0] == 'sys' or a[2][0] < b[2][0]: + if a[0] == 'sys' or a[2][0] < b[2][0]: return -1 - elif b[0] == 'sys' or a[2][0] > b[2][0]: + if b[0] == 'sys' or a[2][0] > b[2][0]: return 1 - else: - return 0 + return 0 #---------------------------------------------------------------------- def turn_off_ticks(ax): @@ -453,7 +451,7 @@ output_file = title_str = type = None for t in types: files = get_files(t) - if len(files) == 0: + if files == 0: continue elif t == 'bnos': do_bnos(files) @@ -463,7 +461,7 @@ generate_output(t, get_data(files)) continue - elif len(files) < 1: + elif not files: fatal('Need data files to process') else: generate_output(type, get_data(files)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/doc/blkparse.1 new/blktrace-1.3.0+git.20210628/doc/blkparse.1 --- old/blktrace-1.2.0+git.20180516/doc/blkparse.1 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/doc/blkparse.1 2021-06-28 21:41:32.000000000 +0200 @@ -165,6 +165,21 @@ Displays data sorted by program .RE +\-S \fIevent\fR +.br +\-\-sort\-program\-stats=\fIevent\fR +.br +.RS +Displays each program's data sorted by program name or io event, like +Queued, Read, Write and Complete. When \-S is specified the \-s will be ignored. +The capital letters Q,R,W,C stand for KB, then q/r/w/c stand for IO. + +If you want to soct programs by how many data they queued, you can use: + +blkparse -i sda.blktrace. -q \-S Q \-o sda.parse +.RE + + \-t .br \-\-track\-ios @@ -317,6 +332,10 @@ .IP \fBe\fR 4 Error value +.IP \fBg\fR 4 +Cgroup identifier of the cgroup that generated the IO. Note that this requires +appropriate kernel support (kernel version at least 4.14). + .IP \fBm\fR 4 Minor number of event's device. @@ -353,6 +372,9 @@ .IP \fBU\fR 4 Payload unsigned integer +.IP \fBz\fR 4 +The absolute time, as local time in your time zone, with no date displayed + .PP Note that the user can optionally specify field display width, and optionally a left-aligned specifier. These precede field specifiers, with a '%' character, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/doc/blktrace.tex new/blktrace-1.3.0+git.20210628/doc/blktrace.tex --- old/blktrace-1.2.0+git.20180516/doc/blktrace.tex 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/doc/blktrace.tex 2021-06-28 21:41:32.000000000 +0200 @@ -601,6 +601,9 @@ the event's device \\ & (separated by a comma). \\ \hline \emph{e} & Error value \\ \hline +\emph{g} & Cgroup identifier of the cgroup that generated the IO. Note that this requires +appropriate \\ + & kernel support (kernel version at least 4.14). \\ \hline \emph{m} & Minor number of event's device. \\ \hline \emph{M} & Major number of event's device. \\ \hline \emph{n} & Number of blocks \\ \hline @@ -613,6 +616,7 @@ \emph{T} & Time stamp (seconds) \\ \hline \emph{u} & Elapsed value in microseconds (\emph{-t} command line option) \\ \hline \emph{U} & Payload unsigned integer \\ \hline +\emph{z} & Absolute time stamp \\ \hline \end{tabular} Note that the user can optionally specify field display width, and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/iowatcher/blkparse.c new/blktrace-1.3.0+git.20210628/iowatcher/blkparse.c --- old/blktrace-1.2.0+git.20180516/iowatcher/blkparse.c 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/iowatcher/blkparse.c 2021-06-28 21:41:32.000000000 +0200 @@ -36,6 +36,7 @@ #include "blkparse.h" #include "list.h" #include "tracers.h" +#include "../blktrace_api.h" #define IO_HASH_TABLE_BITS 11 #define IO_HASH_TABLE_SIZE (1 << IO_HASH_TABLE_BITS) @@ -49,111 +50,8 @@ extern int plot_io_action; extern int io_per_process; -/* - * Trace categories - */ -enum { - BLK_TC_READ = 1 << 0, /* reads */ - BLK_TC_WRITE = 1 << 1, /* writes */ - BLK_TC_FLUSH = 1 << 2, /* flush */ - BLK_TC_SYNC = 1 << 3, /* sync */ - BLK_TC_QUEUE = 1 << 4, /* queueing/merging */ - BLK_TC_REQUEUE = 1 << 5, /* requeueing */ - BLK_TC_ISSUE = 1 << 6, /* issue */ - BLK_TC_COMPLETE = 1 << 7, /* completions */ - BLK_TC_FS = 1 << 8, /* fs requests */ - BLK_TC_PC = 1 << 9, /* pc requests */ - BLK_TC_NOTIFY = 1 << 10, /* special message */ - BLK_TC_AHEAD = 1 << 11, /* readahead */ - BLK_TC_META = 1 << 12, /* metadata */ - BLK_TC_DISCARD = 1 << 13, /* discard requests */ - BLK_TC_DRV_DATA = 1 << 14, /* binary driver data */ - BLK_TC_FUA = 1 << 15, /* fua requests */ - - BLK_TC_END = 1 << 15, /* we've run out of bits! */ -}; - -#define BLK_TC_SHIFT (16) -#define BLK_TC_ACT(act) ((act) << BLK_TC_SHIFT) #define BLK_DATADIR(a) (((a) >> BLK_TC_SHIFT) & (BLK_TC_READ | BLK_TC_WRITE)) - -/* - * Basic trace actions - */ -enum { - __BLK_TA_QUEUE = 1, /* queued */ - __BLK_TA_BACKMERGE, /* back merged to existing rq */ - __BLK_TA_FRONTMERGE, /* front merge to existing rq */ - __BLK_TA_GETRQ, /* allocated new request */ - __BLK_TA_SLEEPRQ, /* sleeping on rq allocation */ - __BLK_TA_REQUEUE, /* request requeued */ - __BLK_TA_ISSUE, /* sent to driver */ - __BLK_TA_COMPLETE, /* completed by driver */ - __BLK_TA_PLUG, /* queue was plugged */ - __BLK_TA_UNPLUG_IO, /* queue was unplugged by io */ - __BLK_TA_UNPLUG_TIMER, /* queue was unplugged by timer */ - __BLK_TA_INSERT, /* insert request */ - __BLK_TA_SPLIT, /* bio was split */ - __BLK_TA_BOUNCE, /* bio was bounced */ - __BLK_TA_REMAP, /* bio was remapped */ - __BLK_TA_ABORT, /* request aborted */ - __BLK_TA_DRV_DATA, /* binary driver data */ -}; - -#define BLK_TA_MASK ((1 << BLK_TC_SHIFT) - 1) - -/* - * Notify events. - */ -enum blktrace_notify { - __BLK_TN_PROCESS = 0, /* establish pid/name mapping */ - __BLK_TN_TIMESTAMP, /* include system clock */ - __BLK_TN_MESSAGE, /* Character string message */ -}; - -/* - * Trace actions in full. Additionally, read or write is masked - */ -#define BLK_TA_QUEUE (__BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_BACKMERGE (__BLK_TA_BACKMERGE | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_FRONTMERGE (__BLK_TA_FRONTMERGE | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_GETRQ (__BLK_TA_GETRQ | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_SLEEPRQ (__BLK_TA_SLEEPRQ | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_REQUEUE (__BLK_TA_REQUEUE | BLK_TC_ACT(BLK_TC_REQUEUE)) -#define BLK_TA_ISSUE (__BLK_TA_ISSUE | BLK_TC_ACT(BLK_TC_ISSUE)) -#define BLK_TA_COMPLETE (__BLK_TA_COMPLETE| BLK_TC_ACT(BLK_TC_COMPLETE)) -#define BLK_TA_PLUG (__BLK_TA_PLUG | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_UNPLUG_IO (__BLK_TA_UNPLUG_IO | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_UNPLUG_TIMER (__BLK_TA_UNPLUG_TIMER | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_INSERT (__BLK_TA_INSERT | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_SPLIT (__BLK_TA_SPLIT) -#define BLK_TA_BOUNCE (__BLK_TA_BOUNCE) -#define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_ABORT (__BLK_TA_ABORT | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_DRV_DATA (__BLK_TA_DRV_DATA | BLK_TC_ACT(BLK_TC_DRV_DATA)) - -#define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY)) -#define BLK_TN_TIMESTAMP (__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY)) -#define BLK_TN_MESSAGE (__BLK_TN_MESSAGE | BLK_TC_ACT(BLK_TC_NOTIFY)) - -#define BLK_IO_TRACE_MAGIC 0x65617400 -#define BLK_IO_TRACE_VERSION 0x07 -/* - * The trace itself - */ -struct blk_io_trace { - __u32 magic; /* MAGIC << 8 | version */ - __u32 sequence; /* event number */ - __u64 time; /* in nanoseconds */ - __u64 sector; /* disk offset */ - __u32 bytes; /* transfer length */ - __u32 action; /* what happened */ - __u32 pid; /* who did it */ - __u32 device; /* device identifier (dev_t) */ - __u32 cpu; /* on what cpu did it happen */ - __u16 error; /* completion error */ - __u16 pdu_len; /* length of data after this trace */ -}; +#define BLK_TA_MASK (((1 << BLK_TC_SHIFT) - 1) & ~__BLK_TA_CGROUP) struct pending_io { /* sector offset of this IO */ @@ -362,18 +260,23 @@ { struct blk_io_trace *io = trace->io; void *payload = (char *)io + sizeof(*io); + int pdu_len = io->pdu_len; u32 two32[2]; - if (io->action == BLK_TN_PROCESS) { + if (io->action & __BLK_TN_CGROUP) { + payload += sizeof(struct blk_io_cgroup_payload); + pdu_len -= sizeof(struct blk_io_cgroup_payload); + } + if ((io->action & ~__BLK_TN_CGROUP) == BLK_TN_PROCESS) { if (io_per_process) process_hash_insert(io->pid, payload); return; } - if (io->action != BLK_TN_TIMESTAMP) + if ((io->action & ~__BLK_TN_CGROUP) != BLK_TN_TIMESTAMP) return; - if (io->pdu_len != sizeof(two32)) + if (pdu_len != sizeof(two32)) return; memcpy(two32, payload, sizeof(two32)); @@ -411,11 +314,16 @@ char *message; if (!(test->action & BLK_TC_ACT(BLK_TC_NOTIFY))) return 1; - if (test->action == BLK_TN_MESSAGE) { + if ((test->action & ~__BLK_TN_CGROUP) == BLK_TN_MESSAGE) { int len = test->pdu_len; + + message = (char *)(test + 1); + if (test->action & __BLK_TN_CGROUP) { + len -= sizeof(struct blk_io_cgroup_payload); + message += sizeof(struct blk_io_cgroup_payload); + } if (len < 3) return 0; - message = (char *)(test + 1); if (strncmp(message, "fio ", 4) == 0) { return 1; } @@ -474,13 +382,17 @@ if (!(test->action & BLK_TC_ACT(BLK_TC_NOTIFY))) return -1; - if (test->action != BLK_TN_MESSAGE) + if ((test->action & ~__BLK_TN_CGROUP) != BLK_TN_MESSAGE) return -1; + message = (char *)(test + 1); + if (test->action & __BLK_TN_CGROUP) { + len -= sizeof(struct blk_io_cgroup_payload); + message += sizeof(struct blk_io_cgroup_payload); + } /* the message is fio rw bank offset num_banks */ if (len < 3) return -1; - message = (char *)(test + 1); if (strncmp(message, "fio r ", 6) != 0) return -1; @@ -1099,16 +1011,28 @@ if (action == __BLK_TA_QUEUE) { if (io->sector == 0) return; - if (trace->found_issue || trace->found_completion) { - pio = hash_queued_io(trace->io); - /* - * When there are no ISSUE events count depth and - * latency at least from queue events - */ - if (pio && !trace->found_issue) { - pio->dispatch_time = io->time; - goto account_io; - } + /* + * 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; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/blktrace-1.2.0+git.20180516/iowatcher/main.c new/blktrace-1.3.0+git.20210628/iowatcher/main.c --- old/blktrace-1.2.0+git.20180516/iowatcher/main.c 2018-05-16 21:09:58.000000000 +0200 +++ new/blktrace-1.3.0+git.20210628/iowatcher/main.c 2021-06-28 21:41:32.000000000 +0200 @@ -1043,9 +1043,14 @@ static void convert_movie_files(char *movie_dir) { + long nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + + if (nr_cpus < 0) + nr_cpus = 8; + fprintf(stderr, "Converting svg files in %s\n", movie_dir); - snprintf(line, line_len, "find %s -name \\*.svg | xargs -I{} -n 1 -P 8 rsvg-convert -o {}.png {}", - movie_dir); + snprintf(line, line_len, "find %s -name \\*.svg | xargs -I{} -n 1 -P %ld rsvg-convert -o {}.png {}", + movie_dir, nr_cpus); system_check(line); }