Linux NFS development
 help / color / mirror / Atom feed
* [PATCH] nfs-utils: add option to display throughput in MB/s
@ 2026-05-01 20:56 Tigran Mkrtchyan
  2026-05-06 20:33 ` Steve Dickson
  0 siblings, 1 reply; 2+ messages in thread
From: Tigran Mkrtchyan @ 2026-05-01 20:56 UTC (permalink / raw)
  To: steved; +Cc: linux-nfs, Tigran Mkrtchyan

Nowadays,the network bandwidth in kB/s is quite a large number to read.
Thus, let nfsiostat display it in MB/s if requested.

Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
---
 tools/nfs-iostat/nfs-iostat.py | 53 ++++++++++++++++++++++------------
 tools/nfs-iostat/nfsiostat.man | 11 ++++---
 2 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
index 69d24a11..af04aac5 100755
--- a/tools/nfs-iostat/nfs-iostat.py
+++ b/tools/nfs-iostat/nfs-iostat.py
@@ -327,7 +327,7 @@ class DeviceData:
             print()
             print('%d congestion waits' % congestionwaits)
 
-    def __print_rpc_op_stats(self, op, sample_time):
+    def __print_rpc_op_stats(self, op, sample_time, use_mb=False):
         """Print generic stats for one RPC op
         """
         if op not in self.__rpc_data:
@@ -343,9 +343,19 @@ class DeviceData:
         if len(rpc_stats) >= 9:
             errs = float(rpc_stats[8])
 
+        # scale to MB if requested
+        if use_mb:
+            throughput = kilobytes / 1024.0
+            throughput_label = 'MB/s'
+            per_op_label = 'MB/op'
+        else:
+            throughput = kilobytes
+            throughput_label = 'kB/s'
+            per_op_label = 'kB/op'
+
         # prevent floating point exceptions
         if ops != 0:
-            kb_per_op = kilobytes / ops
+            unit_per_op = throughput / ops
             retrans_percent = (retrans * 100) / ops
             rtt_per_op = rtt / ops
             exe_per_op = exe / ops
@@ -353,7 +363,7 @@ class DeviceData:
             if len(rpc_stats) >= 9:
                 errs_percent = (errs * 100) / ops
         else:
-            kb_per_op = 0.0
+            unit_per_op = 0.0
             retrans_percent = 0.0
             rtt_per_op = 0.0
             exe_per_op = 0.0
@@ -364,8 +374,8 @@ class DeviceData:
         op += ':'
         print(format(op.lower(), '<16s'), end='')
         print(format('ops/s', '>8s'), end='')
-        print(format('kB/s', '>16s'), end='')
-        print(format('kB/op', '>16s'), end='')
+        print(format(throughput_label, '>16s'), end='')
+        print(format(per_op_label, '>16s'), end='')
         print(format('retrans', '>16s'), end='')
         print(format('avg RTT (ms)', '>16s'), end='')
         print(format('avg exe (ms)', '>16s'), end='')
@@ -375,8 +385,8 @@ class DeviceData:
         print()
 
         print(format((ops / sample_time), '>24.3f'), end='')
-        print(format((kilobytes / sample_time), '>16.3f'), end='')
-        print(format(kb_per_op, '>16.3f'), end='')
+        print(format((throughput / sample_time), '>16.3f'), end='')
+        print(format(unit_per_op, '>16.3f'), end='')
         retransmits = '{0:>10.0f} ({1:>3.1f}%)'.format(retrans, retrans_percent).strip()
         print(format(retransmits, '>16'), end='')
         print(format(rtt_per_op, '>16.3f'), end='')
@@ -395,9 +405,11 @@ class DeviceData:
             sample_time = 1;
         return (sends / sample_time)
 
-    def display_iostats(self, sample_time, which):
+    def display_iostats(self, sample_time, options):
         """Display NFS and RPC stats in an iostat-like way
         """
+        which = options.which
+        use_mb = options.megabytes
         sends = float(self.__rpc_data['rpcsends'])
         if sample_time == 0:
             sample_time = float(self.__nfs_data['age'])
@@ -423,21 +435,21 @@ class DeviceData:
         print()
 
         if which == 0:
-            self.__print_rpc_op_stats('READ', sample_time)
-            self.__print_rpc_op_stats('WRITE', sample_time)
+            self.__print_rpc_op_stats('READ', sample_time, use_mb)
+            self.__print_rpc_op_stats('WRITE', sample_time, use_mb)
         elif which == 1:
-            self.__print_rpc_op_stats('GETATTR', sample_time)
-            self.__print_rpc_op_stats('ACCESS', sample_time)
+            self.__print_rpc_op_stats('GETATTR', sample_time, use_mb)
+            self.__print_rpc_op_stats('ACCESS', sample_time, use_mb)
             self.__print_attr_cache_stats(sample_time)
         elif which == 2:
-            self.__print_rpc_op_stats('LOOKUP', sample_time)
-            self.__print_rpc_op_stats('READDIR', sample_time)
+            self.__print_rpc_op_stats('LOOKUP', sample_time, use_mb)
+            self.__print_rpc_op_stats('READDIR', sample_time, use_mb)
             if 'READDIRPLUS' in self.__rpc_data:
-                self.__print_rpc_op_stats('READDIRPLUS', sample_time)
+                self.__print_rpc_op_stats('READDIRPLUS', sample_time, use_mb)
             self.__print_dir_cache_stats(sample_time)
         elif which == 3:
-            self.__print_rpc_op_stats('READ', sample_time)
-            self.__print_rpc_op_stats('WRITE', sample_time)
+            self.__print_rpc_op_stats('READ', sample_time, use_mb)
+            self.__print_rpc_op_stats('WRITE', sample_time, use_mb)
             self.__print_page_stats(sample_time)
 
         sys.stdout.flush()
@@ -500,7 +512,7 @@ def print_iostat_summary(old, new, devices, time, options):
 
     count = 1
     for device in devices:
-        display_stats[device].display_iostats(time, options.which)
+        display_stats[device].display_iostats(time, options)
 
         count += 1
         if (count > options.list):
@@ -585,6 +597,11 @@ client are listed.
                             type="int",
                             dest="list",
                             help="only print stats for first LIST mount points")
+    displaygroup.add_option('-m', '--megabytes',
+                            action="store_true",
+                            dest="megabytes",
+                            default=False,
+                            help="display throughput in megabytes per second (MB/s) instead of kilobytes per second (kB/s)")
     parser.add_option_group(displaygroup)
 
     (options, args) = parser.parse_args(sys.argv)
diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man
index 104c7ab4..4f24318d 100644
--- a/tools/nfs-iostat/nfsiostat.man
+++ b/tools/nfs-iostat/nfsiostat.man
@@ -56,16 +56,16 @@ This is the length of the backlog queue.
 .RE
 .RE
 .RS 8
-- \fBkB/s\fR
+- \fBkB/s (MB/s)\fR
 .RS
-This is the number of kB written/read per second.
+This is the number of kB (or MB) written/read per second.
 .RE
 .RE
 .RE
 .RS 8
-- \fBkB/op\fR
+- \fBkB/op (MB/op)\fR
 .RS
-This is the number of kB written/read per each operation.
+This is the number of kB (or MB) written/read per each operation.
 .RE
 .RE
 .RE
@@ -122,6 +122,9 @@ shows help message and exit
 .B \-l LIST or " \-\-list=LIST 
 only print stats for first LIST mount points
 .TP
+.B \-m or " \-\-megabytes
+display throughput in megabytes per second
+.TP
 .B \-p " or " \-\-page
 displays statistics related to the page cache
 .TP
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] nfs-utils: add option to display throughput in MB/s
  2026-05-01 20:56 [PATCH] nfs-utils: add option to display throughput in MB/s Tigran Mkrtchyan
@ 2026-05-06 20:33 ` Steve Dickson
  0 siblings, 0 replies; 2+ messages in thread
From: Steve Dickson @ 2026-05-06 20:33 UTC (permalink / raw)
  To: Tigran Mkrtchyan; +Cc: linux-nfs



On 5/1/26 4:56 PM, Tigran Mkrtchyan wrote:
> Nowadays,the network bandwidth in kB/s is quite a large number to read.
> Thus, let nfsiostat display it in MB/s if requested.
> 
> Signed-off-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Committed... (tag: nfs-utils-2-9-2-rc2)

steved.

> ---
>   tools/nfs-iostat/nfs-iostat.py | 53 ++++++++++++++++++++++------------
>   tools/nfs-iostat/nfsiostat.man | 11 ++++---
>   2 files changed, 42 insertions(+), 22 deletions(-)
> 
> diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
> index 69d24a11..af04aac5 100755
> --- a/tools/nfs-iostat/nfs-iostat.py
> +++ b/tools/nfs-iostat/nfs-iostat.py
> @@ -327,7 +327,7 @@ class DeviceData:
>               print()
>               print('%d congestion waits' % congestionwaits)
>   
> -    def __print_rpc_op_stats(self, op, sample_time):
> +    def __print_rpc_op_stats(self, op, sample_time, use_mb=False):
>           """Print generic stats for one RPC op
>           """
>           if op not in self.__rpc_data:
> @@ -343,9 +343,19 @@ class DeviceData:
>           if len(rpc_stats) >= 9:
>               errs = float(rpc_stats[8])
>   
> +        # scale to MB if requested
> +        if use_mb:
> +            throughput = kilobytes / 1024.0
> +            throughput_label = 'MB/s'
> +            per_op_label = 'MB/op'
> +        else:
> +            throughput = kilobytes
> +            throughput_label = 'kB/s'
> +            per_op_label = 'kB/op'
> +
>           # prevent floating point exceptions
>           if ops != 0:
> -            kb_per_op = kilobytes / ops
> +            unit_per_op = throughput / ops
>               retrans_percent = (retrans * 100) / ops
>               rtt_per_op = rtt / ops
>               exe_per_op = exe / ops
> @@ -353,7 +363,7 @@ class DeviceData:
>               if len(rpc_stats) >= 9:
>                   errs_percent = (errs * 100) / ops
>           else:
> -            kb_per_op = 0.0
> +            unit_per_op = 0.0
>               retrans_percent = 0.0
>               rtt_per_op = 0.0
>               exe_per_op = 0.0
> @@ -364,8 +374,8 @@ class DeviceData:
>           op += ':'
>           print(format(op.lower(), '<16s'), end='')
>           print(format('ops/s', '>8s'), end='')
> -        print(format('kB/s', '>16s'), end='')
> -        print(format('kB/op', '>16s'), end='')
> +        print(format(throughput_label, '>16s'), end='')
> +        print(format(per_op_label, '>16s'), end='')
>           print(format('retrans', '>16s'), end='')
>           print(format('avg RTT (ms)', '>16s'), end='')
>           print(format('avg exe (ms)', '>16s'), end='')
> @@ -375,8 +385,8 @@ class DeviceData:
>           print()
>   
>           print(format((ops / sample_time), '>24.3f'), end='')
> -        print(format((kilobytes / sample_time), '>16.3f'), end='')
> -        print(format(kb_per_op, '>16.3f'), end='')
> +        print(format((throughput / sample_time), '>16.3f'), end='')
> +        print(format(unit_per_op, '>16.3f'), end='')
>           retransmits = '{0:>10.0f} ({1:>3.1f}%)'.format(retrans, retrans_percent).strip()
>           print(format(retransmits, '>16'), end='')
>           print(format(rtt_per_op, '>16.3f'), end='')
> @@ -395,9 +405,11 @@ class DeviceData:
>               sample_time = 1;
>           return (sends / sample_time)
>   
> -    def display_iostats(self, sample_time, which):
> +    def display_iostats(self, sample_time, options):
>           """Display NFS and RPC stats in an iostat-like way
>           """
> +        which = options.which
> +        use_mb = options.megabytes
>           sends = float(self.__rpc_data['rpcsends'])
>           if sample_time == 0:
>               sample_time = float(self.__nfs_data['age'])
> @@ -423,21 +435,21 @@ class DeviceData:
>           print()
>   
>           if which == 0:
> -            self.__print_rpc_op_stats('READ', sample_time)
> -            self.__print_rpc_op_stats('WRITE', sample_time)
> +            self.__print_rpc_op_stats('READ', sample_time, use_mb)
> +            self.__print_rpc_op_stats('WRITE', sample_time, use_mb)
>           elif which == 1:
> -            self.__print_rpc_op_stats('GETATTR', sample_time)
> -            self.__print_rpc_op_stats('ACCESS', sample_time)
> +            self.__print_rpc_op_stats('GETATTR', sample_time, use_mb)
> +            self.__print_rpc_op_stats('ACCESS', sample_time, use_mb)
>               self.__print_attr_cache_stats(sample_time)
>           elif which == 2:
> -            self.__print_rpc_op_stats('LOOKUP', sample_time)
> -            self.__print_rpc_op_stats('READDIR', sample_time)
> +            self.__print_rpc_op_stats('LOOKUP', sample_time, use_mb)
> +            self.__print_rpc_op_stats('READDIR', sample_time, use_mb)
>               if 'READDIRPLUS' in self.__rpc_data:
> -                self.__print_rpc_op_stats('READDIRPLUS', sample_time)
> +                self.__print_rpc_op_stats('READDIRPLUS', sample_time, use_mb)
>               self.__print_dir_cache_stats(sample_time)
>           elif which == 3:
> -            self.__print_rpc_op_stats('READ', sample_time)
> -            self.__print_rpc_op_stats('WRITE', sample_time)
> +            self.__print_rpc_op_stats('READ', sample_time, use_mb)
> +            self.__print_rpc_op_stats('WRITE', sample_time, use_mb)
>               self.__print_page_stats(sample_time)
>   
>           sys.stdout.flush()
> @@ -500,7 +512,7 @@ def print_iostat_summary(old, new, devices, time, options):
>   
>       count = 1
>       for device in devices:
> -        display_stats[device].display_iostats(time, options.which)
> +        display_stats[device].display_iostats(time, options)
>   
>           count += 1
>           if (count > options.list):
> @@ -585,6 +597,11 @@ client are listed.
>                               type="int",
>                               dest="list",
>                               help="only print stats for first LIST mount points")
> +    displaygroup.add_option('-m', '--megabytes',
> +                            action="store_true",
> +                            dest="megabytes",
> +                            default=False,
> +                            help="display throughput in megabytes per second (MB/s) instead of kilobytes per second (kB/s)")
>       parser.add_option_group(displaygroup)
>   
>       (options, args) = parser.parse_args(sys.argv)
> diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man
> index 104c7ab4..4f24318d 100644
> --- a/tools/nfs-iostat/nfsiostat.man
> +++ b/tools/nfs-iostat/nfsiostat.man
> @@ -56,16 +56,16 @@ This is the length of the backlog queue.
>   .RE
>   .RE
>   .RS 8
> -- \fBkB/s\fR
> +- \fBkB/s (MB/s)\fR
>   .RS
> -This is the number of kB written/read per second.
> +This is the number of kB (or MB) written/read per second.
>   .RE
>   .RE
>   .RE
>   .RS 8
> -- \fBkB/op\fR
> +- \fBkB/op (MB/op)\fR
>   .RS
> -This is the number of kB written/read per each operation.
> +This is the number of kB (or MB) written/read per each operation.
>   .RE
>   .RE
>   .RE
> @@ -122,6 +122,9 @@ shows help message and exit
>   .B \-l LIST or " \-\-list=LIST
>   only print stats for first LIST mount points
>   .TP
> +.B \-m or " \-\-megabytes
> +display throughput in megabytes per second
> +.TP
>   .B \-p " or " \-\-page
>   displays statistics related to the page cache
>   .TP


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-05-06 20:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-01 20:56 [PATCH] nfs-utils: add option to display throughput in MB/s Tigran Mkrtchyan
2026-05-06 20:33 ` Steve Dickson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox