xref: /openbmc/linux/net/sunrpc/stats.c (revision 5eb53f41)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * linux/net/sunrpc/stats.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * procfs-based user access to generic RPC statistics. The stats files
51da177e4SLinus Torvalds  * reside in /proc/net/rpc.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * The read routines assume that the buffer passed in is just big enough.
81da177e4SLinus Torvalds  * If you implement an RPC service that has its own stats routine which
91da177e4SLinus Torvalds  * appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
101da177e4SLinus Torvalds  * limit.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/module.h>
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/init.h>
181da177e4SLinus Torvalds #include <linux/kernel.h>
191da177e4SLinus Torvalds #include <linux/sched.h>
201da177e4SLinus Torvalds #include <linux/proc_fs.h>
211da177e4SLinus Torvalds #include <linux/seq_file.h>
221da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
231da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h>
2411c556b3SChuck Lever #include <linux/sunrpc/metrics.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #define RPCDBG_FACILITY	RPCDBG_MISC
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds struct proc_dir_entry	*proc_net_rpc = NULL;
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds  * Get RPC client stats
321da177e4SLinus Torvalds  */
331da177e4SLinus Torvalds static int rpc_proc_show(struct seq_file *seq, void *v) {
341da177e4SLinus Torvalds 	const struct rpc_stat	*statp = seq->private;
351da177e4SLinus Torvalds 	const struct rpc_program *prog = statp->program;
361da177e4SLinus Torvalds 	int		i, j;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	seq_printf(seq,
3949e31cbaSMax Kellermann 		"net %u %u %u %u\n",
401da177e4SLinus Torvalds 			statp->netcnt,
411da177e4SLinus Torvalds 			statp->netudpcnt,
421da177e4SLinus Torvalds 			statp->nettcpcnt,
431da177e4SLinus Torvalds 			statp->nettcpconn);
441da177e4SLinus Torvalds 	seq_printf(seq,
4549e31cbaSMax Kellermann 		"rpc %u %u %u\n",
461da177e4SLinus Torvalds 			statp->rpccnt,
471da177e4SLinus Torvalds 			statp->rpcretrans,
481da177e4SLinus Torvalds 			statp->rpcauthrefresh);
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	for (i = 0; i < prog->nrvers; i++) {
511da177e4SLinus Torvalds 		const struct rpc_version *vers = prog->version[i];
521da177e4SLinus Torvalds 		if (!vers)
531da177e4SLinus Torvalds 			continue;
5449e31cbaSMax Kellermann 		seq_printf(seq, "proc%u %u",
551da177e4SLinus Torvalds 					vers->number, vers->nrprocs);
561da177e4SLinus Torvalds 		for (j = 0; j < vers->nrprocs; j++)
5749e31cbaSMax Kellermann 			seq_printf(seq, " %u",
581da177e4SLinus Torvalds 					vers->procs[j].p_count);
591da177e4SLinus Torvalds 		seq_putc(seq, '\n');
601da177e4SLinus Torvalds 	}
611da177e4SLinus Torvalds 	return 0;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int rpc_proc_open(struct inode *inode, struct file *file)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	return single_open(file, rpc_proc_show, PDE(inode)->data);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds static struct file_operations rpc_proc_fops = {
701da177e4SLinus Torvalds 	.owner = THIS_MODULE,
711da177e4SLinus Torvalds 	.open = rpc_proc_open,
721da177e4SLinus Torvalds 	.read  = seq_read,
731da177e4SLinus Torvalds 	.llseek = seq_lseek,
741da177e4SLinus Torvalds 	.release = single_release,
751da177e4SLinus Torvalds };
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds /*
781da177e4SLinus Torvalds  * Get RPC server stats
791da177e4SLinus Torvalds  */
801da177e4SLinus Torvalds void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
811da177e4SLinus Torvalds 	const struct svc_program *prog = statp->program;
821da177e4SLinus Torvalds 	const struct svc_procedure *proc;
831da177e4SLinus Torvalds 	const struct svc_version *vers;
841da177e4SLinus Torvalds 	int		i, j;
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	seq_printf(seq,
8749e31cbaSMax Kellermann 		"net %u %u %u %u\n",
881da177e4SLinus Torvalds 			statp->netcnt,
891da177e4SLinus Torvalds 			statp->netudpcnt,
901da177e4SLinus Torvalds 			statp->nettcpcnt,
911da177e4SLinus Torvalds 			statp->nettcpconn);
921da177e4SLinus Torvalds 	seq_printf(seq,
9349e31cbaSMax Kellermann 		"rpc %u %u %u %u %u\n",
941da177e4SLinus Torvalds 			statp->rpccnt,
951da177e4SLinus Torvalds 			statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
961da177e4SLinus Torvalds 			statp->rpcbadfmt,
971da177e4SLinus Torvalds 			statp->rpcbadauth,
981da177e4SLinus Torvalds 			statp->rpcbadclnt);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	for (i = 0; i < prog->pg_nvers; i++) {
1011da177e4SLinus Torvalds 		if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
1021da177e4SLinus Torvalds 			continue;
10349e31cbaSMax Kellermann 		seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
1041da177e4SLinus Torvalds 		for (j = 0; j < vers->vs_nproc; j++, proc++)
10549e31cbaSMax Kellermann 			seq_printf(seq, " %u", proc->pc_count);
1061da177e4SLinus Torvalds 		seq_putc(seq, '\n');
1071da177e4SLinus Torvalds 	}
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds 
11011c556b3SChuck Lever /**
11111c556b3SChuck Lever  * rpc_alloc_iostats - allocate an rpc_iostats structure
11211c556b3SChuck Lever  * @clnt: RPC program, version, and xprt
11311c556b3SChuck Lever  *
11411c556b3SChuck Lever  */
11511c556b3SChuck Lever struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
11611c556b3SChuck Lever {
11711c556b3SChuck Lever 	unsigned int ops = clnt->cl_maxproc;
11811c556b3SChuck Lever 	size_t size = ops * sizeof(struct rpc_iostats);
11911c556b3SChuck Lever 	struct rpc_iostats *new;
12011c556b3SChuck Lever 
12111c556b3SChuck Lever 	new = kmalloc(size, GFP_KERNEL);
12211c556b3SChuck Lever 	if (new)
12311c556b3SChuck Lever 		memset(new, 0 , size);
12411c556b3SChuck Lever 	return new;
12511c556b3SChuck Lever }
12611c556b3SChuck Lever EXPORT_SYMBOL(rpc_alloc_iostats);
12711c556b3SChuck Lever 
12811c556b3SChuck Lever /**
12911c556b3SChuck Lever  * rpc_free_iostats - release an rpc_iostats structure
13011c556b3SChuck Lever  * @stats: doomed rpc_iostats structure
13111c556b3SChuck Lever  *
13211c556b3SChuck Lever  */
13311c556b3SChuck Lever void rpc_free_iostats(struct rpc_iostats *stats)
13411c556b3SChuck Lever {
13511c556b3SChuck Lever 	kfree(stats);
13611c556b3SChuck Lever }
13711c556b3SChuck Lever EXPORT_SYMBOL(rpc_free_iostats);
13811c556b3SChuck Lever 
13911c556b3SChuck Lever /**
14011c556b3SChuck Lever  * rpc_count_iostats - tally up per-task stats
14111c556b3SChuck Lever  * @task: completed rpc_task
14211c556b3SChuck Lever  *
14311c556b3SChuck Lever  * Relies on the caller for serialization.
14411c556b3SChuck Lever  */
14511c556b3SChuck Lever void rpc_count_iostats(struct rpc_task *task)
14611c556b3SChuck Lever {
14711c556b3SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
14811c556b3SChuck Lever 	struct rpc_iostats *stats = task->tk_client->cl_metrics;
14911c556b3SChuck Lever 	struct rpc_iostats *op_metrics;
15011c556b3SChuck Lever 	long rtt, execute, queue;
15111c556b3SChuck Lever 
15211c556b3SChuck Lever 	if (!stats || !req)
15311c556b3SChuck Lever 		return;
154cc0175c1SChuck Lever 	op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx];
15511c556b3SChuck Lever 
15611c556b3SChuck Lever 	op_metrics->om_ops++;
15711c556b3SChuck Lever 	op_metrics->om_ntrans += req->rq_ntrans;
15811c556b3SChuck Lever 	op_metrics->om_timeouts += task->tk_timeouts;
15911c556b3SChuck Lever 
16011c556b3SChuck Lever 	op_metrics->om_bytes_sent += task->tk_bytes_sent;
16111c556b3SChuck Lever 	op_metrics->om_bytes_recv += req->rq_received;
16211c556b3SChuck Lever 
16311c556b3SChuck Lever 	queue = (long)req->rq_xtime - task->tk_start;
16411c556b3SChuck Lever 	if (queue < 0)
16511c556b3SChuck Lever 		queue = -queue;
16611c556b3SChuck Lever 	op_metrics->om_queue += queue;
16711c556b3SChuck Lever 
16811c556b3SChuck Lever 	rtt = task->tk_rtt;
16911c556b3SChuck Lever 	if (rtt < 0)
17011c556b3SChuck Lever 		rtt = -rtt;
17111c556b3SChuck Lever 	op_metrics->om_rtt += rtt;
17211c556b3SChuck Lever 
17311c556b3SChuck Lever 	execute = (long)jiffies - task->tk_start;
17411c556b3SChuck Lever 	if (execute < 0)
17511c556b3SChuck Lever 		execute = -execute;
17611c556b3SChuck Lever 	op_metrics->om_execute += execute;
17711c556b3SChuck Lever }
17811c556b3SChuck Lever 
179cc0175c1SChuck Lever void _print_name(struct seq_file *seq, unsigned int op, struct rpc_procinfo *procs)
180cc0175c1SChuck Lever {
181cc0175c1SChuck Lever 	if (procs[op].p_name)
182cc0175c1SChuck Lever 		seq_printf(seq, "\t%12s: ", procs[op].p_name);
183cc0175c1SChuck Lever 	else if (op == 0)
184cc0175c1SChuck Lever 		seq_printf(seq, "\t        NULL: ");
185cc0175c1SChuck Lever 	else
186cc0175c1SChuck Lever 		seq_printf(seq, "\t%12u: ", op);
187cc0175c1SChuck Lever }
188cc0175c1SChuck Lever 
189*5eb53f41SChuck Lever #define MILLISECS_PER_JIFFY	(1000 / HZ)
19011c556b3SChuck Lever 
19111c556b3SChuck Lever void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
19211c556b3SChuck Lever {
19311c556b3SChuck Lever 	struct rpc_iostats *stats = clnt->cl_metrics;
19411c556b3SChuck Lever 	struct rpc_xprt *xprt = clnt->cl_xprt;
19511c556b3SChuck Lever 	unsigned int op, maxproc = clnt->cl_maxproc;
19611c556b3SChuck Lever 
19711c556b3SChuck Lever 	if (!stats)
19811c556b3SChuck Lever 		return;
19911c556b3SChuck Lever 
20011c556b3SChuck Lever 	seq_printf(seq, "\tRPC iostats version: %s  ", RPC_IOSTATS_VERS);
20111c556b3SChuck Lever 	seq_printf(seq, "p/v: %u/%u (%s)\n",
20211c556b3SChuck Lever 			clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
20311c556b3SChuck Lever 
20411c556b3SChuck Lever 	if (xprt)
20511c556b3SChuck Lever 		xprt->ops->print_stats(xprt, seq);
20611c556b3SChuck Lever 
20711c556b3SChuck Lever 	seq_printf(seq, "\tper-op statistics\n");
20811c556b3SChuck Lever 	for (op = 0; op < maxproc; op++) {
20911c556b3SChuck Lever 		struct rpc_iostats *metrics = &stats[op];
210cc0175c1SChuck Lever 		_print_name(seq, op, clnt->cl_procinfo);
21111c556b3SChuck Lever 		seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n",
21211c556b3SChuck Lever 				metrics->om_ops,
21311c556b3SChuck Lever 				metrics->om_ntrans,
21411c556b3SChuck Lever 				metrics->om_timeouts,
21511c556b3SChuck Lever 				metrics->om_bytes_sent,
21611c556b3SChuck Lever 				metrics->om_bytes_recv,
21711c556b3SChuck Lever 				metrics->om_queue * MILLISECS_PER_JIFFY,
21811c556b3SChuck Lever 				metrics->om_rtt * MILLISECS_PER_JIFFY,
21911c556b3SChuck Lever 				metrics->om_execute * MILLISECS_PER_JIFFY);
22011c556b3SChuck Lever 	}
22111c556b3SChuck Lever }
22211c556b3SChuck Lever EXPORT_SYMBOL(rpc_print_iostats);
22311c556b3SChuck Lever 
2241da177e4SLinus Torvalds /*
2251da177e4SLinus Torvalds  * Register/unregister RPC proc files
2261da177e4SLinus Torvalds  */
2271da177e4SLinus Torvalds static inline struct proc_dir_entry *
2281da177e4SLinus Torvalds do_register(const char *name, void *data, struct file_operations *fops)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	struct proc_dir_entry *ent;
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	rpc_proc_init();
2331da177e4SLinus Torvalds 	dprintk("RPC: registering /proc/net/rpc/%s\n", name);
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 	ent = create_proc_entry(name, 0, proc_net_rpc);
2361da177e4SLinus Torvalds 	if (ent) {
2371da177e4SLinus Torvalds 		ent->proc_fops = fops;
2381da177e4SLinus Torvalds 		ent->data = data;
2391da177e4SLinus Torvalds 	}
2401da177e4SLinus Torvalds 	return ent;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds struct proc_dir_entry *
2441da177e4SLinus Torvalds rpc_proc_register(struct rpc_stat *statp)
2451da177e4SLinus Torvalds {
2461da177e4SLinus Torvalds 	return do_register(statp->program->name, statp, &rpc_proc_fops);
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds void
2501da177e4SLinus Torvalds rpc_proc_unregister(const char *name)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds 	remove_proc_entry(name, proc_net_rpc);
2531da177e4SLinus Torvalds }
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds struct proc_dir_entry *
2561da177e4SLinus Torvalds svc_proc_register(struct svc_stat *statp, struct file_operations *fops)
2571da177e4SLinus Torvalds {
2581da177e4SLinus Torvalds 	return do_register(statp->program->pg_name, statp, fops);
2591da177e4SLinus Torvalds }
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds void
2621da177e4SLinus Torvalds svc_proc_unregister(const char *name)
2631da177e4SLinus Torvalds {
2641da177e4SLinus Torvalds 	remove_proc_entry(name, proc_net_rpc);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds void
2681da177e4SLinus Torvalds rpc_proc_init(void)
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds 	dprintk("RPC: registering /proc/net/rpc\n");
2711da177e4SLinus Torvalds 	if (!proc_net_rpc) {
2721da177e4SLinus Torvalds 		struct proc_dir_entry *ent;
2731da177e4SLinus Torvalds 		ent = proc_mkdir("rpc", proc_net);
2741da177e4SLinus Torvalds 		if (ent) {
2751da177e4SLinus Torvalds 			ent->owner = THIS_MODULE;
2761da177e4SLinus Torvalds 			proc_net_rpc = ent;
2771da177e4SLinus Torvalds 		}
2781da177e4SLinus Torvalds 	}
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds void
2821da177e4SLinus Torvalds rpc_proc_exit(void)
2831da177e4SLinus Torvalds {
2841da177e4SLinus Torvalds 	dprintk("RPC: unregistering /proc/net/rpc\n");
2851da177e4SLinus Torvalds 	if (proc_net_rpc) {
2861da177e4SLinus Torvalds 		proc_net_rpc = NULL;
2871da177e4SLinus Torvalds 		remove_proc_entry("net/rpc", NULL);
2881da177e4SLinus Torvalds 	}
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds 
291