PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/cmd/stat/vmstat/vmstat.c

https://bitbucket.org/dilos/onarm-gate
C | 544 lines | 436 code | 84 blank | 24 comment | 58 complexity | 411eb8e2814856446ff038ffc8929994 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, AGPL-3.0, MIT, Apache-2.0, 0BSD, GPL-2.0, LGPL-2.0, AGPL-1.0, BSD-3-Clause, LGPL-3.0, BSD-3-Clause-No-Nuclear-License-2014
  1. /*
  2. * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
  3. * Use is subject to license terms.
  4. */
  5. /*
  6. * Copyright (c) 1980 Regents of the University of California.
  7. * All rights reserved. The Berkeley software License Agreement
  8. * specifies the terms and conditions for redistribution.
  9. */
  10. #pragma ident "%Z%%M% %I% %E% SMI"
  11. /* from UCB 5.4 5/17/86 */
  12. /* from SunOS 4.1, SID 1.31 */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdarg.h>
  16. #include <ctype.h>
  17. #include <unistd.h>
  18. #include <memory.h>
  19. #include <string.h>
  20. #include <fcntl.h>
  21. #include <errno.h>
  22. #include <signal.h>
  23. #include <values.h>
  24. #include <poll.h>
  25. #include "statcommon.h"
  26. char *cmdname = "vmstat";
  27. int caught_cont = 0;
  28. static int hz;
  29. static int pagesize;
  30. static double etime;
  31. static int lines = 1;
  32. static int swflag = 0, cflag = 0, pflag = 0;
  33. static int suppress_state;
  34. static long iter = 0;
  35. static hrtime_t period_n = 0;
  36. static struct snapshot *ss;
  37. struct iodev_filter df;
  38. #define pgtok(a) ((a) * (pagesize >> 10))
  39. #define denom(x) ((x) ? (x) : 1)
  40. #define REPRINT 19
  41. static void dovmstats(struct snapshot *old, struct snapshot *new);
  42. static void printhdr(int);
  43. static void dosum(struct sys_snapshot *ss);
  44. static void dointr(struct snapshot *ss);
  45. static void docachestats(kstat_ctl_t *kc, hrtime_t interval, int forever);
  46. static void usage(void);
  47. int
  48. main(int argc, char **argv)
  49. {
  50. struct snapshot *old = NULL;
  51. enum snapshot_types types = SNAP_SYSTEM;
  52. int summary = 0;
  53. int intr = 0;
  54. kstat_ctl_t *kc;
  55. int forever = 0;
  56. hrtime_t start_n;
  57. pagesize = sysconf(_SC_PAGESIZE);
  58. hz = sysconf(_SC_CLK_TCK);
  59. argc--, argv++;
  60. while (argc > 0 && argv[0][0] == '-') {
  61. char *cp = *argv++;
  62. argc--;
  63. while (*++cp) {
  64. switch (*cp) {
  65. case 'S':
  66. swflag = !swflag;
  67. break;
  68. case 's':
  69. summary = 1;
  70. break;
  71. case 'i':
  72. intr = 1;
  73. break;
  74. case 'c':
  75. cflag++;
  76. break;
  77. case 'q':
  78. suppress_state = 1;
  79. break;
  80. case 'p':
  81. pflag++; /* detailed paging info */
  82. break;
  83. default:
  84. usage();
  85. }
  86. }
  87. }
  88. /* consistency with iostat */
  89. types |= SNAP_CPUS;
  90. if (intr)
  91. types |= SNAP_INTERRUPTS;
  92. if (cflag)
  93. types |= SNAP_FLUSHES;
  94. if (!intr)
  95. types |= SNAP_IODEVS;
  96. /* max to fit in less than 80 characters */
  97. df.if_max_iodevs = 4;
  98. df.if_allowed_types = IODEV_DISK;
  99. df.if_nr_names = 0;
  100. df.if_names = safe_alloc(df.if_max_iodevs * sizeof (char *));
  101. (void) memset(df.if_names, 0, df.if_max_iodevs * sizeof (char *));
  102. while (argc > 0 && !isdigit(argv[0][0]) &&
  103. df.if_nr_names < df.if_max_iodevs) {
  104. df.if_names[df.if_nr_names] = *argv;
  105. df.if_nr_names++;
  106. argc--, argv++;
  107. }
  108. kc = open_kstat();
  109. start_n = gethrtime();
  110. ss = acquire_snapshot(kc, types, &df);
  111. /* time, in seconds, since boot */
  112. etime = ss->s_sys.ss_ticks / hz;
  113. if (intr) {
  114. dointr(ss);
  115. free_snapshot(ss);
  116. exit(0);
  117. }
  118. if (summary) {
  119. dosum(&ss->s_sys);
  120. free_snapshot(ss);
  121. exit(0);
  122. }
  123. if (argc > 0) {
  124. long interval;
  125. char *endptr;
  126. errno = 0;
  127. interval = strtol(argv[0], &endptr, 10);
  128. if (errno > 0 || *endptr != '\0' || interval <= 0 ||
  129. interval > MAXINT)
  130. usage();
  131. period_n = (hrtime_t)interval * NANOSEC;
  132. if (period_n <= 0)
  133. usage();
  134. iter = MAXLONG;
  135. if (argc > 1) {
  136. iter = strtol(argv[1], NULL, 10);
  137. if (errno > 0 || *endptr != '\0' || iter <= 0)
  138. usage();
  139. } else
  140. forever = 1;
  141. if (argc > 2)
  142. usage();
  143. }
  144. if (cflag) {
  145. free_snapshot(ss);
  146. docachestats(kc, period_n, forever);
  147. exit(0);
  148. }
  149. (void) sigset(SIGCONT, printhdr);
  150. printhdr(0);
  151. dovmstats(old, ss);
  152. while (forever || --iter > 0) {
  153. /* (void) poll(NULL, 0, poll_interval); */
  154. /* Have a kip */
  155. sleep_until(&start_n, period_n, forever, &caught_cont);
  156. free_snapshot(old);
  157. old = ss;
  158. ss = acquire_snapshot(kc, types, &df);
  159. if (!suppress_state)
  160. snapshot_report_changes(old, ss);
  161. /* if config changed, show stats from boot */
  162. if (snapshot_has_changed(old, ss)) {
  163. free_snapshot(old);
  164. old = NULL;
  165. }
  166. dovmstats(old, ss);
  167. }
  168. free_snapshot(old);
  169. free_snapshot(ss);
  170. free(df.if_names);
  171. (void) kstat_close(kc);
  172. return (0);
  173. }
  174. #define DELTA(v) (new->v - (old ? old->v : 0))
  175. #define ADJ(n) ((adj <= 0) ? n : (adj >= n) ? 1 : n - adj)
  176. #define adjprintf(fmt, n, val) adj -= (n + 1) - printf(fmt, ADJ(n), val)
  177. static int adj; /* number of excess columns */
  178. /*ARGSUSED*/
  179. static void
  180. show_disk(void *v1, void *v2, void *d)
  181. {
  182. struct iodev_snapshot *old = (struct iodev_snapshot *)v1;
  183. struct iodev_snapshot *new = (struct iodev_snapshot *)v2;
  184. hrtime_t oldtime = new->is_crtime;
  185. double hr_etime;
  186. double reads, writes;
  187. if (new == NULL)
  188. return;
  189. if (old)
  190. oldtime = old->is_stats.wlastupdate;
  191. hr_etime = new->is_stats.wlastupdate - oldtime;
  192. if (hr_etime == 0.0)
  193. hr_etime = NANOSEC;
  194. reads = new->is_stats.reads - (old ? old->is_stats.reads : 0);
  195. writes = new->is_stats.writes - (old ? old->is_stats.writes : 0);
  196. adjprintf(" %*.0f", 2, (reads + writes) / hr_etime * NANOSEC);
  197. }
  198. static void
  199. dovmstats(struct snapshot *old, struct snapshot *new)
  200. {
  201. kstat_t *oldsys = NULL;
  202. kstat_t *newsys = &new->s_sys.ss_agg_sys;
  203. kstat_t *oldvm = NULL;
  204. kstat_t *newvm = &new->s_sys.ss_agg_vm;
  205. double percent_factor;
  206. ulong_t updates;
  207. int count;
  208. adj = 0;
  209. if (old) {
  210. oldsys = &old->s_sys.ss_agg_sys;
  211. oldvm = &old->s_sys.ss_agg_vm;
  212. }
  213. etime = cpu_ticks_delta(oldsys, newsys);
  214. percent_factor = 100.0 / denom(etime);
  215. /*
  216. * If any time has passed, convert etime to seconds per CPU
  217. */
  218. etime = etime >= 1.0 ? (etime / nr_active_cpus(new)) / hz : 1.0;
  219. updates = denom(DELTA(s_sys.ss_sysinfo.updates));
  220. if (--lines == 0)
  221. printhdr(0);
  222. adj = 0;
  223. if (pflag) {
  224. adjprintf(" %*u", 6,
  225. pgtok((int)(DELTA(s_sys.ss_vminfo.swap_avail) / updates)));
  226. adjprintf(" %*u", 5,
  227. pgtok((int)(DELTA(s_sys.ss_vminfo.freemem) / updates)));
  228. adjprintf(" %*.0f", 3, kstat_delta(oldvm, newvm, "pgrec")
  229. / etime);
  230. adjprintf(" %*.0f", 3, (kstat_delta(oldvm, newvm, "hat_fault") +
  231. kstat_delta(oldvm, newvm, "as_fault")) / etime);
  232. adjprintf(" %*.0f", 3, pgtok(kstat_delta(oldvm, newvm, "dfree"))
  233. / etime);
  234. adjprintf(" %*ld", 3, pgtok(new->s_sys.ss_deficit));
  235. adjprintf(" %*.0f", 3, kstat_delta(oldvm, newvm, "scan")
  236. / etime);
  237. adjprintf(" %*.0f", 4,
  238. pgtok(kstat_delta(oldvm, newvm, "execpgin")) / etime);
  239. adjprintf(" %*.0f", 4,
  240. pgtok(kstat_delta(oldvm, newvm, "execpgout")) / etime);
  241. adjprintf(" %*.0f", 4,
  242. pgtok(kstat_delta(oldvm, newvm, "execfree")) / etime);
  243. adjprintf(" %*.0f", 4,
  244. pgtok(kstat_delta(oldvm, newvm, "anonpgin")) / etime);
  245. adjprintf(" %*.0f", 4,
  246. pgtok(kstat_delta(oldvm, newvm, "anonpgout")) / etime);
  247. adjprintf(" %*.0f", 4,
  248. pgtok(kstat_delta(oldvm, newvm, "anonfree")) / etime);
  249. adjprintf(" %*.0f", 4,
  250. pgtok(kstat_delta(oldvm, newvm, "fspgin")) / etime);
  251. adjprintf(" %*.0f", 4,
  252. pgtok(kstat_delta(oldvm, newvm, "fspgout")) / etime);
  253. adjprintf(" %*.0f\n", 4,
  254. pgtok(kstat_delta(oldvm, newvm, "fsfree")) / etime);
  255. (void) fflush(stdout);
  256. return;
  257. }
  258. adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.runque) / updates);
  259. adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.waiting) / updates);
  260. adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.swpque) / updates);
  261. adjprintf(" %*u", 6, pgtok((int)(DELTA(s_sys.ss_vminfo.swap_avail)
  262. / updates)));
  263. adjprintf(" %*u", 5, pgtok((int)(DELTA(s_sys.ss_vminfo.freemem)
  264. / updates)));
  265. adjprintf(" %*.0f", 3, swflag?
  266. kstat_delta(oldvm, newvm, "swapin") / etime :
  267. kstat_delta(oldvm, newvm, "pgrec") / etime);
  268. adjprintf(" %*.0f", 3, swflag?
  269. kstat_delta(oldvm, newvm, "swapout") / etime :
  270. (kstat_delta(oldvm, newvm, "hat_fault")
  271. + kstat_delta(oldvm, newvm, "as_fault"))
  272. / etime);
  273. adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "pgpgin"))
  274. / etime);
  275. adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "pgpgout"))
  276. / etime);
  277. adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "dfree"))
  278. / etime);
  279. adjprintf(" %*ld", 2, pgtok(new->s_sys.ss_deficit));
  280. adjprintf(" %*.0f", 2, kstat_delta(oldvm, newvm, "scan") / etime);
  281. (void) snapshot_walk(SNAP_IODEVS, old, new, show_disk, NULL);
  282. count = df.if_max_iodevs - new->s_nr_iodevs;
  283. while (count-- > 0)
  284. adjprintf(" %*d", 2, 0);
  285. adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "intr") / etime);
  286. adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "syscall") / etime);
  287. adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "pswitch") / etime);
  288. adjprintf(" %*.0f", 2,
  289. kstat_delta(oldsys, newsys, "cpu_ticks_user") * percent_factor);
  290. adjprintf(" %*.0f", 2, kstat_delta(oldsys, newsys, "cpu_ticks_kernel")
  291. * percent_factor);
  292. adjprintf(" %*.0f\n", 2, (kstat_delta(oldsys, newsys, "cpu_ticks_idle")
  293. + kstat_delta(oldsys, newsys, "cpu_ticks_wait"))
  294. * percent_factor);
  295. (void) fflush(stdout);
  296. }
  297. /*ARGSUSED*/
  298. static void
  299. print_disk(void *v, void *v2, void *d)
  300. {
  301. struct iodev_snapshot *iodev = (struct iodev_snapshot *)v2;
  302. if (iodev == NULL)
  303. return;
  304. (void) printf("%c%c ", iodev->is_name[0], iodev->is_name[2]);
  305. }
  306. /* ARGSUSED */
  307. static void
  308. printhdr(int sig)
  309. {
  310. int i = df.if_max_iodevs - ss->s_nr_iodevs;
  311. if (sig == SIGCONT)
  312. caught_cont = 1;
  313. if (pflag) {
  314. (void) printf(" memory page ");
  315. (void) printf("executable anonymous filesystem \n");
  316. (void) printf(" swap free re mf fr de sr ");
  317. (void) printf("epi epo epf api apo apf fpi fpo fpf\n");
  318. lines = REPRINT;
  319. return;
  320. }
  321. (void) printf(" kthr memory page ");
  322. (void) printf("disk faults cpu\n");
  323. if (swflag)
  324. (void) printf(" r b w swap free si so pi po fr de sr ");
  325. else
  326. (void) printf(" r b w swap free re mf pi po fr de sr ");
  327. (void) snapshot_walk(SNAP_IODEVS, NULL, ss, print_disk, NULL);
  328. while (i-- > 0)
  329. (void) printf("-- ");
  330. (void) printf(" in sy cs us sy id\n");
  331. lines = REPRINT;
  332. }
  333. static void
  334. sum_out(char const *pretty, kstat_t *ks, char *name)
  335. {
  336. kstat_named_t *ksn = kstat_data_lookup(ks, name);
  337. if (ksn == NULL) {
  338. fail(0, "kstat_data_lookup('%s', '%s') failed",
  339. ks->ks_name, name);
  340. }
  341. (void) printf("%9llu %s\n", ksn->value.ui64, pretty);
  342. }
  343. static void
  344. dosum(struct sys_snapshot *ss)
  345. {
  346. uint64_t total_faults;
  347. kstat_named_t *ksn;
  348. long double nchtotal;
  349. uint64_t nchhits;
  350. sum_out("swap ins", &ss->ss_agg_vm, "swapin");
  351. sum_out("swap outs", &ss->ss_agg_vm, "swapout");
  352. sum_out("pages swapped in", &ss->ss_agg_vm, "pgswapin");
  353. sum_out("pages swapped out", &ss->ss_agg_vm, "pgswapout");
  354. ksn = kstat_data_lookup(&ss->ss_agg_vm, "hat_fault");
  355. if (ksn == NULL) {
  356. fail(0, "kstat_data_lookup('%s', 'hat_fault') failed",
  357. ss->ss_agg_vm.ks_name);
  358. }
  359. total_faults = ksn->value.ui64;
  360. ksn = kstat_data_lookup(&ss->ss_agg_vm, "as_fault");
  361. if (ksn == NULL) {
  362. fail(0, "kstat_data_lookup('%s', 'as_fault') failed",
  363. ss->ss_agg_vm.ks_name);
  364. }
  365. total_faults += ksn->value.ui64;
  366. (void) printf("%9llu total address trans. faults taken\n",
  367. total_faults);
  368. sum_out("page ins", &ss->ss_agg_vm, "pgin");
  369. sum_out("page outs", &ss->ss_agg_vm, "pgout");
  370. sum_out("pages paged in", &ss->ss_agg_vm, "pgpgin");
  371. sum_out("pages paged out", &ss->ss_agg_vm, "pgpgout");
  372. sum_out("total reclaims", &ss->ss_agg_vm, "pgrec");
  373. sum_out("reclaims from free list", &ss->ss_agg_vm, "pgfrec");
  374. sum_out("micro (hat) faults", &ss->ss_agg_vm, "hat_fault");
  375. sum_out("minor (as) faults", &ss->ss_agg_vm, "as_fault");
  376. sum_out("major faults", &ss->ss_agg_vm, "maj_fault");
  377. sum_out("copy-on-write faults", &ss->ss_agg_vm, "cow_fault");
  378. sum_out("zero fill page faults", &ss->ss_agg_vm, "zfod");
  379. sum_out("pages examined by the clock daemon", &ss->ss_agg_vm, "scan");
  380. sum_out("revolutions of the clock hand", &ss->ss_agg_vm, "rev");
  381. sum_out("pages freed by the clock daemon", &ss->ss_agg_vm, "dfree");
  382. sum_out("forks", &ss->ss_agg_sys, "sysfork");
  383. sum_out("vforks", &ss->ss_agg_sys, "sysvfork");
  384. sum_out("execs", &ss->ss_agg_sys, "sysexec");
  385. sum_out("cpu context switches", &ss->ss_agg_sys, "pswitch");
  386. sum_out("device interrupts", &ss->ss_agg_sys, "intr");
  387. sum_out("traps", &ss->ss_agg_sys, "trap");
  388. sum_out("system calls", &ss->ss_agg_sys, "syscall");
  389. nchtotal = (long double) ss->ss_nc.ncs_hits.value.ui64 +
  390. (long double) ss->ss_nc.ncs_misses.value.ui64;
  391. nchhits = ss->ss_nc.ncs_hits.value.ui64;
  392. (void) printf("%9.0Lf total name lookups (cache hits %.0Lf%%)\n",
  393. nchtotal, nchhits / denom(nchtotal) * 100);
  394. sum_out("user cpu", &ss->ss_agg_sys, "cpu_ticks_user");
  395. sum_out("system cpu", &ss->ss_agg_sys, "cpu_ticks_kernel");
  396. sum_out("idle cpu", &ss->ss_agg_sys, "cpu_ticks_idle");
  397. sum_out("wait cpu", &ss->ss_agg_sys, "cpu_ticks_wait");
  398. }
  399. static void
  400. dointr(struct snapshot *ss)
  401. {
  402. size_t i;
  403. ulong_t total = 0;
  404. (void) printf("interrupt total rate\n");
  405. (void) printf("--------------------------------\n");
  406. for (i = 0; i < ss->s_nr_intrs; i++) {
  407. (void) printf("%-12.8s %10lu %8.0f\n",
  408. ss->s_intrs[i].is_name, ss->s_intrs[i].is_total,
  409. ss->s_intrs[i].is_total / etime);
  410. total += ss->s_intrs[i].is_total;
  411. }
  412. (void) printf("--------------------------------\n");
  413. (void) printf("Total %10lu %8.0f\n", total, total / etime);
  414. }
  415. static void
  416. docachestats(kstat_ctl_t *kc, hrtime_t interval, int forever)
  417. {
  418. struct snapshot *old;
  419. struct snapshot *new;
  420. int i;
  421. hrtime_t start;
  422. start = gethrtime();
  423. old = acquire_snapshot(kc, SNAP_FLUSHES, NULL);
  424. if (iter == 0) {
  425. (void) printf("flush statistics: (totals)\n");
  426. (void) printf("%8s%8s%8s%8s%8s%8s\n",
  427. "usr", "ctx", "rgn", "seg", "pag", "par");
  428. (void) printf(" %7d %7d %7d %7d %7d %7d\n",
  429. old->s_flushes.f_usr, old->s_flushes.f_ctx,
  430. old->s_flushes.f_region, old->s_flushes.f_segment,
  431. old->s_flushes.f_page, old->s_flushes.f_partial);
  432. return;
  433. }
  434. (void) printf("flush statistics: (interval based)\n");
  435. for (i = 0; i < iter; i++) {
  436. if (i % REPRINT == 0)
  437. (void) printf("%8s%8s%8s%8s%8s%8s\n",
  438. "usr", "ctx", "rgn", "seg", "pag", "par");
  439. /* Have a kip */
  440. sleep_until(&start, interval, forever, &caught_cont);
  441. new = acquire_snapshot(kc, SNAP_FLUSHES, NULL);
  442. (void) printf(" %7d %7d %7d %7d %7d %7d\n",
  443. new->s_flushes.f_usr - old->s_flushes.f_usr,
  444. new->s_flushes.f_ctx - old->s_flushes.f_ctx,
  445. new->s_flushes.f_region - old->s_flushes.f_region,
  446. new->s_flushes.f_segment - old->s_flushes.f_segment,
  447. new->s_flushes.f_page - old->s_flushes.f_page,
  448. new->s_flushes.f_partial- old->s_flushes.f_partial);
  449. (void) fflush(stdout);
  450. free_snapshot(old);
  451. old = new;
  452. }
  453. }
  454. static void
  455. usage(void)
  456. {
  457. (void) fprintf(stderr,
  458. "Usage: vmstat [-cipqsS] [disk ...] [interval [count]]\n");
  459. exit(1);
  460. }