xref: /netbsd-src/usr.bin/systat/syscall.c (revision f81322cf185a4db50f71fcf7701f20198272620e)
1 /*	$NetBSD: syscall.c,v 1.1 2006/03/18 20:31:45 dsl Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by David Laight.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The NetBSD Foundation nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: syscall.c,v 1.1 2006/03/18 20:31:45 dsl Exp $");
37 
38 /* System call stats */
39 
40 #include <sys/param.h>
41 #include <sys/user.h>
42 #include <sys/namei.h>
43 #include <sys/sysctl.h>
44 #include <sys/device.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #include <stdlib.h>
49 #include <string.h>
50 #include <util.h>
51 
52 #include "systat.h"
53 #include "extern.h"
54 #include "dkstats.h"
55 #include "utmpentry.h"
56 #include "vmstat.h"
57 
58 #include <sys/syscall.h>
59 #include <../../sys/kern/syscalls.c>
60 
61 #define nelem(x) (sizeof (x) / sizeof *(x))
62 
63 static struct Info {
64 	struct	uvmexp_sysctl uvmexp;
65 	struct	vmtotal Total;
66 	int     syscall[SYS_NSYSENT];
67 } s, s1, s2, irf;
68 
69 int syscall_sort[SYS_NSYSENT];
70 
71 static	enum sort_order { UNSORTED, NAMES, COUNTS } sort_order = NAMES;
72 
73 static void getinfo(struct Info *);
74 
75 static	char buf[26];
76 static	float hertz;
77 
78 static size_t syscall_mib_len;
79 static int syscall_mib[4];
80 
81 WINDOW *
82 opensyscall(void)
83 {
84 	return (stdscr);
85 }
86 
87 void
88 closesyscall(WINDOW *w)
89 {
90 
91 	if (w == NULL)
92 		return;
93 	wclear(w);
94 	wrefresh(w);
95 }
96 
97 
98 /*
99  * These constants define where the major pieces are laid out
100  */
101 #define SYSCALLROW	9	/* Below the vmstat header */
102 
103 int
104 initsyscall(void)
105 {
106 	static char name[] = "name";
107 
108 	hertz = stathz ? stathz : hz;
109 
110 	syscall_order(name);
111 
112 	/* dkinit gets number of cpus! */
113 	dkinit(1);
114 
115 	syscall_mib_len = nelem(syscall_mib);
116 	if (sysctlnametomib("kern.syscalls.counts", syscall_mib, &syscall_mib_len) &&
117 	    sysctlnametomib("kern.syscalls", syscall_mib, &syscall_mib_len))
118 		syscall_mib_len = 0;
119 
120 	getinfo(&s2);
121 	s1 = s2;
122 	return(1);
123 }
124 
125 void
126 fetchsyscall(void)
127 {
128 	time_t now;
129 
130 	time(&now);
131 	strlcpy(buf, ctime(&now), sizeof(buf));
132 	buf[19] = '\0';
133 	getinfo(&s);
134 }
135 
136 void
137 labelsyscall(void)
138 {
139 	labelvmstat_top();
140 }
141 
142 #define MAXFAIL 5
143 
144 static int
145 compare_counts(const void *a, const void *b)
146 {
147 	int ia = *(const int *)a, ib = *(const int *)b;
148 
149 	if (display_mode == TIME)
150 		return irf.syscall[ib] - irf.syscall[ia];
151 
152 	return s.syscall[ib] - s1.syscall[ib] - s.syscall[ia] + s1.syscall[ia];
153 }
154 
155 void
156 showsyscall(void)
157 {
158 	int i, ii, l, c;
159 	unsigned int val;
160 	static int failcnt = 0;
161 	static int relabel = 0;
162 	static char pigs[] = "pigs";
163 
164 	if (relabel) {
165 		labelsyscall();
166 		relabel = 0;
167 	}
168 
169 	cpuswap();
170 	if (display_mode == TIME) {
171 		etime = cur.cp_etime;
172 		/* < 5 ticks - ignore this trash */
173 		if ((etime * hertz) < 1.0) {
174 			if (failcnt++ > MAXFAIL)
175 				return;
176 			failcnt = 0;
177 			clear();
178 			mvprintw(2, 10, "The alternate system clock has died!");
179 			mvprintw(3, 10, "Reverting to ``pigs'' display.");
180 			move(CMDLINE, 0);
181 			refresh();
182 			failcnt = 0;
183 			sleep(5);
184 			command(pigs);
185 			return;
186 		}
187 	} else
188 		etime = 1.0;
189 
190 	failcnt = 0;
191 
192 	show_vmstat_top(&s.Total, &s.uvmexp, &s1.uvmexp);
193 
194 	if (sort_order == COUNTS) {
195 		/*
196 		 * We use an 'infinite response filter' in a vague
197 		 * attempt to stop the data leaping around too much.
198 		 * I suspect there are other/better methods in use.
199 		 */
200 		for (i = 0; i < nelem(s.syscall); i++) {
201 			val = s.syscall[i] - s1.syscall[i];
202 			irf.syscall[i] = irf.syscall[i] * 7 / 8 + val;
203 		}
204 
205 		/* mergesort() doesn't swap equal values about... */
206 		mergesort(syscall_sort, nelem(syscall_sort),
207 			sizeof syscall_sort[0], compare_counts);
208 	}
209 
210 	l = SYSCALLROW;
211 	c = 0;
212 	move(l, c);
213 	for (ii = 0; ii < nelem(s.syscall); ii++) {
214 		i = syscall_sort[ii];
215 		val = s.syscall[i] - s1.syscall[i];
216 		if (val == 0 && irf.syscall[i] == 0)
217 			continue;
218 
219 		if (i < nelem(syscallnames)) {
220 			const char *name = syscallnames[i];
221 			while (name[0] == '_')
222 				name++;
223 			if (name[0] == 'c' && !strcmp(name + 1, "ompat_"))
224 				name += 7;
225 			mvprintw(l, c, "%17.17s", name);
226 		} else
227 			mvprintw(l, c, "syscall #%d       ", i);
228 
229 		putint((int)((float)val/etime + 0.5), l, c + 17, 9);
230 		c += 27;
231 		if (c + 26 > COLS) {
232 			c = 0;
233 			l++;
234 			if (l >= LINES - 1)
235 				break;
236 		}
237 	}
238 	if (display_mode == TIME)
239 		memcpy(s1.syscall, s.syscall, sizeof s1.syscall);
240 	while (l < LINES - 1) {
241 	    clrtoeol();
242 	    move(++l, 0);
243 	}
244 }
245 
246 void
247 syscall_boot(char *args)
248 {
249 	memset(&s1, 0, sizeof s1);
250 	display_mode = BOOT;
251 }
252 
253 void
254 syscall_run(char *args)
255 {
256 	s1 = s2;
257 	display_mode = RUN;
258 }
259 
260 void
261 syscall_time(char *args)
262 {
263 	display_mode = TIME;
264 }
265 
266 void
267 syscall_zero(char *args)
268 {
269 	s1 = s;
270 }
271 
272 static int
273 compare_names(const void *a, const void *b)
274 {
275 	const char *name_a = syscallnames[*(const int *)a];
276 	const char *name_b = syscallnames[*(const int *)b];
277 
278 	while (*name_a == '_')
279 		name_a++;
280 	while (*name_b == '_')
281 		name_b++;
282 
283 	return strcmp(name_a, name_b);
284 }
285 
286 void
287 syscall_order(char *args)
288 {
289 	int i, len;
290 
291 	if (args == NULL)
292 		goto usage;
293 
294 	len = strcspn(args, " \t\r\n");
295 
296 	if (args[len + strspn(args + len, " \t\r\n")])
297 		goto usage;
298 
299 	if (memcmp(args, "count", len) == 0)
300 		sort_order = COUNTS;
301 	else if (memcmp(args, "name", len) == 0)
302 		sort_order = NAMES;
303 	else if (memcmp(args, "syscall", len) == 0)
304 		sort_order = UNSORTED;
305 	else
306 		goto usage;
307 
308 	/* Undo all the sorting */
309 	for (i = 0; i < nelem(syscall_sort); i++)
310 		syscall_sort[i] = i;
311 
312 	if (sort_order == NAMES) {
313 		/* Only sort the entries we have names for */
314 		qsort(syscall_sort, nelem(syscallnames), sizeof syscall_sort[0],
315 			compare_names);
316 	}
317 	return;
318 
319     usage:
320 	error("Usage: sort [count|name|syscall]");
321 }
322 
323 static void
324 getinfo(struct Info *stats)
325 {
326 	int mib[2];
327 	size_t size;
328 
329 	cpureadstats();
330 
331 	size = sizeof stats->syscall;
332 	if (!syscall_mib_len ||
333 	    sysctl(syscall_mib, syscall_mib_len, &stats->syscall, &size,
334 		    NULL, 0)) {
335 		error("can't get syscall counts: %s\n", strerror(errno));
336 		memset(&stats->syscall, 0, sizeof stats->syscall);
337 	}
338 
339 	size = sizeof(stats->uvmexp);
340 	mib[0] = CTL_VM;
341 	mib[1] = VM_UVMEXP2;
342 	if (sysctl(mib, 2, &stats->uvmexp, &size, NULL, 0) < 0) {
343 		error("can't get uvmexp: %s\n", strerror(errno));
344 		memset(&stats->uvmexp, 0, sizeof(stats->uvmexp));
345 	}
346 	size = sizeof(stats->Total);
347 	mib[0] = CTL_VM;
348 	mib[1] = VM_METER;
349 	if (sysctl(mib, 2, &stats->Total, &size, NULL, 0) < 0) {
350 		error("Can't get kernel info: %s\n", strerror(errno));
351 		memset(&stats->Total, 0, sizeof(stats->Total));
352 	}
353 }
354