xref: /dragonfly/sbin/hammer/cmd_stats.c (revision e6e77800)
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sbin/hammer/cmd_stats.c,v 1.3 2008/07/14 20:28:07 dillon Exp $
35  */
36 
37 #include "hammer.h"
38 
39 #include <sys/sysctl.h>
40 #include <math.h>
41 
42 static void loaddelay(struct timespec *ts, const char *arg);
43 
44 #define _HAMMER "vfs.hammer.stats_"
45 #define bstats_title	\
46 "   lookups   searches    inserts    deletes   elements     splits iterations  rootiters   reciters"
47 #define iostats_title	\
48 "   f_read   f_write    d_read   d_write i_flushes   commits      undo      redo"
49 
50 /*
51  * Taken from sys/vfs/hammer/hammer_vfsops.c
52  */
53 struct btree_stats {
54 	int64_t btree_lookups;
55 	int64_t btree_searches;
56 	int64_t btree_inserts;
57 	int64_t btree_deletes;
58 	int64_t btree_elements;
59 	int64_t btree_splits;
60 	int64_t btree_iterations;
61 	int64_t btree_root_iterations;
62 	int64_t record_iterations;
63 };
64 
65 struct io_stats {
66 	int64_t file_read;
67 	int64_t file_write;
68 	int64_t disk_read;
69 	int64_t disk_write;
70 	int64_t inode_flushes;
71 	int64_t commits;
72 	int64_t undo;
73 	int64_t redo;
74 };
75 
76 static __inline __always_inline
77 int
78 _sysctl(const char *name, int64_t *p)
79 {
80 	size_t len = sizeof(*p);
81 	return(sysctlbyname(name, p, &len, NULL, 0));
82 }
83 
84 static __inline __always_inline
85 void
86 collect_bstats(struct btree_stats *p)
87 {
88 	/* sysctls must exist, so ignore return values */
89 	_sysctl(_HAMMER"btree_lookups", &p->btree_lookups);
90 	_sysctl(_HAMMER"btree_searches", &p->btree_searches);
91 	_sysctl(_HAMMER"btree_inserts", &p->btree_inserts);
92 	_sysctl(_HAMMER"btree_deletes", &p->btree_deletes);
93 	_sysctl(_HAMMER"btree_elements", &p->btree_elements);
94 	_sysctl(_HAMMER"btree_splits", &p->btree_splits);
95 	_sysctl(_HAMMER"btree_iterations", &p->btree_iterations);
96 	_sysctl(_HAMMER"btree_root_iterations", &p->btree_root_iterations);
97 	_sysctl(_HAMMER"record_iterations", &p->record_iterations);
98 }
99 
100 static __inline __always_inline
101 void
102 collect_iostats(struct io_stats *p)
103 {
104 	/* sysctls must exist, so ignore return values */
105 	_sysctl(_HAMMER"file_read", &p->file_read);
106 	_sysctl(_HAMMER"file_write", &p->file_write);
107 	_sysctl(_HAMMER"disk_read", &p->disk_read);
108 	_sysctl(_HAMMER"disk_write", &p->disk_write);
109 	_sysctl(_HAMMER"inode_flushes", &p->inode_flushes);
110 	_sysctl(_HAMMER"commits", &p->commits);
111 	_sysctl(_HAMMER"undo", &p->undo);
112 	_sysctl(_HAMMER"redo", &p->redo);
113 }
114 
115 static __inline __always_inline
116 void
117 print_bstats(const struct btree_stats *p1, const struct btree_stats *p2)
118 {
119 	printf("%10jd %10jd %10jd %10jd %10jd %10jd %10jd %10jd %10jd",
120 		(intmax_t)(p1->btree_lookups - p2->btree_lookups),
121 		(intmax_t)(p1->btree_searches - p2->btree_searches),
122 		(intmax_t)(p1->btree_inserts - p2->btree_inserts),
123 		(intmax_t)(p1->btree_deletes - p2->btree_deletes),
124 		(intmax_t)(p1->btree_elements - p2->btree_elements),
125 		(intmax_t)(p1->btree_splits - p2->btree_splits),
126 		(intmax_t)(p1->btree_iterations - p2->btree_iterations),
127 		(intmax_t)(p1->btree_root_iterations - p2->btree_root_iterations),
128 		(intmax_t)(p1->record_iterations - p2->record_iterations));
129 		/* no trailing \n */
130 }
131 
132 static __inline __always_inline
133 void
134 print_iostats(const struct io_stats *p1, const struct io_stats *p2)
135 {
136 	printf("%9jd %9jd %9jd %9jd %9jd %9jd %9jd %9jd",
137 		(intmax_t)(p1->file_read - p2->file_read),
138 		(intmax_t)(p1->file_write - p2->file_write),
139 		(intmax_t)(p1->disk_read - p2->disk_read),
140 		(intmax_t)(p1->disk_write - p2->disk_write),
141 		(intmax_t)(p1->inode_flushes - p2->inode_flushes),
142 		(intmax_t)(p1->commits - p2->commits),
143 		(intmax_t)(p1->undo - p2->undo),
144 		(intmax_t)(p1->redo - p2->redo));
145 		/* no trailing \n */
146 }
147 
148 void
149 hammer_cmd_bstats(char **av, int ac)
150 {
151 	struct btree_stats st1, st2;
152 	struct timespec delay = {1, 0};
153 	int count;
154 
155 	bzero(&st1, sizeof(st1));
156 	bzero(&st2, sizeof(st2));
157 
158 	if (ac > 0)
159 		loaddelay(&delay, av[0]);
160 
161 	for (count = 0; ; ++count) {
162 		collect_bstats(&st1);
163 		if (count) {
164 			if ((count & 15) == 1)
165 				printf(bstats_title"\n");
166 			print_bstats(&st1, &st2);
167 			printf("\n");
168 		}
169 		bcopy(&st1, &st2, sizeof(st2));
170 		nanosleep(&delay, NULL);
171 	}
172 }
173 
174 void
175 hammer_cmd_iostats(char **av, int ac)
176 {
177 	struct io_stats st1, st2;
178 	struct timespec delay = {1, 0};
179 	int count;
180 
181 	bzero(&st1, sizeof(st1));
182 	bzero(&st2, sizeof(st2));
183 
184 	if (ac > 0)
185 		loaddelay(&delay, av[0]);
186 
187 	for (count = 0; ; ++count) {
188 		collect_iostats(&st1);
189 		if (count) {
190 			if ((count & 15) == 1)
191 				printf(iostats_title"\n");
192 			print_iostats(&st1, &st2);
193 			printf("\n");
194 		}
195 		bcopy(&st1, &st2, sizeof(st2));
196 		nanosleep(&delay, NULL);
197 	}
198 }
199 
200 void
201 hammer_cmd_stats(char **av, int ac)
202 {
203 	struct btree_stats bst1, bst2;
204 	struct io_stats ist1, ist2;
205 	struct timespec delay = {1, 0};
206 	int count;
207 
208 	bzero(&bst1, sizeof(bst1));
209 	bzero(&bst2, sizeof(bst2));
210 	bzero(&ist1, sizeof(ist1));
211 	bzero(&ist2, sizeof(ist2));
212 
213 	if (ac > 0)
214 		loaddelay(&delay, av[0]);
215 
216 	for (count = 0; ; ++count) {
217 		collect_bstats(&bst1);
218 		collect_iostats(&ist1);
219 		if (count) {
220 			if ((count & 15) == 1)
221 				printf(bstats_title"\t"iostats_title"\n");
222 			print_bstats(&bst1, &bst2);
223 			printf("\t");
224 			print_iostats(&ist1, &ist2);
225 			printf("\n");
226 		}
227 		bcopy(&bst1, &bst2, sizeof(bst2));
228 		bcopy(&ist1, &ist2, sizeof(ist2));
229 		nanosleep(&delay, NULL);
230 	}
231 }
232 
233 /*
234  * Convert a delay string (e.g. "0.1") into a timespec.
235  */
236 static
237 void
238 loaddelay(struct timespec *ts, const char *arg)
239 {
240 	double d;
241 
242 	d = strtod(arg, NULL);
243 	if (d < 0.001)
244 		d = 0.001;
245 	ts->tv_sec = (int)d;
246 	ts->tv_nsec = (int)(modf(d, &d) * 1000000000.0);
247 }
248