Hello community, here is the log from the commit of package ioping for openSUSE:Factory checked in at 2020-03-16 10:18:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ioping (Old) and /work/SRC/openSUSE:Factory/.ioping.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ioping" Mon Mar 16 10:18:54 2020 rev:4 rq:785100 version:1.2 Changes: -------- --- /work/SRC/openSUSE:Factory/ioping/ioping.changes 2017-03-31 15:09:54.688787952 +0200 +++ /work/SRC/openSUSE:Factory/.ioping.new.3160/ioping.changes 2020-03-16 10:19:42.847620859 +0100 @@ -1,0 +2,11 @@ +Fri Mar 13 13:29:05 UTC 2020 - Paolo Stivanin <[email protected]> + +- Update to 1.2: + * ioping: add -r, -rate-limit + * ioping: option -J|-json for printing JSON + * ioping: add option -a|-warmup + * ioping: add long options + * ioping: print filesystem size for file or directory target + * ioping.1: raw statisitics in nanoseconds + +------------------------------------------------------------------- Old: ---- ioping-1.0.tar.gz New: ---- ioping-1.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ioping.spec ++++++ --- /var/tmp/diff_new_pack.F175Jz/_old 2020-03-16 10:19:43.523621134 +0100 +++ /var/tmp/diff_new_pack.F175Jz/_new 2020-03-16 10:19:43.527621136 +0100 @@ -1,7 +1,7 @@ # # spec file for package ioping # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,17 +12,17 @@ # 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/ # Name: ioping -Version: 1.0 +Version: 1.2 Release: 0 Summary: A tool to monitor I/O latency in real time -License: GPL-3.0+ +License: GPL-3.0-or-later Group: System/Benchmark -Url: https://github.com/koct9i/ioping +URL: https://github.com/koct9i/ioping Source: https://github.com/koct9i/ioping/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz %description @@ -33,7 +33,7 @@ %setup -q %build -make %{?_smp_mflags} CFLAGS="%{optflags} -std=gnu99" +%make_build CFLAGS="%{optflags} -std=gnu99" %install install -D -p -m 0755 %{name} \ @@ -42,9 +42,9 @@ %{buildroot}%{_mandir}/man1/%{name}.1 %files -%defattr(-,root,root,-) -%doc LICENSE README.md changelog +%license LICENSE +%doc README.md changelog %{_bindir}/ioping -%{_mandir}/man1/ioping.1%{ext_man} +%{_mandir}/man1/ioping.1%{?ext_man} %changelog ++++++ ioping-1.0.tar.gz -> ioping-1.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ioping-1.0/Makefile new/ioping-1.2/Makefile --- old/ioping-1.0/Makefile 2016-12-11 12:54:54.000000000 +0100 +++ new/ioping-1.2/Makefile 2020-02-02 14:37:55.000000000 +0100 @@ -6,7 +6,6 @@ MAN1DIR=$(PREFIX)/share/man/man1 SRCS=ioping.c -OBJS=$(SRCS:.c=.o) BINARY=ioping MANS=ioping.1 MANS_F=$(MANS:.1=.txt) $(MANS:.1=.pdf) @@ -14,11 +13,16 @@ SPEC=ioping.spec PACKAGE=ioping -EXTRA_VERSION:=$(shell test -d .git && git describe --tags --dirty=+ | sed 's/^v[^-]*//;s/-/./g') -VERSION:=$(shell sed -ne 's/\# define VERSION \"\(.*\)\"/\1/p' ioping.c)${EXTRA_VERSION} +GIT_VER:=$(shell test -d .git && git describe --tags --match 'v[0-9]*' \ + --abbrev=0 | sed 's/v//') +SRC_VER:=$(shell sed -ne 's/\# define VERSION \"\(.*\)\"/\1/p' ioping.c) +EXTRA_VERSION:=$(shell test -d .git && git describe --tags --match 'v[0-9]*' \ + --dirty=+ | sed 's/^v[^-]*//;s/-/./g') +VERSION:=$(SRC_VER)$(EXTRA_VERSION) DISTDIR=$(PACKAGE)-$(VERSION) DISTFILES=$(SRCS) $(MANS) $(DOCS) $(SPEC) Makefile PACKFILES=$(BINARY) $(MANS) $(MANS_F) $(DOCS) +CPPFLAGS+=-DEXTRA_VERSION=\"${EXTRA_VERSION}\" STRIP=strip TARGET=$(shell ${CC} -dumpmachine) @@ -35,13 +39,20 @@ LIBS=-lm endif -all: $(BINARY) +all: checkver $(BINARY) -version: +version: checkver @echo ${VERSION} +checkver: + @if test -n "$(GIT_VER)" -a "$(GIT_VER)" != "$(SRC_VER)"; then \ + echo "ERROR: Version mismatch between git and source"; \ + echo git: $(GIT_VER), src: $(SRC_VER); \ + exit 1; \ + fi + clean: - $(RM) -f $(OBJS) $(BINARY) $(MANS_F) ioping.tmp + $(RM) -f $(BINARY) $(MANS_F) ioping.tmp strip: $(BINARY) $(STRIP) $^ @@ -58,9 +69,6 @@ mkdir -p $(DESTDIR)$(MAN1DIR) install -m 644 $(MANS) $(DESTDIR)$(MAN1DIR) -%.o: %.c - $(CC) $(CFLAGS) $(CPPFLAGS) -DEXTRA_VERSION=\"${EXTRA_VERSION}\" -c -o $@ $< - %.ps: %.1 man -t ./$< > $@ @@ -70,20 +78,20 @@ %.txt: %.1 MANWIDTH=80 man ./$< | col -b > $@ -$(BINARY): $(OBJS) +$(BINARY): $(SRCS) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS) -dist: $(DISTFILES) +dist: checkver $(DISTFILES) tar -cz --transform='s,^,$(DISTDIR)/,S' $^ -f $(DISTDIR).tar.gz -binary-tgz: $(PACKFILES) +binary-tgz: checkver $(PACKFILES) ${STRIP} ${BINARY} tar -cz --transform='s,^,$(DISTDIR)/,S' -f ${PACKAGE}-${VERSION}-${TARGET}.tgz $^ -binary-zip: $(PACKFILES) +binary-zip: checkver $(PACKFILES) ${STRIP} ${BINARY} ln -s . $(DISTDIR) zip ${PACKAGE}-${VERSION}-${TARGET}.zip $(addprefix $(DISTDIR)/,$^) rm $(DISTDIR) -.PHONY: all clean install dist version +.PHONY: all version checkver clean strip test install dist binary-tgz binary-zip diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ioping-1.0/README.md new/ioping-1.2/README.md --- old/ioping-1.0/README.md 2016-12-11 12:54:54.000000000 +0100 +++ new/ioping-1.2/README.md 2020-02-02 14:37:55.000000000 +0100 @@ -1,7 +1,7 @@ ioping ====== -An tool to monitor I/O latency in real time. +A tool to monitor I/O latency in real time. It shows disk latency in the same way as ping shows network latency. Homepage: https://github.com/koct9i/ioping/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ioping-1.0/changelog new/ioping-1.2/changelog --- old/ioping-1.0/changelog 2016-12-11 12:54:54.000000000 +0100 +++ new/ioping-1.2/changelog 2020-02-02 14:37:55.000000000 +0100 @@ -1,4 +1,37 @@ +v1.2 / 2020-02-02 +================== + + * makefile: merge compiling and linking + * ioping: add -r, -rate-limit + * ioping: reformat usage + * Merge pull request #42 from kohju/patch-Solaris + * Support for Solaris. + * ioping: option -J|-json for printing JSON + * ioping: add option -a|-warmup <count> + * ioping: add long options + * ioping: print filesystem size for file or directory target + * Merge pull request #39 from justinpitts/patch-1 + * Fix grammar mistake. + +v1.1 / 2018-09-11 +================== + + * ioping: release 1.1 + * ioping.1: raw statisitics in nanoseconds + * Merge pull request #37 from standby24x7/fix-man + * Fix a typo in ioping.1 + * Merge pull request #36 from lewellyn/solaris + * Correct Solaris predefined macro + * ioping.1: add more references + * Merge pull request #32 from kolyshkin/makefile + * Makefile: only use vN tags for EXTRA_VERSION + * ioping.c: set VERSION to 1.0 + * Makefile: make sure git tag == src ver + * Makefile: make all phony targets as such + * Makefile: move -D to CPPFLAGS + * ioping(1): fix aio description + v1.0 / 2016-12-11 ================= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ioping-1.0/ioping.1 new/ioping-1.2/ioping.1 --- old/ioping-1.0/ioping.1 2016-12-11 12:54:54.000000000 +0100 +++ new/ioping-1.2/ioping.1 2020-02-02 14:37:55.000000000 +0100 @@ -3,10 +3,12 @@ ioping \- simple disk I/O latency monitoring tool .SH SYNOPSYS .SY ioping -.OP \-ABCDLRWGYykq +.OP \-ABCDJLRWGYykq +.OP \-a count .OP \-c count .OP \-i interval .OP \-l speed +.OP \-r rate .OP \-t time .OP \-T time .OP \-s size @@ -27,96 +29,113 @@ latency in real time. .SH OPTIONS .TP -.BI \-c \ count -Stop after \fIcount\fR requests. +\fB\-a\fR, \fB\-warmup\fR \fIcount\fR +Ignore in statistics first \fIcount\fR requests, default 1. .TP -.BI \-i \ interval -Set time between requests to \fIinterval\fR (\fB1s\fR). +\fB\-c\fR, \fB\-count\fR \fIcount\fR +Stop after \fIcount\fR requests, default \fB0\fR (infinite). .TP -.BI \-l \ speed -Set \fIspeed\fR limit in bytes per second. Set interval to request-size / speed. +\fB\-i\fR, \fB\-interval\fR \fItime\fR +Set \fItime\fR between requests, default \fB1s\fR. .TP -.BI \-t \ time +\fB\-l\fR, \fB\-speed-limit\fR \fIsize\fR +Set speed limit in \fIsize\fR per second. Increases interval to request-size / speed. +.TP +\fB\-r\fR, \fB\-rate-limit\fR \fIcount\fR +Set rate limit in \fIcount\fR per second. Increases interval to 1 / rate. +.TP +\fB\-t\fR, \fB\-min\-time\fR \fItime\fR Minimal valid request time (\fB0us\fR). Too fast requests are ignored in statistics. .TP -.BI \-T \ time +\fB\-T\fR, \fB\-max\-time\fR \fItime\fR Maximum valid request time. Too slow requests are ignored in statistics. .TP -.BI \-s \ size -Request size (\fB4k\fR). +\fB\-s\fR, \fB\-size\fR \fIsize\fR +Request size, default \fB4k\fR. .TP -.BI \-S \ wsize +\fB\-S\fR, \fB\-work\-size\fR \fIsize\fR Working set size (\fB1m\fR for directory, whole size for file or device). .TP -.BI \-o \ offset +\fB\-o\fR, \fB\-work\-offset\fR \fIsize\fR Starting offset in the file/device (0). .TP -.BI \-w \ deadline -Stop after \fIdeadline\fR time passed. +\fB\-w\fR, \fB\-work\-time\fR \fItime\fR +Stop after \fItime\fR passed, default \fB0\fR (infinite). .TP -.BI \-p \ period -Print raw statistics for every \fIperiod\fR requests (see format below). +\fB\-p\fR, \fB\-print\-count\fR \fIcount\fR +Print raw statistics for every \fIcount\fR requests (see format below). .TP -.BI \-P \ period -Print raw statistics for every \fIperiod\fR in time. +\fB\-P\fR, \fB\-print\-interval\fR \fItime\fR +Print raw statistics for every \fItime\fR. .TP -.B \-A -Use asynchronous I/O (syscalls \fBio_submit\fR(2), \fBio_submit\fR(2), etc). +\fB\-A\fR, \fB\-async\fR +Use asynchronous I/O (\fBio_setup\fR(2), \fBio_submit\fR(2) etc syscalls). .TP -.B \-B +\fB\-B\fR, \fB\-batch\fR Batch mode. Be quiet and print final statistics in raw format. .TP -.B \-C +\fB\-C\fR, \fB\-cached\fR Use cached I/O. Suppress cache invalidation via \fBposix_fadvise\fR(2)) before read and \fBfdatasync\fR(2) after each write. .TP -.B \-D +\fB\-D\fR, \fB\-direct\fR Use direct I/O (see \fBO_DIRECT\fR in \fBopen\fR(2)). .TP -.B \-L +\fB\-J\fR, \fB\-json\fR +Print output in JSON format. +.TP +\fB\-L\fR, \fB\-linear\fR Use sequential operations rather than random. This also sets default request -size to \fB256k\fR (as in \fB-s 256k\fR). +size to \fB256k\fR (as in \fB-size 256k\fR). .TP -.B \-R -Disk seek rate test. This option suppress human-readable output for each -request (as \fB-q\fR), sets default interval to zero (\fB-i 0\fR), stops -measurement after 3 seconds (\fB-w 3\fR) and increases default working set -size to 64m (\fB-S 64m\fR). Working set (\fB-S\fR) should be increased -accordingly if disk has huge cache. -.TP -.B \-W -Use writes rather than reads. Safe for directory target. Write I/O gives -more reliable results for systems where non-cached reads are not supported or -cached at some level. Might be \fB*DANGEROUS*\fR for file/device: it will -shred your data. In this case should be repeated tree times (\fB-WWW\fR). +\fB\-R\fR, \fB\-rapid\fR +Disk seek rate test, or bandwidth test if used together with \fB-linear\fR. + +This option suppress human-readable output for each request +(as \fB-quiet\fR), sets default interval to zero (\fB-interval 0\fR), +stops measurement after 3 seconds (\fB-work-time 3\fR) and +increases default working set size to 64m (\fB-work-size 64m\fR). +Working set (\fB-work-size\fR) should be increased accordingly if disk has +huge hardware cache. +.TP +\fB\-W\fR, \fB\-write\fR +Use writes rather than reads. Safe for temporary file in directory target. +Write I/O gives more reliable results for systems where non-cached reads are +not supported or cached at some level. +.IP +Might be \fB*DANGEROUS*\fR for file/device: it will shred your data. +In this case should be repeated three times (\fB-WWW\fR). .TP -.B \-G +\fB\-G\fR, \fB\-read\-write\fR Alternate read and write requests. .TP -.B \-Y +\fB\-Y\fR, \fB\-sync\fR Use sync I/O (see \fBO_SYNC\fR in \fBopen\fR(2)). .TP -.B \-y +\fB\-y\fR, \fB\-dsync\fR Use data sync I/O (see \fBO_DSYNC\fR in \fBopen\fR(2)). .TP -.BI \-k +\fB\-k\fR, \fB\-keep\fR Keep and reuse temporary working file "ioping.tmp" (only for directory target). .TP -.B \-q +\fB\-q\fR, \fB\-quiet\fR Suppress periodical human-readable output. .TP -.B \-h +\fB\-h\fR, \fB\-help\fR Display help message and exit. .TP -.B \-v +\fB\-v\fR, \fB\-version\fR Display version and exit. .SS Argument suffixes -For options that expect time argument (\fB\-i\fR, \fB\-P\fR and \fB\-w\fR), +For options that expect time argument (\fB\-interval\fR, \fB\-print-interval\fR and \fB\-work-time\fR), default is seconds, unless you specify one of the following suffixes (case-insensitive): .TP +.BR ns ,\ nsec +nanoseconds (a billionth of a second, 1 / 1 000 000 000) +.TP .BR us ,\ usec microseconds (a millionth of a second, 1 / 1 000 000) .TP @@ -132,7 +151,8 @@ .BR h ,\ hour hours .PP -For options that expect "size" argument (\fB\-s\fR, \fB\-S\fR and \fB\-o\fR), +For options that expect "size" argument (\fB\-size\fR, \fB-speed-limit\fR, +\fB\-work-size\fR and \fB\-work-offset\fR), default is bytes, unless you specify one of the following suffixes (case-insensitive): .TP @@ -154,7 +174,7 @@ .BR TiB ,\ t ,\ tb terabytes (1 099 511 627 776 bytes) .PP -For options that expect "number" argument (\fB-p\fR and \fB-c\fR) you +For options that expect "number" argument (\fB-count\fR and \fB-print-count\fR) you can optionally specify one of the following suffixes (case-insensitive): .TP .B k @@ -180,36 +200,36 @@ .B 3 Error during runtime. .SH RAW STATISTICS -.B ioping -p 100 -c 200 -i 0 -q . +.B ioping -print-count 100 -count 200 -interval 0 -quiet . .ad l .br -\f(CW100 26694 3746 15344272 188 267 1923 228 100 26694 +\f(CW99 10970974 9024 36961531 90437 110818 358872 30756 100 12516420 .br -100 24165 4138 16950134 190 242 2348 214 100 24165 +100 9573265 10446 42785821 86849 95733 154609 10548 100 10649035 .br -(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) +(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) .br .br (1) count of requests in statistics .br -(2) running time (usec) +(2) running time (nanoseconds) .br (3) requests per second (iops) .br -(4) transfer speed (bytes/sec) +(4) transfer speed (bytes per second) .br -(5) minimal request time (usec) +(5) minimal request time (nanoseconds) .br -(6) average request time (usec) +(6) average request time (nanoseconds) .br -(7) maximum request time (usec) +(7) maximum request time (nanoseconds) .br -(8) request time standard deviation (usec) +(8) request time standard deviation (nanoseconds) .br -(9) total requests (including too slow and too fast) +(9) total requests (including warmup, too slow or too fast) .br -(10) total running time (usec) +(10) total running time (nanoseconds) .SH EXAMPLES .TP .B ioping . @@ -232,7 +252,10 @@ .BR iostat (1), .BR dd (1), .BR fio (1), +.BR stress (1), +.BR stress-ng (1), .BR dbench (1), +.BR sysbench (1), .BR fsstress, .BR xfstests, .BR hdparm (8), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ioping-1.0/ioping.c new/ioping-1.2/ioping.c --- old/ioping-1.0/ioping.c 2016-12-11 12:54:54.000000000 +0100 +++ new/ioping-1.2/ioping.c 2020-02-02 14:37:55.000000000 +0100 @@ -19,7 +19,7 @@ */ #ifndef VERSION -# define VERSION "0.9" +# define VERSION "1.2" #endif #ifndef EXTRA_VERSION @@ -45,6 +45,8 @@ #include <sys/time.h> #include <sys/stat.h> +#define HAVE_GETOPT_LONG_ONLY + #ifdef __linux__ # include <sys/ioctl.h> # include <sys/mount.h> @@ -56,6 +58,7 @@ # define HAVE_DIRECT_IO # define HAVE_LINUX_ASYNC_IO # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS # define MAX_RW_COUNT 0x7ffff000 /* 2G - 4K */ #endif @@ -65,6 +68,7 @@ # define HAVE_POSIX_MEMALIGN # define HAVE_MKOSTEMP # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -75,6 +79,7 @@ # define HAVE_MKOSTEMP # define HAVE_DIRECT_IO # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS #endif #ifdef __DragonFly__ @@ -82,6 +87,7 @@ # define HAVE_CLOCK_GETTIME # define HAVE_MKOSTEMP # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS #endif #ifdef __OpenBSD__ @@ -94,6 +100,7 @@ # define HAVE_POSIX_MEMALIGN # define HAVE_MKOSTEMP # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS #endif #ifdef __APPLE__ /* OS X */ @@ -103,15 +110,16 @@ # include <sys/uio.h> # define HAVE_NOCACHE_IO # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS #endif -#ifdef __sun__ /* Solaris */ +#ifdef __sun /* Solaris */ # include <sys/dkio.h> # include <sys/vtoc.h> # define HAVE_CLOCK_GETTIME -# define HAVE_DIRECT_IO -# define O_DIRECT O_DSYNC +# define HAVE_POSIX_FADVICE # define HAVE_ERR_INCLUDE +# define HAVE_STATVFS #endif #ifdef __MINGW32__ /* Windows */ @@ -126,6 +134,10 @@ # define HAVE_POSIX_FDATASYNC #endif +#ifdef HAVE_STATVFS +# include <sys/statvfs.h> +#endif + #ifdef HAVE_ERR_INCLUDE # include <err.h> #else @@ -167,6 +179,7 @@ #endif /* HAVE_ERR_INCLUDE */ #define NSEC_PER_SEC 1000000000ll +#define USEC_PER_SEC 1000000L #ifdef HAVE_CLOCK_GETTIME @@ -180,6 +193,16 @@ return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec; } +static inline double timestamp(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts)) + err(3, "clock_gettime failed"); + + return ts.tv_sec + (double)ts.tv_nsec / NSEC_PER_SEC; +} + #else static inline long long now(void) @@ -192,6 +215,16 @@ return tv.tv_sec * NSEC_PER_SEC + tv.tv_usec * 1000ll; } +static inline double timestamp(void) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL)) + err(3, "gettimeofday failed"); + + return tv.tv_sec + (double)tv.tv_usec / USEC_PER_SEC; +} + #endif /* HAVE_CLOCK_GETTIME */ #ifndef HAVE_MKOSTEMP @@ -297,42 +330,6 @@ } #endif -void usage(void) -{ - fprintf(stderr, - " Usage: ioping [-ABCDRLWYykq] [-c count] [-i interval] [-s size] [-S wsize]\n" - " [-o offset] [-w deadline] [-pP period] directory|file|device\n" - " ioping -h | -v\n" - "\n" - " -c <count> stop after <count> requests\n" - " -i <interval> interval between requests (1s)\n" - " -l <speed> speed limit in bytes per second\n" - " -t <time> minimal valid request time (0us)\n" - " -T <time> maximum valid request time\n" - " -s <size> request size (4k)\n" - " -S <wsize> working set size (1m)\n" - " -o <offset> working set offset (0)\n" - " -w <deadline> stop after <deadline> time passed\n" - " -p <period> print raw statistics for every <period> requests\n" - " -P <period> print raw statistics for every <period> in time\n" - " -A use asynchronous I/O\n" - " -C use cached I/O (no cache flush/drop)\n" - " -B print final statistics in raw format\n" - " -D use direct I/O (O_DIRECT)\n" - " -R seek rate test\n" - " -L use sequential operations\n" - " -W use write I/O (please read manpage)\n" - " -G read-write ping-pong mode\n" - " -Y use sync I/O (O_SYNC)\n" - " -y use data sync I/O (O_DSYNC)\n" - " -k keep and reuse temporary file (ioping.tmp)\n" - " -q suppress human-readable output\n" - " -h display this message and exit\n" - " -v display version and exit\n" - "\n" - ); -} - void version(void) { fprintf(stderr, "ioping %s\n", VERSION EXTRA_VERSION); @@ -397,8 +394,8 @@ { NULL, 0ll }, }; -long long parse_suffix(const char *str, struct suffix *sfx, - long long min, long long max) +double parse_suffix(const char *str, struct suffix *sfx, + long long min, long long max) { char *end; double val, den; @@ -481,7 +478,7 @@ char *path = NULL; char *fstype = ""; char *device = ""; -off_t device_size = 0; +long long device_size = 0; int fd; void *buf; @@ -504,6 +501,7 @@ struct timespec interval_ts; long long deadline = 0; long long speed_limit = 0; +double rate_limit = 0; long long min_valid_time = 0; long long max_valid_time = LLONG_MAX; @@ -518,10 +516,106 @@ off_t offset = 0; off_t woffset = 0; +long long request = 0; +long long warmup_request = 1; long long stop_at_request = 0; +int json = 0; +int json_line = 0; + int exiting = 0; +const char *options = "hvkALRDCWGYBqyi:t:T:w:s:S:c:o:p:P:l:r:a:J"; + +#ifdef HAVE_GETOPT_LONG_ONLY + +static struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + + {"keep", no_argument, NULL, 'k'}, + + {"quiet", no_argument, NULL, 'q'}, + {"batch", no_argument, NULL, 'B'}, + {"json", no_argument, NULL, 'J'}, + + {"rapid", no_argument, NULL, 'R'}, + {"linear", no_argument, NULL, 'L'}, + {"direct", no_argument, NULL, 'D'}, + {"cached", no_argument, NULL, 'C'}, + {"sync", no_argument, NULL, 'Y'}, + {"dsync", no_argument, NULL, 'y'}, + {"async", no_argument, NULL, 'A'}, + {"write", no_argument, NULL, 'W'}, + {"read-write", no_argument, NULL, 'G'}, + + {"size", required_argument, NULL, 's'}, + {"work-size", required_argument, NULL, 'S'}, + {"work-offset", required_argument, NULL, 'o'}, + + {"count", required_argument, NULL, 'c'}, + {"work-time", required_argument, NULL, 'w'}, + + {"interval", required_argument, NULL, 'i'}, + {"speed-limit", required_argument, NULL, 'l'}, + {"rate-limit", required_argument, NULL, 'r'}, + + {"warmup", required_argument, NULL, 'a'}, + {"min-time", required_argument, NULL, 't'}, + {"max-time", required_argument, NULL, 'T'}, + + {"print-count", required_argument, NULL, 'p'}, + {"print-interval", required_argument, NULL, 'P'}, + + {0, 0, NULL, 0}, +}; + +#endif /* HAVE_GETOPT_LONG */ + +void usage(void) +{ + fprintf(stderr, + " Usage: ioping [-ABCDRLWYykq] [-c count] [-i interval] [-s size] [-S wsize]\n" + " [-o offset] [-w deadline] [-pP period] directory|file|device\n" + " ioping -h | -v\n" + "\n" + " options:\n" + " -A, -async use asynchronous I/O\n" + " -C, -cached use cached I/O (no cache flush/drop)\n" + " -D, -direct use direct I/O (O_DIRECT)\n" + " -G, -read-write read-write ping-pong mode\n" + " -L, -linear use sequential operations\n" + " -W, -write use write I/O (please read manpage)\n" + " -Y, -sync use sync I/O (O_SYNC)\n" + " -y, -dsync use data sync I/O (O_DSYNC)\n" + " -R, -rapid test with rapid I/O during 3s (-q -i 0 -w 3)\n" + " -k, -keep keep and reuse temporary file (ioping.tmp)\n" + "\n" + " parameters:\n" + " -a, -warmup <count> ignore <count> first requests (1)\n" + " -c, -count <count> stop after <count> requests\n" + " -i, -interval <time> interval between requests (1s)\n" + " -s, -size <size> request size (4k)\n" + " -S, -work-size <size> working set size (1m)\n" + " -o, -work-offset <size> working set offset (0)\n" + " -w, -work-time <time> stop after <time> passed\n" + " -l, -speed-limit <size> limit speed with <size> per second\n" + " -r, -rate-limit <count> limit rate with <count> per second\n" + "\n" + " output:\n" + " -p, -print-count <count> print raw statistics for every <count> requests\n" + " -P, -print-interval <time> print raw statistics for every <time>\n" + " -t, -min-time <time> minimal valid request time (0us)\n" + " -T, -max-time <time> maximum valid request time\n" + " -B, -batch print final statistics in raw format\n" + " -J, -json print output in JSON format\n" + " -q, -quiet suppress human-readable output\n" + " -h, -help display this message and exit\n" + " -v, -version display version and exit\n" + "\n" + ); +} + void parse_options(int argc, char **argv) { int opt; @@ -531,7 +625,14 @@ exit(1); } - while ((opt = getopt(argc, argv, "hvkALRDCWGYBqyi:t:T:w:s:S:c:o:p:P:l:")) != -1) { + while ((opt = +#ifdef HAVE_GETOPT_LONG_ONLY + getopt_long_only(argc, argv, options, long_options, NULL) +#else + getopt(argc, argv, options) +#endif + ) != -1) { + switch (opt) { case 'h': usage(); @@ -544,8 +645,15 @@ default_size = 1<<18; break; case 'l': + if (!custom_interval) + interval = 0; speed_limit = parse_size(optarg); break; + case 'r': + if (!custom_interval) + interval = 0; + rate_limit = parse_suffix(optarg, int_suffix, 0, NSEC_PER_SEC); + break; case 'R': if (!custom_interval) interval = 0; @@ -612,9 +720,15 @@ quiet = 1; batch_mode = 1; break; + case 'J': + json = 1; + break; case 'c': stop_at_request = parse_int(optarg); break; + case 'a': + warmup_request = parse_int(optarg); + break; case 'k': keep_file = 1; break; @@ -736,7 +850,7 @@ part = label.d_partitions[DISKPART(st->st_rdev)]; blksize = DL_GETPSIZE(&part) * label.d_secsize; -#elif defined(__sun__) +#elif defined(__sun) struct dk_minfo dkmp; ret = ioctl(fd, DKIOCGMEDIAINFO, &dkmp); @@ -1086,9 +1200,11 @@ s->start = start; } -static void add_statistics(struct statistics *s, long long val) { +static int add_statistics(struct statistics *s, long long val) { s->count++; - if (val < min_valid_time) { + if (request <= warmup_request) { + /* warmup */ + } else if (val < min_valid_time) { s->too_fast++; } else if (val > max_valid_time) { s->too_slow++; @@ -1100,7 +1216,10 @@ s->min = val; if (val > s->max) s->max = val; + return 1; } + + return 0; } static void merge_statistics(struct statistics *s, struct statistics *o) { @@ -1152,32 +1271,126 @@ (unsigned long)s->load_time); } +static void json_request(size_t io_size, long long io_time, int valid) +{ + printf("%s{\n" + " \"timestamp\": %f,\n" + " \"target\": {\n" + " \"path\": \"%s\",\n" + " \"fstype\": \"%s\",\n" + " \"device\": \"%s\",\n" + " \"device_size\": %ld\n" + " },\n" + " \"io\": {\n" + " \"request\": %ld,\n" + " \"operation\": \"%s\",\n" + " \"size\": %ld,\n" + " \"time\": %lu,\n" + " \"ignored\": %s\n" + " }\n" + "}", + json_line++ ? "," : "", + timestamp(), + path, + fstype, + device, + (long)device_size, + (long)request, + write_test ? "write" : "read", + (unsigned long)io_size, + (unsigned long)io_time, + valid ? "false" : "true"); + fflush(stdout); +} + +static void json_statistics(struct statistics *s) +{ + printf("%s{\n" + " \"timestamp\": %f,\n" + " \"target\": {\n" + " \"path\": \"%s\",\n" + " \"fstype\": \"%s\",\n" + " \"device\": \"%s\",\n" + " \"device_size\": %ld\n" + " },\n" + " \"stat\": {\n" + " \"count\": %lu,\n" + " \"size\": %lu,\n" + " \"time\": %.0f,\n" + " \"iops\": %f,\n" + " \"bps\": %.0f,\n" + " \"min\": %lu,\n" + " \"avg\": %.0f,\n" + " \"max\": %lu,\n" + " \"mdev\": %.0f\n" + " },\n" + " \"load\": {\n" + " \"count\": %lu,\n" + " \"size\": %lu,\n" + " \"time\": %lu,\n" + " \"iops\": %f,\n" + " \"bps\": %.0f\n" + " }\n" + "}", + json_line++ ? "," : "", + timestamp(), + path, + fstype, + device, + (long)device_size, + (unsigned long)s->valid, + (unsigned long)s->size, + s->sum, + s->iops, + s->speed, + (unsigned long)s->min, + s->avg, + (unsigned long)s->max, + s->mdev, + (unsigned long)s->count, + (unsigned long)s->load_size, + (unsigned long)s->load_time, + s->load_iops, + s->load_speed); + fflush(stdout); +} + int main (int argc, char **argv) { ssize_t ret_size; struct stat st; + int valid; int ret; struct statistics part, total; - long long request, this_time; + long long this_time; long long time_now, time_next, period_deadline; - setvbuf(stdout, NULL, _IOLBF, 0); - parse_options(argc, argv); + if (!json) + setvbuf(stdout, NULL, _IOLBF, 0); + if (!size) size = default_size; if (size <= 0) errx(1, "request size must be greater than zero"); - if (custom_interval && speed_limit) - errx(1, "speed limit and interval cannot be set simultaneously"); + if (speed_limit) { + long long i = size * NSEC_PER_SEC / speed_limit; - if (speed_limit) - interval = size * NSEC_PER_SEC / speed_limit; + if (i > interval) + interval = i; + } + + if (rate_limit) { + long long i = NSEC_PER_SEC / rate_limit; + + if (i > interval) + interval = i; + } #ifdef MAX_RW_COUNT if (size > MAX_RW_COUNT) @@ -1249,7 +1462,7 @@ } else { device_size = st.st_size; fstype = "block"; - device = "device "; + device = "device"; } } else { errx(2, "unsupported destination: \"%s\"", path); @@ -1304,6 +1517,15 @@ err(2, "failed to open \"%s\"", path); } +#ifdef HAVE_STATVFS + if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode)) { + struct statvfs vfs; + + if (!fstatvfs(fd, &vfs)) + device_size = (long long)vfs.f_frsize * vfs.f_blocks; + } +#endif + /* No readahead for non-cached I/O, we'll invalidate it anyway */ if (randomize || !cached) { #ifdef HAVE_POSIX_FADVICE @@ -1325,7 +1547,6 @@ set_signal(); - request = 0; woffset = 0; time_now = now(); @@ -1333,6 +1554,9 @@ start_statistics(&part, time_now); start_statistics(&total, time_now); + if (json) + printf("["); + if (deadline) deadline += time_now; @@ -1384,22 +1608,20 @@ this_time = time_now - this_time; - if (request == 1) { - /* warmup */ - part.count++; - } else { - add_statistics(&part, this_time); - } + valid = add_statistics(&part, this_time); - if (!quiet) { + if (quiet) { + /* silence */ + } else if (json) { + json_request(ret_size, this_time, valid); + } else { print_size(ret_size); - printf(" %s %s (%s %s", write_test ? ">>>" : "<<<", + printf(" %s %s (%s %s ", write_test ? ">>>" : "<<<", path, fstype, device); - if (device_size) - print_size(device_size); + print_size(device_size); printf("): request=%lu time=", (long unsigned)request); print_time(this_time); - if (request == 1) { + if (request <= warmup_request) { printf(" (warmup)"); } else if (this_time < min_valid_time) { printf(" (too fast)"); @@ -1416,10 +1638,13 @@ printf("\n"); } - if ((period_request && (part.count >= period_request)) || + if ((period_request && (part.valid >= period_request)) || (period_time && (time_next >= period_deadline))) { finish_statistics(&part, time_now); - dump_statistics(&part); + if (json) + json_statistics(&part); + else + dump_statistics(&part); merge_statistics(&total, &part); start_statistics(&part, time_now); period_deadline = time_now + period_time; @@ -1454,6 +1679,12 @@ merge_statistics(&total, &part); finish_statistics(&total, time_now); + if (json) { + json_statistics(&total); + printf("]\n"); + return 0; + } + if (batch_mode) { dump_statistics(&total); return 0; @@ -1462,9 +1693,8 @@ if (quiet && (period_time || period_request)) return 0; - printf("\n--- %s (%s %s", path, fstype, device); - if (device_size) - print_size(device_size); + printf("\n--- %s (%s %s ", path, fstype, device); + print_size(device_size); printf(") ioping statistics ---\n"); print_int(total.valid); printf(" requests completed in ");
