Home | History | Annotate | Line # | Download | only in systat
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