diff options
author | Chuck Lever <cel@netapp.com> | 2006-03-20 13:44:22 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-20 13:44:22 -0500 |
commit | 11c556b3d8d481829ab5f9933a25d29b00913b5a (patch) | |
tree | d1127fa5d22aeb035ca9977abbc73a29d5436fbe /net/sunrpc | |
parent | ef759a2e54ed434b2f72b52a14edecd6d4eadf74 (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.c | 9 | ||||
-rw-r--r-- | net/sunrpc/stats.c | 105 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 2 |
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; |
250 | out_no_clnt: | 251 | out_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); |
317 | out_free: | 318 | out_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 | */ | ||
115 | struct 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 | } | ||
126 | EXPORT_SYMBOL(rpc_alloc_iostats); | ||
127 | |||
128 | /** | ||
129 | * rpc_free_iostats - release an rpc_iostats structure | ||
130 | * @stats: doomed rpc_iostats structure | ||
131 | * | ||
132 | */ | ||
133 | void rpc_free_iostats(struct rpc_iostats *stats) | ||
134 | { | ||
135 | kfree(stats); | ||
136 | } | ||
137 | EXPORT_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 | */ | ||
145 | void 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 | |||
181 | void 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 | } | ||
212 | EXPORT_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) |