aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorChuck Lever <cel@netapp.com>2006-03-20 13:44:22 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 13:44:22 -0500
commit11c556b3d8d481829ab5f9933a25d29b00913b5a (patch)
treed1127fa5d22aeb035ca9977abbc73a29d5436fbe /net/sunrpc
parentef759a2e54ed434b2f72b52a14edecd6d4eadf74 (diff)
SUNRPC: provide a mechanism for collecting stats in the RPC client
Add a simple mechanism for collecting stats in the RPC client. Stats are tabulated during xprt_release. Note that per_cpu shenanigans are not required here because the RPC client already serializes on the transport write lock. Test plan: Compile kernel with CONFIG_NFS enabled. Basic performance regression testing with high-speed networking and high performance server. Signed-off-by: Chuck Lever <cel@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/clnt.c9
-rw-r--r--net/sunrpc/stats.c105
-rw-r--r--net/sunrpc/xprt.c2
3 files changed, 113 insertions, 3 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 84eb5b4565fc..0bb23e8e9d0c 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -28,12 +28,11 @@
28#include <linux/mm.h> 28#include <linux/mm.h>
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/utsname.h> 30#include <linux/utsname.h>
31#include <linux/workqueue.h>
31 32
32#include <linux/sunrpc/clnt.h> 33#include <linux/sunrpc/clnt.h>
33#include <linux/workqueue.h>
34#include <linux/sunrpc/rpc_pipe_fs.h> 34#include <linux/sunrpc/rpc_pipe_fs.h>
35 35#include <linux/sunrpc/metrics.h>
36#include <linux/nfs.h>
37 36
38 37
39#define RPC_SLACK_SPACE (1024) /* total overkill */ 38#define RPC_SLACK_SPACE (1024) /* total overkill */
@@ -147,6 +146,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
147 clnt->cl_vers = version->number; 146 clnt->cl_vers = version->number;
148 clnt->cl_prot = xprt->prot; 147 clnt->cl_prot = xprt->prot;
149 clnt->cl_stats = program->stats; 148 clnt->cl_stats = program->stats;
149 clnt->cl_metrics = rpc_alloc_iostats(clnt);
150 rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait"); 150 rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
151 151
152 if (!clnt->cl_port) 152 if (!clnt->cl_port)
@@ -245,6 +245,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
245 if (new->cl_auth) 245 if (new->cl_auth)
246 atomic_inc(&new->cl_auth->au_count); 246 atomic_inc(&new->cl_auth->au_count);
247 new->cl_pmap = &new->cl_pmap_default; 247 new->cl_pmap = &new->cl_pmap_default;
248 new->cl_metrics = rpc_alloc_iostats(clnt);
248 rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait"); 249 rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
249 return new; 250 return new;
250out_no_clnt: 251out_no_clnt:
@@ -315,6 +316,8 @@ rpc_destroy_client(struct rpc_clnt *clnt)
315 if (clnt->cl_server != clnt->cl_inline_name) 316 if (clnt->cl_server != clnt->cl_inline_name)
316 kfree(clnt->cl_server); 317 kfree(clnt->cl_server);
317out_free: 318out_free:
319 rpc_free_iostats(clnt->cl_metrics);
320 clnt->cl_metrics = NULL;
318 if (clnt->cl_dentry) 321 if (clnt->cl_dentry)
319 dput(clnt->cl_dentry); 322 dput(clnt->cl_dentry);
320 kfree(clnt); 323 kfree(clnt);
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 4979f226e285..24ac7163b9c7 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -21,6 +21,7 @@
21#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22#include <linux/sunrpc/clnt.h> 22#include <linux/sunrpc/clnt.h>
23#include <linux/sunrpc/svcsock.h> 23#include <linux/sunrpc/svcsock.h>
24#include <linux/sunrpc/metrics.h>
24 25
25#define RPCDBG_FACILITY RPCDBG_MISC 26#define RPCDBG_FACILITY RPCDBG_MISC
26 27
@@ -106,6 +107,110 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
106 } 107 }
107} 108}
108 109
110/**
111 * rpc_alloc_iostats - allocate an rpc_iostats structure
112 * @clnt: RPC program, version, and xprt
113 *
114 */
115struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
116{
117 unsigned int ops = clnt->cl_maxproc;
118 size_t size = ops * sizeof(struct rpc_iostats);
119 struct rpc_iostats *new;
120
121 new = kmalloc(size, GFP_KERNEL);
122 if (new)
123 memset(new, 0 , size);
124 return new;
125}
126EXPORT_SYMBOL(rpc_alloc_iostats);
127
128/**
129 * rpc_free_iostats - release an rpc_iostats structure
130 * @stats: doomed rpc_iostats structure
131 *
132 */
133void rpc_free_iostats(struct rpc_iostats *stats)
134{
135 kfree(stats);
136}
137EXPORT_SYMBOL(rpc_free_iostats);
138
139/**
140 * rpc_count_iostats - tally up per-task stats
141 * @task: completed rpc_task
142 *
143 * Relies on the caller for serialization.
144 */
145void rpc_count_iostats(struct rpc_task *task)
146{
147 struct rpc_rqst *req = task->tk_rqstp;
148 struct rpc_iostats *stats = task->tk_client->cl_metrics;
149 struct rpc_iostats *op_metrics;
150 long rtt, execute, queue;
151
152 if (!stats || !req)
153 return;
154 op_metrics = &stats[task->tk_msg.rpc_proc->p_proc];
155
156 op_metrics->om_ops++;
157 op_metrics->om_ntrans += req->rq_ntrans;
158 op_metrics->om_timeouts += task->tk_timeouts;
159
160 op_metrics->om_bytes_sent += task->tk_bytes_sent;
161 op_metrics->om_bytes_recv += req->rq_received;
162
163 queue = (long)req->rq_xtime - task->tk_start;
164 if (queue < 0)
165 queue = -queue;
166 op_metrics->om_queue += queue;
167
168 rtt = task->tk_rtt;
169 if (rtt < 0)
170 rtt = -rtt;
171 op_metrics->om_rtt += rtt;
172
173 execute = (long)jiffies - task->tk_start;
174 if (execute < 0)
175 execute = -execute;
176 op_metrics->om_execute += execute;
177}
178
179#define MILLISECS_PER_JIFFY (1000UL / HZ)
180
181void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
182{
183 struct rpc_iostats *stats = clnt->cl_metrics;
184 struct rpc_xprt *xprt = clnt->cl_xprt;
185 unsigned int op, maxproc = clnt->cl_maxproc;
186
187 if (!stats)
188 return;
189
190 seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS);
191 seq_printf(seq, "p/v: %u/%u (%s)\n",
192 clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
193
194 if (xprt)
195 xprt->ops->print_stats(xprt, seq);
196
197 seq_printf(seq, "\tper-op statistics\n");
198 for (op = 0; op < maxproc; op++) {
199 struct rpc_iostats *metrics = &stats[op];
200 seq_printf(seq, "%12u: ", op);
201 seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n",
202 metrics->om_ops,
203 metrics->om_ntrans,
204 metrics->om_timeouts,
205 metrics->om_bytes_sent,
206 metrics->om_bytes_recv,
207 metrics->om_queue * MILLISECS_PER_JIFFY,
208 metrics->om_rtt * MILLISECS_PER_JIFFY,
209 metrics->om_execute * MILLISECS_PER_JIFFY);
210 }
211}
212EXPORT_SYMBOL(rpc_print_iostats);
213
109/* 214/*
110 * Register/unregister RPC proc files 215 * Register/unregister RPC proc files
111 */ 216 */
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index c6241976a6ee..eb5a262e024e 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -44,6 +44,7 @@
44#include <linux/random.h> 44#include <linux/random.h>
45 45
46#include <linux/sunrpc/clnt.h> 46#include <linux/sunrpc/clnt.h>
47#include <linux/sunrpc/metrics.h>
47 48
48/* 49/*
49 * Local variables 50 * Local variables
@@ -859,6 +860,7 @@ void xprt_release(struct rpc_task *task)
859 860
860 if (!(req = task->tk_rqstp)) 861 if (!(req = task->tk_rqstp))
861 return; 862 return;
863 rpc_count_iostats(task);
862 spin_lock_bh(&xprt->transport_lock); 864 spin_lock_bh(&xprt->transport_lock);
863 xprt->ops->release_xprt(xprt, task); 865 xprt->ops->release_xprt(xprt, task);
864 if (xprt->ops->release_request) 866 if (xprt->ops->release_request)