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 ");


Reply via email to