aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/sunrpc/clnt.h3
-rw-r--r--include/linux/sunrpc/metrics.h77
-rw-r--r--net/sunrpc/clnt.c9
-rw-r--r--net/sunrpc/stats.c105
-rw-r--r--net/sunrpc/xprt.c2
5 files changed, 192 insertions, 4 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index f147e6b84332..0f3662002ffc 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -45,7 +45,8 @@ struct rpc_clnt {
45 char * cl_server; /* server machine name */ 45 char * cl_server; /* server machine name */
46 char * cl_protname; /* protocol name */ 46 char * cl_protname; /* protocol name */
47 struct rpc_auth * cl_auth; /* authenticator */ 47 struct rpc_auth * cl_auth; /* authenticator */
48 struct rpc_stat * cl_stats; /* statistics */ 48 struct rpc_stat * cl_stats; /* per-program statistics */
49 struct rpc_iostats * cl_metrics; /* per-client statistics */
49 50
50 unsigned int cl_softrtry : 1,/* soft timeouts */ 51 unsigned int cl_softrtry : 1,/* soft timeouts */
51 cl_intr : 1,/* interruptible */ 52 cl_intr : 1,/* interruptible */
diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h
new file mode 100644
index 000000000000..8f96e9dc369a
--- /dev/null
+++ b/include/linux/sunrpc/metrics.h
@@ -0,0 +1,77 @@
1/*
2 * linux/include/linux/sunrpc/metrics.h
3 *
4 * Declarations for RPC client per-operation metrics
5 *
6 * Copyright (C) 2005 Chuck Lever <cel@netapp.com>
7 *
8 * RPC client per-operation statistics provide latency and retry
9 * information about each type of RPC procedure in a given RPC program.
10 * These statistics are not for detailed problem diagnosis, but simply
11 * to indicate whether the problem is local or remote.
12 *
13 * These counters are not meant to be human-readable, but are meant to be
14 * integrated into system monitoring tools such as "sar" and "iostat". As
15 * such, the counters are sampled by the tools over time, and are never
16 * zeroed after a file system is mounted. Moving averages can be computed
17 * by the tools by taking the difference between two instantaneous samples
18 * and dividing that by the time between the samples.
19 *
20 * The counters are maintained in a single array per RPC client, indexed
21 * by procedure number. There is no need to maintain separate counter
22 * arrays per-CPU because these counters are always modified behind locks.
23 */
24
25#ifndef _LINUX_SUNRPC_METRICS_H
26#define _LINUX_SUNRPC_METRICS_H
27
28#include <linux/seq_file.h>
29
30#define RPC_IOSTATS_VERS "1.0"
31
32struct rpc_iostats {
33 /*
34 * These counters give an idea about how many request
35 * transmissions are required, on average, to complete that
36 * particular procedure. Some procedures may require more
37 * than one transmission because the server is unresponsive,
38 * the client is retransmitting too aggressively, or the
39 * requests are large and the network is congested.
40 */
41 unsigned long om_ops, /* count of operations */
42 om_ntrans, /* count of RPC transmissions */
43 om_timeouts; /* count of major timeouts */
44
45 /*
46 * These count how many bytes are sent and received for a
47 * given RPC procedure type. This indicates how much load a
48 * particular procedure is putting on the network. These
49 * counts include the RPC and ULP headers, and the request
50 * payload.
51 */
52 unsigned long long om_bytes_sent, /* count of bytes out */
53 om_bytes_recv; /* count of bytes in */
54
55 /*
56 * The length of time an RPC request waits in queue before
57 * transmission, the network + server latency of the request,
58 * and the total time the request spent from init to release
59 * are measured.
60 */
61 unsigned long long om_queue, /* jiffies queued for xmit */
62 om_rtt, /* jiffies for RPC RTT */
63 om_execute; /* jiffies for RPC execution */
64} ____cacheline_aligned;
65
66struct rpc_task;
67struct rpc_clnt;
68
69/*
70 * EXPORTed functions for managing rpc_iostats structures
71 */
72struct rpc_iostats * rpc_alloc_iostats(struct rpc_clnt *);
73void rpc_count_iostats(struct rpc_task *);
74void rpc_print_iostats(struct seq_file *, struct rpc_clnt *);
75void rpc_free_iostats(struct rpc_iostats *);
76
77#endif /* _LINUX_SUNRPC_METRICS_H */
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)