syscall.c revision 1.1 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