|
@@ -21,6 +21,7 @@
|
|
|
#include <linux/seq_file.h>
|
|
|
#include <linux/sunrpc/clnt.h>
|
|
|
#include <linux/sunrpc/svcsock.h>
|
|
|
+#include <linux/sunrpc/metrics.h>
|
|
|
|
|
|
#define RPCDBG_FACILITY RPCDBG_MISC
|
|
|
|
|
@@ -106,6 +107,110 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * rpc_alloc_iostats - allocate an rpc_iostats structure
|
|
|
+ * @clnt: RPC program, version, and xprt
|
|
|
+ *
|
|
|
+ */
|
|
|
+struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
|
|
|
+{
|
|
|
+ unsigned int ops = clnt->cl_maxproc;
|
|
|
+ size_t size = ops * sizeof(struct rpc_iostats);
|
|
|
+ struct rpc_iostats *new;
|
|
|
+
|
|
|
+ new = kmalloc(size, GFP_KERNEL);
|
|
|
+ if (new)
|
|
|
+ memset(new, 0 , size);
|
|
|
+ return new;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(rpc_alloc_iostats);
|
|
|
+
|
|
|
+/**
|
|
|
+ * rpc_free_iostats - release an rpc_iostats structure
|
|
|
+ * @stats: doomed rpc_iostats structure
|
|
|
+ *
|
|
|
+ */
|
|
|
+void rpc_free_iostats(struct rpc_iostats *stats)
|
|
|
+{
|
|
|
+ kfree(stats);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(rpc_free_iostats);
|
|
|
+
|
|
|
+/**
|
|
|
+ * rpc_count_iostats - tally up per-task stats
|
|
|
+ * @task: completed rpc_task
|
|
|
+ *
|
|
|
+ * Relies on the caller for serialization.
|
|
|
+ */
|
|
|
+void rpc_count_iostats(struct rpc_task *task)
|
|
|
+{
|
|
|
+ struct rpc_rqst *req = task->tk_rqstp;
|
|
|
+ struct rpc_iostats *stats = task->tk_client->cl_metrics;
|
|
|
+ struct rpc_iostats *op_metrics;
|
|
|
+ long rtt, execute, queue;
|
|
|
+
|
|
|
+ if (!stats || !req)
|
|
|
+ return;
|
|
|
+ op_metrics = &stats[task->tk_msg.rpc_proc->p_proc];
|
|
|
+
|
|
|
+ op_metrics->om_ops++;
|
|
|
+ op_metrics->om_ntrans += req->rq_ntrans;
|
|
|
+ op_metrics->om_timeouts += task->tk_timeouts;
|
|
|
+
|
|
|
+ op_metrics->om_bytes_sent += task->tk_bytes_sent;
|
|
|
+ op_metrics->om_bytes_recv += req->rq_received;
|
|
|
+
|
|
|
+ queue = (long)req->rq_xtime - task->tk_start;
|
|
|
+ if (queue < 0)
|
|
|
+ queue = -queue;
|
|
|
+ op_metrics->om_queue += queue;
|
|
|
+
|
|
|
+ rtt = task->tk_rtt;
|
|
|
+ if (rtt < 0)
|
|
|
+ rtt = -rtt;
|
|
|
+ op_metrics->om_rtt += rtt;
|
|
|
+
|
|
|
+ execute = (long)jiffies - task->tk_start;
|
|
|
+ if (execute < 0)
|
|
|
+ execute = -execute;
|
|
|
+ op_metrics->om_execute += execute;
|
|
|
+}
|
|
|
+
|
|
|
+#define MILLISECS_PER_JIFFY (1000UL / HZ)
|
|
|
+
|
|
|
+void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
|
|
|
+{
|
|
|
+ struct rpc_iostats *stats = clnt->cl_metrics;
|
|
|
+ struct rpc_xprt *xprt = clnt->cl_xprt;
|
|
|
+ unsigned int op, maxproc = clnt->cl_maxproc;
|
|
|
+
|
|
|
+ if (!stats)
|
|
|
+ return;
|
|
|
+
|
|
|
+ seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS);
|
|
|
+ seq_printf(seq, "p/v: %u/%u (%s)\n",
|
|
|
+ clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
|
|
|
+
|
|
|
+ if (xprt)
|
|
|
+ xprt->ops->print_stats(xprt, seq);
|
|
|
+
|
|
|
+ seq_printf(seq, "\tper-op statistics\n");
|
|
|
+ for (op = 0; op < maxproc; op++) {
|
|
|
+ struct rpc_iostats *metrics = &stats[op];
|
|
|
+ seq_printf(seq, "%12u: ", op);
|
|
|
+ seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n",
|
|
|
+ metrics->om_ops,
|
|
|
+ metrics->om_ntrans,
|
|
|
+ metrics->om_timeouts,
|
|
|
+ metrics->om_bytes_sent,
|
|
|
+ metrics->om_bytes_recv,
|
|
|
+ metrics->om_queue * MILLISECS_PER_JIFFY,
|
|
|
+ metrics->om_rtt * MILLISECS_PER_JIFFY,
|
|
|
+ metrics->om_execute * MILLISECS_PER_JIFFY);
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(rpc_print_iostats);
|
|
|
+
|
|
|
/*
|
|
|
* Register/unregister RPC proc files
|
|
|
*/
|