1 /* $NetBSD: syscall.c,v 1.6 2009/04/13 23:20:27 lukem Exp $ */
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: syscall.c,v 1.6 2009/04/13 23:20:27 lukem Exp $");
35 /* System call stats */
37 #include <sys/param.h>
39 #include <sys/namei.h>
40 #include <sys/sysctl.h>
42 #include <uvm/uvm_extern.h>
52 #include "utmpentry.h"
55 #include <sys/syscall.h>
56 #include <../../sys/kern/syscalls.c>
58 #define nelem(x) (sizeof (x) / sizeof *(x))
61 struct uvmexp_sysctl uvmexp
;
63 uint64_t counts
[SYS_NSYSENT
];
64 uint64_t times
[SYS_NSYSENT
];
67 static uint64_t irf
[SYS_NSYSENT
], val
[SYS_NSYSENT
];
68 static int irf_first
= 1;
70 int syscall_sort
[SYS_NSYSENT
];
72 static enum sort_order
{ UNSORTED
, NAMES
, COUNTS
} sort_order
= NAMES
;
76 static int show
= SHOW_COUNTS
;
78 static void getinfo(struct Info
*, int);
83 static size_t counts_mib_len
, times_mib_len
;
84 static int counts_mib
[4], times_mib
[4];
93 closesyscall(WINDOW
*w
)
104 * These constants define where the major pieces are laid out
106 #define SYSCALLROW 9 /* Below the vmstat header */
111 static char name
[] = "name";
113 hertz
= stathz
? stathz
: hz
;
117 /* drvinit gets number of cpus! */
120 counts_mib_len
= nelem(counts_mib
);
121 if (sysctlnametomib("kern.syscalls.counts", counts_mib
, &counts_mib_len
))
124 times_mib_len
= nelem(times_mib
);
125 if (sysctlnametomib("kern.syscalls.times", times_mib
, ×_mib_len
))
128 getinfo(&s2
, SHOW_COUNTS
| SHOW_TIMES
);
140 strlcpy(buf
, ctime(&now
), sizeof(buf
));
154 putuint64(uint64_t v
, int row
, int col
, int width
)
156 static const char suffix
[] = "KMDT";
159 len
= snprintf(buf
, sizeof buf
, "%" PRIu64
, v
);
161 i
= (len
- width
) / 3;
162 if (i
>= (int)sizeof(suffix
)) {
163 memset(buf
, '*', width
);
167 buf
[len
++] = suffix
[i
];
171 mvprintw(row
, col
, "%*s", width
, buf
);
175 compare_irf(const void *a
, const void *b
)
177 int ia
= *(const int *)a
, ib
= *(const int *)b
;
180 delta
= irf
[ib
] - irf
[ia
];
181 return delta
? delta
< 0 ? -1 : 1 : 0;
189 static int failcnt
= 0;
190 static int relabel
= 0;
191 static char pigs
[] = "pigs";
200 if (display_mode
== TIME
) {
201 etime
= cur
.cp_etime
;
202 /* < 5 ticks - ignore this trash */
203 if ((etime
* hertz
) < 1.0) {
204 if (failcnt
++ <= MAXFAIL
)
207 mvprintw(2, 10, "The alternate system clock has died!");
208 mvprintw(3, 10, "Reverting to ``pigs'' display.");
222 show_vmstat_top(&s
.Total
, &s
.uvmexp
, &s1
.uvmexp
);
224 /* Sort out the values we are going to display */
225 for (i
= 0; i
< (int)nelem(s
.counts
); i
++) {
229 v
= s
.counts
[i
] - s1
.counts
[i
];
232 v
= s
.times
[i
] - s1
.times
[i
];
234 case SHOW_COUNTS
| SHOW_TIMES
: /* time/count */
235 v
= s
.counts
[i
] - s1
.counts
[i
];
236 v
= v
? (s
.times
[i
] - s1
.times
[i
]) / v
: 0;
239 if (display_mode
== TIME
)
240 v
= (v
* 100 + itime
/2) / itime
;
245 * We use an 'infinite response filter' in a vague
246 * attempt to stop the data leaping around too much.
247 * I suspect there are other/better methods in use.
253 irf
[i
] = irf
[i
] * 7 / 8 + v
;
257 if (sort_order
== COUNTS
) {
258 /* mergesort() doesn't swap equal values about... */
259 mergesort(syscall_sort
, nelem(syscall_sort
),
260 sizeof syscall_sort
[0], compare_irf
);
266 for (ii
= 0; ii
< (int)nelem(s
.counts
); ii
++) {
267 i
= syscall_sort
[ii
];
268 if (val
[i
] == 0 && irf
[i
] == 0)
271 if (i
< (int)nelem(syscallnames
)) {
272 const char *name
= syscallnames
[i
];
273 while (name
[0] == '_')
275 if (name
[0] == 'c' && !strcmp(name
+ 1, "ompat_"))
277 mvprintw(l
, c
, "%17.17s", name
);
279 mvprintw(l
, c
, "syscall #%d ", i
);
281 putuint64(val
[i
], l
, c
+ 18, 8);
290 if (display_mode
== TIME
) {
291 memcpy(s1
.counts
, s
.counts
, sizeof s1
.counts
);
292 memcpy(s1
.times
, s
.times
, sizeof s1
.times
);
294 while (l
< LINES
- 1) {
301 syscall_boot(char *args
)
303 memset(&s1
, 0, sizeof s1
);
308 syscall_run(char *args
)
315 syscall_time(char *args
)
321 syscall_zero(char *args
)
327 compare_names(const void *a
, const void *b
)
329 const char *name_a
= syscallnames
[*(const int *)a
];
330 const char *name_b
= syscallnames
[*(const int *)b
];
332 while (*name_a
== '_')
334 while (*name_b
== '_')
337 return strcmp(name_a
, name_b
);
341 syscall_order(char *args
)
348 len
= strcspn(args
, " \t\r\n");
350 if (args
[len
+ strspn(args
+ len
, " \t\r\n")])
353 if (memcmp(args
, "count", len
) == 0)
355 else if (memcmp(args
, "name", len
) == 0)
357 else if (memcmp(args
, "syscall", len
) == 0)
358 sort_order
= UNSORTED
;
362 /* Undo all the sorting */
363 for (i
= 0; i
< (int)nelem(syscall_sort
); i
++)
366 if (sort_order
== NAMES
) {
367 /* Only sort the entries we have names for */
368 qsort(syscall_sort
, nelem(syscallnames
), sizeof syscall_sort
[0],
374 error("Usage: sort [count|name|syscall]");
378 syscall_show(char *args
)
385 len
= strcspn(args
, " \t\r\n");
387 if (args
[len
+ strspn(args
+ len
, " \t\r\n")])
390 if (memcmp(args
, "counts", len
) == 0)
392 else if (memcmp(args
, "times", len
) == 0)
394 else if (memcmp(args
, "ratio", len
) == 0)
395 show
= SHOW_COUNTS
| SHOW_TIMES
;
399 memset(&irf
, 0, sizeof irf
);
405 error("Usage: show [counts|times|ratio]");
409 getinfo(struct Info
*stats
, int get_what
)
416 if (get_what
& SHOW_COUNTS
) {
417 size
= sizeof stats
->counts
;
418 if (!counts_mib_len
||
419 sysctl(counts_mib
, counts_mib_len
, &stats
->counts
, &size
,
421 error("can't get syscall counts: %s\n", strerror(errno
));
422 memset(&stats
->counts
, 0, sizeof stats
->counts
);
426 if (get_what
& SHOW_TIMES
) {
427 size
= sizeof stats
->times
;
428 if (!times_mib_len
||
429 sysctl(times_mib
, times_mib_len
, &stats
->times
, &size
,
431 error("can't get syscall times: %s\n", strerror(errno
));
432 memset(&stats
->times
, 0, sizeof stats
->times
);
436 size
= sizeof(stats
->uvmexp
);
439 if (sysctl(mib
, 2, &stats
->uvmexp
, &size
, NULL
, 0) < 0) {
440 error("can't get uvmexp: %s\n", strerror(errno
));
441 memset(&stats
->uvmexp
, 0, sizeof(stats
->uvmexp
));
443 size
= sizeof(stats
->Total
);
446 if (sysctl(mib
, 2, &stats
->Total
, &size
, NULL
, 0) < 0) {
447 error("Can't get kernel info: %s\n", strerror(errno
));
448 memset(&stats
->Total
, 0, sizeof(stats
->Total
));