Blame SOURCES/nfs-utils-1.3.0-mountstats-rdma.patch

5fd2c0
diff -up nfs-utils-1.3.0/tools/mountstats/mountstats.man.orig nfs-utils-1.3.0/tools/mountstats/mountstats.man
5fd2c0
--- nfs-utils-1.3.0/tools/mountstats/mountstats.man.orig	2018-06-11 10:10:22.450171982 -0400
5fd2c0
+++ nfs-utils-1.3.0/tools/mountstats/mountstats.man	2018-06-11 10:11:00.756778817 -0400
5fd2c0
@@ -19,6 +19,8 @@ mountstats \- Displays various NFS clien
5fd2c0
 .RB [ \-r | \-\-rpc ]
5fd2c0
 |
5fd2c0
 .RB  [ \-R | \-\-raw ]
5fd2c0
+|
5fd2c0
+.RB  [ \-x | \-\-xprt ]
5fd2c0
 ]
5fd2c0
 .RI [ mountpoint ] ...
5fd2c0
 .P
5fd2c0
@@ -110,6 +112,9 @@ Display only the raw statistics.  This i
5fd2c0
 and
5fd2c0
 .BR \-S | \-\-since
5fd2c0
 options.
5fd2c0
+.TP
5fd2c0
+.B \-x, \-\-xprt
5fd2c0
+Display only the transport statistics
5fd2c0
 .SS Options specific to the iostat sub-command
5fd2c0
 .IP "\fIinterval\fP"
5fd2c0
 Specifies the amount of time in seconds between each report.  The first report contains statistics for the time since each file system was mounted.  Each subsequent report contains statistics collected during the interval since the previous report.  This may not be used with the
5fd2c0
diff -up nfs-utils-1.3.0/tools/mountstats/mountstats.py.orig nfs-utils-1.3.0/tools/mountstats/mountstats.py
5fd2c0
--- nfs-utils-1.3.0/tools/mountstats/mountstats.py.orig	2018-06-11 10:10:22.501172790 -0400
5fd2c0
+++ nfs-utils-1.3.0/tools/mountstats/mountstats.py	2018-06-11 10:11:00.757778833 -0400
5fd2c0
@@ -87,7 +87,10 @@ XprtUdpCounters = [
5fd2c0
     'rpcreceives',
5fd2c0
     'badxids',
5fd2c0
     'inflightsends',
5fd2c0
-    'backlogutil'
5fd2c0
+    'backlogutil',
5fd2c0
+    'maxslots',
5fd2c0
+    'sendutil',
5fd2c0
+    'pendutil'
5fd2c0
 ]
5fd2c0
 
5fd2c0
 XprtTcpCounters = [
5fd2c0
@@ -100,7 +103,10 @@ XprtTcpCounters = [
5fd2c0
     'rpcreceives',
5fd2c0
     'badxids',
5fd2c0
     'inflightsends',
5fd2c0
-    'backlogutil'
5fd2c0
+    'backlogutil',
5fd2c0
+    'maxslots',
5fd2c0
+    'sendutil',
5fd2c0
+    'pendutil'
5fd2c0
 ]
5fd2c0
 
5fd2c0
 XprtRdmaCounters = [
5fd2c0
@@ -112,17 +118,25 @@ XprtRdmaCounters = [
5fd2c0
     'rpcsends',
5fd2c0
     'rpcreceives',
5fd2c0
     'badxids',
5fd2c0
+    'inflightsends',
5fd2c0
     'backlogutil',
5fd2c0
-    'read_chunks',
5fd2c0
-    'write_chunks',
5fd2c0
-    'reply_chunks',
5fd2c0
+    'read_segments',
5fd2c0
+    'write_segments',
5fd2c0
+    'reply_segments',
5fd2c0
     'total_rdma_req',
5fd2c0
     'total_rdma_rep',
5fd2c0
     'pullup',
5fd2c0
     'fixup',
5fd2c0
     'hardway',
5fd2c0
     'failed_marshal',
5fd2c0
-    'bad_reply'
5fd2c0
+    'bad_reply',
5fd2c0
+    'nomsg_calls',
5fd2c0
+    'recovered_mrs',
5fd2c0
+    'orphaned_mrs',
5fd2c0
+    'allocated_mrs',
5fd2c0
+    'local_invalidates',
5fd2c0
+    'empty_sendctx_q',
5fd2c0
+    'reply_waits_for_send',
5fd2c0
 ]
5fd2c0
 
5fd2c0
 Nfsv3ops = [
5fd2c0
@@ -266,17 +280,20 @@ class DeviceData:
5fd2c0
             if words[1] == 'udp':
5fd2c0
                 i = 2
5fd2c0
                 for key in XprtUdpCounters:
5fd2c0
-                    self.__rpc_data[key] = int(words[i])
5fd2c0
+                    if i < len(words):
5fd2c0
+                        self.__rpc_data[key] = int(words[i])
5fd2c0
                     i += 1
5fd2c0
             elif words[1] == 'tcp':
5fd2c0
                 i = 2
5fd2c0
                 for key in XprtTcpCounters:
5fd2c0
-                    self.__rpc_data[key] = int(words[i])
5fd2c0
+                    if i < len(words):
5fd2c0
+                        self.__rpc_data[key] = int(words[i])
5fd2c0
                     i += 1
5fd2c0
             elif words[1] == 'rdma':
5fd2c0
                 i = 2
5fd2c0
                 for key in XprtRdmaCounters:
5fd2c0
-                    self.__rpc_data[key] = int(words[i])
5fd2c0
+                    if i < len(words):
5fd2c0
+                        self.__rpc_data[key] = int(words[i])
5fd2c0
                     i += 1
5fd2c0
         elif words[0] == 'per-op':
5fd2c0
             self.__rpc_data['per-op'] = words
5fd2c0
@@ -354,12 +371,11 @@ class DeviceData:
5fd2c0
     def display_stats_header(self):
5fd2c0
         print('Stats for %s mounted on %s:' % \
5fd2c0
             (self.__nfs_data['export'], self.__nfs_data['mountpoint']))
5fd2c0
+        print()
5fd2c0
 
5fd2c0
     def display_nfs_options(self):
5fd2c0
         """Pretty-print the NFS options
5fd2c0
         """
5fd2c0
-        self.display_stats_header()
5fd2c0
-
5fd2c0
         print('  NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions']))
5fd2c0
         print('  NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities']))
5fd2c0
         if 'nfsv4flags' in self.__nfs_data:
5fd2c0
@@ -425,7 +441,6 @@ class DeviceData:
5fd2c0
         """
5fd2c0
         sends = self.__rpc_data['rpcsends']
5fd2c0
 
5fd2c0
-        print()
5fd2c0
         print('RPC statistics:')
5fd2c0
 
5fd2c0
         print('  %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \
5fd2c0
@@ -643,6 +658,83 @@ class DeviceData:
5fd2c0
         self.__print_rpc_op_stats('WRITE', sample_time)
5fd2c0
         sys.stdout.flush()
5fd2c0
 
5fd2c0
+    def display_xprt_stats(self):
5fd2c0
+        """Pretty-print the xprt statistics
5fd2c0
+        """
5fd2c0
+        if self.__rpc_data['protocol'] == 'udp':
5fd2c0
+            print('\tTransport protocol: udp')
5fd2c0
+            print('\tSource port: %d' % self.__rpc_data['port'])
5fd2c0
+            print('\tBind count: %d' % self.__rpc_data['bind_count'])
5fd2c0
+            print('\tRPC requests: %d' % self.__rpc_data['rpcsends'])
5fd2c0
+            print('\tRPC replies: %d' % self.__rpc_data['rpcreceives'])
5fd2c0
+            print('\tXIDs not found: %d' % self.__rpc_data['badxids'])
5fd2c0
+            print('\tMax slots: %d' % self.__rpc_data['maxslots'])
5fd2c0
+            if self.__rpc_data['rpcsends'] != 0:
5fd2c0
+                print('\tAvg backlog length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['backlogutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+                print('\tAvg send queue length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['sendutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+                print('\tAvg pending queue length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['pendutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+        elif self.__rpc_data['protocol'] == 'tcp':
5fd2c0
+            print('\tTransport protocol: tcp')
5fd2c0
+            print('\tSource port: %d' % self.__rpc_data['port'])
5fd2c0
+            print('\tBind count: %d' % self.__rpc_data['bind_count'])
5fd2c0
+            print('\tConnect count: %d' % self.__rpc_data['connect_count'])
5fd2c0
+            print('\tConnect time: %d seconds' % self.__rpc_data['connect_time'])
5fd2c0
+            print('\tIdle time: %d seconds' % self.__rpc_data['idle_time'])
5fd2c0
+            print('\tRPC requests: %d' % self.__rpc_data['rpcsends'])
5fd2c0
+            print('\tRPC replies: %d' % self.__rpc_data['rpcreceives'])
5fd2c0
+            print('\tXIDs not found: %d' % self.__rpc_data['badxids'])
5fd2c0
+            print('\tMax slots: %d' % self.__rpc_data['maxslots'])
5fd2c0
+            if self.__rpc_data['rpcsends'] != 0:
5fd2c0
+                print('\tAvg backlog length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['backlogutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+                print('\tAvg send queue length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['sendutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+                print('\tAvg pending queue length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['pendutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+        elif self.__rpc_data['protocol'] == 'rdma':
5fd2c0
+            print('\tTransport protocol: rdma')
5fd2c0
+            print('\tConnect count: %d' % self.__rpc_data['connect_count'])
5fd2c0
+            print('\tConnect time: %d seconds' % self.__rpc_data['connect_time'])
5fd2c0
+            print('\tIdle time: %d seconds' % self.__rpc_data['idle_time'])
5fd2c0
+            sends = self.__rpc_data['rpcsends']
5fd2c0
+            print('\tRPC requests: %d' % self.__rpc_data['rpcsends'])
5fd2c0
+            print('\tRPC replies: %d' % self.__rpc_data['rpcreceives'])
5fd2c0
+            print('\tXIDs not found: %d' % self.__rpc_data['badxids'])
5fd2c0
+            if self.__rpc_data['rpcsends'] != 0:
5fd2c0
+                print('\tAvg backlog length: %d' % \
5fd2c0
+                    (float(self.__rpc_data['backlogutil']) / self.__rpc_data['rpcsends']))
5fd2c0
+            print('\tRead segments: %d' % self.__rpc_data['read_segments'])
5fd2c0
+            print('\tWrite segments: %d' % self.__rpc_data['write_segments'])
5fd2c0
+            print('\tReply segments: %d' % self.__rpc_data['reply_segments'])
5fd2c0
+            print('\tRegistered: %d bytes' % self.__rpc_data['total_rdma_req'])
5fd2c0
+            print('\tRDMA received: %d bytes' % self.__rpc_data['total_rdma_rep'])
5fd2c0
+            print('\tTotal pull-up: %d bytes' % self.__rpc_data['pullup'])
5fd2c0
+            print('\tTotal fix-up: %d bytes' % self.__rpc_data['fixup'])
5fd2c0
+            print('\tHardway allocations: %d bytes' % self.__rpc_data['hardway'])
5fd2c0
+            print('\tFailed marshals: %d' % self.__rpc_data['failed_marshal'])
5fd2c0
+            print('\tBad replies: %d' % self.__rpc_data['bad_reply'])
5fd2c0
+
5fd2c0
+            """ Counters not present in all kernels """
5fd2c0
+            if 'nomsg_calls' in self.__rpc_data:
5fd2c0
+                print('\tRDMA_NOMSG calls: %d' % self.__rpc_data['nomsg_calls'])
5fd2c0
+            if 'allocated_mrs' in self.__rpc_data:
5fd2c0
+                print('\tAllocated MRs: %d' % self.__rpc_data['allocated_mrs'])
5fd2c0
+            if 'recovered_mrs' in self.__rpc_data:
5fd2c0
+                print('\tRecovered MRs: %d' % self.__rpc_data['recovered_mrs'])
5fd2c0
+            if 'orphaned_mrs' in self.__rpc_data:
5fd2c0
+                print('\tOrphaned MRs: %d' % self.__rpc_data['orphaned_mrs'])
5fd2c0
+            if 'local_invalidates' in self.__rpc_data:
5fd2c0
+                print('\tLocal Invalidates needed: %d' % self.__rpc_data['local_invalidates'])
5fd2c0
+            if 'empty_sendctx_q' in self.__rpc_data:
5fd2c0
+                print('\tEmpty sendctx queue count: %d' % self.__rpc_data['empty_sendctx_q'])
5fd2c0
+            if 'reply_waits_for_send' in self.__rpc_data:
5fd2c0
+                print('\tReplies that waited for Send completion: %d' % self.__rpc_data['reply_waits_for_send'])
5fd2c0
+        else:
5fd2c0
+            raise Exception('Unknown RPC transport protocol %s' % self.__rpc_data['protocol'])
5fd2c0
+
5fd2c0
 def parse_stats_file(f):
5fd2c0
     """pop the contents of a mountstats file into a dictionary,
5fd2c0
     keyed by mount point.  each value object is a list of the
5fd2c0
@@ -669,8 +761,9 @@ def parse_stats_file(f):
5fd2c0
 
5fd2c0
     return ms_dict
5fd2c0
 
5fd2c0
-def print_mountstats(stats, nfs_only, rpc_only, raw):
5fd2c0
+def print_mountstats(stats, nfs_only, rpc_only, raw, xprt_only):
5fd2c0
     if nfs_only:
5fd2c0
+       stats.display_stats_header()
5fd2c0
        stats.display_nfs_options()
5fd2c0
        stats.display_nfs_events()
5fd2c0
        stats.display_nfs_bytes()
5fd2c0
@@ -680,7 +773,11 @@ def print_mountstats(stats, nfs_only, rp
5fd2c0
        stats.display_rpc_op_stats()
5fd2c0
     elif raw:
5fd2c0
        stats.display_raw_stats()
5fd2c0
+    elif xprt_only:
5fd2c0
+       stats.display_stats_header()
5fd2c0
+       stats.display_xprt_stats()
5fd2c0
     else:
5fd2c0
+       stats.display_stats_header()
5fd2c0
        stats.display_nfs_options()
5fd2c0
        stats.display_nfs_bytes()
5fd2c0
        stats.display_rpc_generic_stats()
5fd2c0
@@ -722,14 +819,14 @@ def mountstats_command(args):
5fd2c0
         stats = DeviceData()
5fd2c0
         stats.parse_stats(mountstats[mp])
5fd2c0
         if not args.since:
5fd2c0
-            print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw)
5fd2c0
+            print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw, args.xprt_only)
5fd2c0
         elif args.since and mp not in old_mountstats:
5fd2c0
-            print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw)
5fd2c0
+            print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw, args.xprt_only)
5fd2c0
         else:
5fd2c0
             old_stats = DeviceData()
5fd2c0
             old_stats.parse_stats(old_mountstats[mp])
5fd2c0
             diff_stats = stats.compare_iostats(old_stats)
5fd2c0
-            print_mountstats(diff_stats, args.nfs_only, args.rpc_only, args.raw)
5fd2c0
+            print_mountstats(diff_stats, args.nfs_only, args.rpc_only, args.raw, args.xprt_only)
5fd2c0
 
5fd2c0
     args.infile.close()
5fd2c0
     if args.since:
5fd2c0
@@ -941,6 +1038,8 @@ def main():
5fd2c0
         help='Display only the RPC statistics')
5fd2c0
     group.add_argument('-R', '--raw', action='store_true',
5fd2c0
         help='Display only the raw statistics')
5fd2c0
+    group.add_argument('-x', '--xprt', action='store_true', dest='xprt_only',
5fd2c0
+        help='Display only the xprt statistics')
5fd2c0
     # The mountpoints argument cannot be moved into the common_parser because
5fd2c0
     # it will screw up the parsing of the iostat arguments (interval and count)
5fd2c0
     mountstats_parser.add_argument('mountpoints', nargs='*', metavar='mountpoint',