SUNRPC: add a handful of per-xprt counters
authorChuck Lever <cel@netapp.com>
Mon, 20 Mar 2006 18:44:16 +0000 (13:44 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 20 Mar 2006 18:44:16 +0000 (13:44 -0500)
Monitor generic transport events.  Add a transport switch callout to
format transport counters for export to user-land.

Test plan:
Compile kernel with CONFIG_NFS enabled.

Signed-off-by: Chuck Lever <cel@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
include/linux/sunrpc/xprt.h
net/sunrpc/pmap_clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index 6ef99b1..7eebbab 100644 (file)
@@ -114,6 +114,7 @@ struct rpc_xprt_ops {
        void            (*release_request)(struct rpc_task *task);
        void            (*close)(struct rpc_xprt *xprt);
        void            (*destroy)(struct rpc_xprt *xprt);
+       void            (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq);
 };
 
 struct rpc_xprt {
@@ -187,6 +188,18 @@ struct rpc_xprt {
 
        struct list_head        recv;
 
+       struct {
+               unsigned long           bind_count,     /* total number of binds */
+                                       connect_count,  /* total number of connects */
+                                       connect_start,  /* connect start timestamp */
+                                       connect_time,   /* jiffies waiting for connect */
+                                       sends,          /* how many complete requests */
+                                       recvs,          /* how many complete requests */
+                                       bad_xids;       /* lookup_rqst didn't find XID */
+
+               unsigned long long      req_u,          /* average requests on the wire */
+                                       bklog_u;        /* backlog queue utilization */
+       } stat;
 
        void                    (*old_data_ready)(struct sock *, int);
        void                    (*old_state_change)(struct sock *);
index 8139ce6..332cc5d 100644 (file)
@@ -82,6 +82,7 @@ rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
        rpc_call_setup(child, &msg, 0);
 
        /* ... and run the child task */
+       task->tk_xprt->stat.bind_count++;
        rpc_run_child(task, child, pmap_getport_done);
        return;
 
index 8ff2c8a..93a0a3c 100644 (file)
@@ -548,6 +548,7 @@ void xprt_connect(struct rpc_task *task)
 
                task->tk_timeout = xprt->connect_timeout;
                rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
+               xprt->stat.connect_start = jiffies;
                xprt->ops->connect(task);
        }
        return;
@@ -558,6 +559,8 @@ static void xprt_connect_status(struct rpc_task *task)
        struct rpc_xprt *xprt = task->tk_xprt;
 
        if (task->tk_status >= 0) {
+               xprt->stat.connect_count++;
+               xprt->stat.connect_time += (long)jiffies - xprt->stat.connect_start;
                dprintk("RPC: %4d xprt_connect_status: connection established\n",
                                task->tk_pid);
                return;
@@ -601,16 +604,14 @@ static void xprt_connect_status(struct rpc_task *task)
 struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
        struct list_head *pos;
-       struct rpc_rqst *req = NULL;
 
        list_for_each(pos, &xprt->recv) {
                struct rpc_rqst *entry = list_entry(pos, struct rpc_rqst, rq_list);
-               if (entry->rq_xid == xid) {
-                       req = entry;
-                       break;
-               }
+               if (entry->rq_xid == xid)
+                       return entry;
        }
-       return req;
+       xprt->stat.bad_xids++;
+       return NULL;
 }
 
 /**
@@ -646,6 +647,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
        dprintk("RPC: %5u xid %08x complete (%d bytes received)\n",
                        task->tk_pid, ntohl(req->rq_xid), copied);
 
+       task->tk_xprt->stat.recvs++;
        list_del_init(&req->rq_list);
        req->rq_received = req->rq_private_buf.len = copied;
        rpc_wake_up_task(task);
@@ -744,12 +746,19 @@ void xprt_transmit(struct rpc_task *task)
        if (status == 0) {
                dprintk("RPC: %4d xmit complete\n", task->tk_pid);
                spin_lock_bh(&xprt->transport_lock);
+
                xprt->ops->set_retrans_timeout(task);
+
+               xprt->stat.sends++;
+               xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;
+               xprt->stat.bklog_u += xprt->backlog.qlen;
+
                /* Don't race with disconnect */
                if (!xprt_connected(xprt))
                        task->tk_status = -ENOTCONN;
                else if (!req->rq_received)
                        rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
+
                xprt->ops->release_xprt(xprt, task);
                spin_unlock_bh(&xprt->transport_lock);
                return;
index c458f8d..6766b7f 100644 (file)
@@ -1114,6 +1114,8 @@ static void xs_tcp_connect_worker(void *args)
        }
 
        /* Tell the socket layer to start connecting... */
+       xprt->stat.connect_count++;
+       xprt->stat.connect_start = jiffies;
        status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
                        sizeof(xprt->addr), O_NONBLOCK);
        dprintk("RPC: %p  connect status %d connected %d sock state %d\n",
@@ -1177,6 +1179,50 @@ static void xs_connect(struct rpc_task *task)
        }
 }
 
+/**
+ * xs_udp_print_stats - display UDP socket-specifc stats
+ * @xprt: rpc_xprt struct containing statistics
+ * @seq: output file
+ *
+ */
+static void xs_udp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
+{
+       seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n",
+                       xprt->port,
+                       xprt->stat.bind_count,
+                       xprt->stat.sends,
+                       xprt->stat.recvs,
+                       xprt->stat.bad_xids,
+                       xprt->stat.req_u,
+                       xprt->stat.bklog_u);
+}
+
+/**
+ * xs_tcp_print_stats - display TCP socket-specifc stats
+ * @xprt: rpc_xprt struct containing statistics
+ * @seq: output file
+ *
+ */
+static void xs_tcp_print_stats(struct rpc_xprt *xprt, struct seq_file *seq)
+{
+       long idle_time = 0;
+
+       if (xprt_connected(xprt))
+               idle_time = (long)(jiffies - xprt->last_used) / HZ;
+
+       seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n",
+                       xprt->port,
+                       xprt->stat.bind_count,
+                       xprt->stat.connect_count,
+                       xprt->stat.connect_time,
+                       idle_time,
+                       xprt->stat.sends,
+                       xprt->stat.recvs,
+                       xprt->stat.bad_xids,
+                       xprt->stat.req_u,
+                       xprt->stat.bklog_u);
+}
+
 static struct rpc_xprt_ops xs_udp_ops = {
        .set_buffer_size        = xs_udp_set_buffer_size,
        .reserve_xprt           = xprt_reserve_xprt_cong,
@@ -1191,6 +1237,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
        .release_request        = xprt_release_rqst_cong,
        .close                  = xs_close,
        .destroy                = xs_destroy,
+       .print_stats            = xs_udp_print_stats,
 };
 
 static struct rpc_xprt_ops xs_tcp_ops = {
@@ -1204,6 +1251,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
        .set_retrans_timeout    = xprt_set_retrans_timeout_def,
        .close                  = xs_close,
        .destroy                = xs_destroy,
+       .print_stats            = xs_tcp_print_stats,
 };
 
 /**