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/stats.c | |
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/stats.c')
-rw-r--r-- | net/sunrpc/stats.c | 105 |
1 files changed, 105 insertions, 0 deletions
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 | */ |