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