vmstat.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. /*-
  2. * SPDX-License-Identifier: BSD-3-Clause
  3. *
  4. * Copyright (c) 1980, 1986, 1991, 1993
  5. * The Regents of the University of California. All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the University nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. #include <sys/param.h>
  32. #include <sys/proc.h>
  33. #include <sys/uio.h>
  34. #include <sys/namei.h>
  35. #include <sys/malloc.h>
  36. #include <sys/signal.h>
  37. #include <sys/fcntl.h>
  38. #include <sys/ioctl.h>
  39. #include <sys/resource.h>
  40. #include <sys/sysctl.h>
  41. #include <sys/time.h>
  42. #include <sys/user.h>
  43. #define _WANT_VMMETER
  44. #include <sys/vmmeter.h>
  45. #include <sys/pcpu.h>
  46. #include <vm/vm_param.h>
  47. #include <ctype.h>
  48. #include <devstat.h>
  49. #include <err.h>
  50. #include <errno.h>
  51. #include <inttypes.h>
  52. #include <kvm.h>
  53. #include <limits.h>
  54. #include <memstat.h>
  55. #include <nlist.h>
  56. #include <paths.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <sysexits.h>
  61. #include <time.h>
  62. #include <unistd.h>
  63. #include <libutil.h>
  64. #include <libxo/xo.h>
  65. #define VMSTAT_XO_VERSION "1"
  66. static char da[] = "da";
  67. enum x_stats { X_SUM, X_HZ, X_STATHZ, X_NCHSTATS, X_INTRNAMES, X_SINTRNAMES,
  68. X_INTRCNT, X_SINTRCNT, X_NINTRCNT };
  69. static struct nlist namelist[] = {
  70. [X_SUM] = { .n_name = "_vm_cnt", },
  71. [X_HZ] = { .n_name = "_hz", },
  72. [X_STATHZ] = { .n_name = "_stathz", },
  73. [X_NCHSTATS] = { .n_name = "_nchstats", },
  74. [X_INTRNAMES] = { .n_name = "_intrnames", },
  75. [X_SINTRNAMES] = { .n_name = "_sintrnames", },
  76. [X_INTRCNT] = { .n_name = "_intrcnt", },
  77. [X_SINTRCNT] = { .n_name = "_sintrcnt", },
  78. [X_NINTRCNT] = { .n_name = "_nintrcnt", },
  79. { .n_name = NULL, },
  80. };
  81. static struct devstat_match *matches;
  82. static struct device_selection *dev_select;
  83. static struct statinfo cur, last;
  84. static devstat_select_mode select_mode;
  85. static size_t size_cp_times;
  86. static long *cur_cp_times, *last_cp_times;
  87. static long generation, select_generation;
  88. static int hz, hdrcnt, maxshowdevs;
  89. static int num_devices, num_devices_specified;
  90. static int num_matches, num_selected, num_selections;
  91. static char **specified_devices;
  92. static struct __vmmeter {
  93. uint64_t v_swtch;
  94. uint64_t v_trap;
  95. uint64_t v_syscall;
  96. uint64_t v_intr;
  97. uint64_t v_soft;
  98. uint64_t v_vm_faults;
  99. uint64_t v_io_faults;
  100. uint64_t v_cow_faults;
  101. uint64_t v_cow_optim;
  102. uint64_t v_zfod;
  103. uint64_t v_ozfod;
  104. uint64_t v_swapin;
  105. uint64_t v_swapout;
  106. uint64_t v_swappgsin;
  107. uint64_t v_swappgsout;
  108. uint64_t v_vnodein;
  109. uint64_t v_vnodeout;
  110. uint64_t v_vnodepgsin;
  111. uint64_t v_vnodepgsout;
  112. uint64_t v_intrans;
  113. uint64_t v_reactivated;
  114. uint64_t v_pdwakeups;
  115. uint64_t v_pdpages;
  116. uint64_t v_pdshortfalls;
  117. uint64_t v_dfree;
  118. uint64_t v_pfree;
  119. uint64_t v_tfree;
  120. uint64_t v_forks;
  121. uint64_t v_vforks;
  122. uint64_t v_rforks;
  123. uint64_t v_kthreads;
  124. uint64_t v_forkpages;
  125. uint64_t v_vforkpages;
  126. uint64_t v_rforkpages;
  127. uint64_t v_kthreadpages;
  128. u_int v_page_size;
  129. u_int v_page_count;
  130. u_int v_free_reserved;
  131. u_int v_free_target;
  132. u_int v_free_min;
  133. u_int v_free_count;
  134. u_int v_wire_count;
  135. u_long v_user_wire_count;
  136. u_int v_active_count;
  137. u_int v_inactive_target;
  138. u_int v_inactive_count;
  139. u_int v_laundry_count;
  140. u_int v_pageout_free_min;
  141. u_int v_interrupt_free_min;
  142. u_int v_free_severe;
  143. } sum, osum;
  144. #define VMSTAT_DEFAULT_LINES 20 /* Default number of `winlines'. */
  145. static volatile sig_atomic_t wresized; /* Tty resized when non-zero. */
  146. static int winlines = VMSTAT_DEFAULT_LINES; /* Current number of tty rows. */
  147. static int aflag;
  148. static int nflag;
  149. static int Pflag;
  150. static int hflag;
  151. static kvm_t *kd;
  152. #define FORKSTAT 0x01
  153. #define INTRSTAT 0x02
  154. #define MEMSTAT 0x04
  155. #define SUMSTAT 0x08
  156. #define TIMESTAT 0x10
  157. #define VMSTAT 0x20
  158. #define ZMEMSTAT 0x40
  159. #define OBJSTAT 0x80
  160. static void cpustats(void);
  161. static void pcpustats(u_long, int);
  162. static void devstats(void);
  163. static void doforkst(void);
  164. static void dointr(unsigned int, int);
  165. static void doobjstat(void);
  166. static void dosum(void);
  167. static void dovmstat(unsigned int, int);
  168. static void domemstat_malloc(void);
  169. static void domemstat_zone(void);
  170. static void kread(int, void *, size_t);
  171. static void kreado(int, void *, size_t, size_t);
  172. static void kreadptr(uintptr_t, void *, size_t);
  173. static void needhdr(int);
  174. static void needresize(int);
  175. static void doresize(void);
  176. static void printhdr(int, u_long);
  177. static void usage(void);
  178. static long pct(long, long);
  179. static long long getuptime(void);
  180. static char **getdrivedata(char **);
  181. int
  182. main(int argc, char *argv[])
  183. {
  184. char *bp, *buf, *memf, *nlistf;
  185. float f;
  186. int bufsize, c, reps, todo;
  187. size_t len;
  188. unsigned int interval;
  189. char errbuf[_POSIX2_LINE_MAX];
  190. memf = nlistf = NULL;
  191. interval = reps = todo = 0;
  192. maxshowdevs = 2;
  193. argc = xo_parse_args(argc, argv);
  194. if (argc < 0)
  195. return (argc);
  196. hflag = isatty(1);
  197. while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:oPp:sw:z")) != -1) {
  198. switch (c) {
  199. case 'a':
  200. aflag++;
  201. break;
  202. case 'c':
  203. reps = atoi(optarg);
  204. break;
  205. case 'P':
  206. Pflag++;
  207. break;
  208. case 'f':
  209. todo |= FORKSTAT;
  210. break;
  211. case 'h':
  212. hflag = 1;
  213. break;
  214. case 'H':
  215. hflag = 0;
  216. break;
  217. case 'i':
  218. todo |= INTRSTAT;
  219. break;
  220. case 'M':
  221. memf = optarg;
  222. break;
  223. case 'm':
  224. todo |= MEMSTAT;
  225. break;
  226. case 'N':
  227. nlistf = optarg;
  228. break;
  229. case 'n':
  230. nflag = 1;
  231. maxshowdevs = atoi(optarg);
  232. if (maxshowdevs < 0)
  233. xo_errx(1, "number of devices %d is < 0",
  234. maxshowdevs);
  235. break;
  236. case 'o':
  237. todo |= OBJSTAT;
  238. break;
  239. case 'p':
  240. if (devstat_buildmatch(optarg, &matches, &num_matches)
  241. != 0)
  242. xo_errx(1, "%s", devstat_errbuf);
  243. break;
  244. case 's':
  245. todo |= SUMSTAT;
  246. break;
  247. case 'w':
  248. /* Convert to milliseconds. */
  249. f = atof(optarg);
  250. interval = f * 1000;
  251. break;
  252. case 'z':
  253. todo |= ZMEMSTAT;
  254. break;
  255. case '?':
  256. default:
  257. usage();
  258. }
  259. }
  260. argc -= optind;
  261. argv += optind;
  262. xo_set_version(VMSTAT_XO_VERSION);
  263. if (!hflag)
  264. xo_set_options(NULL, "no-humanize");
  265. if (todo == 0)
  266. todo = VMSTAT;
  267. if (memf != NULL) {
  268. kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
  269. if (kd == NULL)
  270. xo_errx(1, "kvm_openfiles: %s", errbuf);
  271. }
  272. retry_nlist:
  273. if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) {
  274. if (c > 0) {
  275. bufsize = 0;
  276. len = 0;
  277. /*
  278. * 'cnt' was renamed to 'vm_cnt'. If 'vm_cnt' is not
  279. * found try looking up older 'cnt' symbol.
  280. * */
  281. if (namelist[X_SUM].n_type == 0 &&
  282. strcmp(namelist[X_SUM].n_name, "_vm_cnt") == 0) {
  283. namelist[X_SUM].n_name = "_cnt";
  284. goto retry_nlist;
  285. }
  286. /*
  287. * 'nintrcnt' doesn't exist in older kernels, but
  288. * that isn't fatal.
  289. */
  290. if (namelist[X_NINTRCNT].n_type == 0 && c == 1)
  291. goto nlist_ok;
  292. for (c = 0; c < (int)(nitems(namelist)); c++)
  293. if (namelist[c].n_type == 0)
  294. bufsize += strlen(namelist[c].n_name)
  295. + 1;
  296. bufsize += len + 1;
  297. buf = bp = alloca(bufsize);
  298. for (c = 0; c < (int)(nitems(namelist)); c++)
  299. if (namelist[c].n_type == 0) {
  300. xo_error(" %s",
  301. namelist[c].n_name);
  302. len = strlen(namelist[c].n_name);
  303. *bp++ = ' ';
  304. memcpy(bp, namelist[c].n_name, len);
  305. bp += len;
  306. }
  307. *bp = '\0';
  308. xo_error("undefined symbols:\n", buf);
  309. } else
  310. xo_warnx("kvm_nlist: %s", kvm_geterr(kd));
  311. xo_finish();
  312. exit(1);
  313. }
  314. nlist_ok:
  315. if (kd && Pflag)
  316. xo_errx(1, "Cannot use -P with crash dumps");
  317. if (todo & VMSTAT) {
  318. /*
  319. * Make sure that the userland devstat version matches the
  320. * kernel devstat version. If not, exit and print a
  321. * message informing the user of his mistake.
  322. */
  323. if (devstat_checkversion(NULL) < 0)
  324. xo_errx(1, "%s", devstat_errbuf);
  325. argv = getdrivedata(argv);
  326. }
  327. if (*argv) {
  328. f = atof(*argv);
  329. interval = f * 1000;
  330. if (*++argv)
  331. reps = atoi(*argv);
  332. }
  333. if (interval) {
  334. if (!reps)
  335. reps = -1;
  336. } else if (reps)
  337. interval = 1 * 1000;
  338. if (todo & FORKSTAT)
  339. doforkst();
  340. if (todo & MEMSTAT)
  341. domemstat_malloc();
  342. if (todo & ZMEMSTAT)
  343. domemstat_zone();
  344. if (todo & SUMSTAT)
  345. dosum();
  346. if (todo & OBJSTAT)
  347. doobjstat();
  348. if (todo & INTRSTAT)
  349. dointr(interval, reps);
  350. if (todo & VMSTAT)
  351. dovmstat(interval, reps);
  352. xo_finish();
  353. exit(0);
  354. }
  355. static int
  356. mysysctl(const char *name, void *oldp, size_t *oldlenp)
  357. {
  358. int error;
  359. error = sysctlbyname(name, oldp, oldlenp, NULL, 0);
  360. if (error != 0 && errno != ENOMEM)
  361. xo_err(1, "sysctl(%s)", name);
  362. return (error);
  363. }
  364. static char **
  365. getdrivedata(char **argv)
  366. {
  367. if ((num_devices = devstat_getnumdevs(NULL)) < 0)
  368. xo_errx(1, "%s", devstat_errbuf);
  369. cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
  370. last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
  371. if (devstat_getdevs(NULL, &cur) == -1)
  372. xo_errx(1, "%s", devstat_errbuf);
  373. num_devices = cur.dinfo->numdevs;
  374. generation = cur.dinfo->generation;
  375. specified_devices = malloc(sizeof(char *));
  376. for (num_devices_specified = 0; *argv; ++argv) {
  377. if (isdigit(**argv))
  378. break;
  379. num_devices_specified++;
  380. specified_devices = reallocf(specified_devices,
  381. sizeof(char *) * num_devices_specified);
  382. if (specified_devices == NULL) {
  383. xo_errx(1, "%s", "reallocf (specified_devices)");
  384. }
  385. specified_devices[num_devices_specified - 1] = *argv;
  386. }
  387. dev_select = NULL;
  388. if (nflag == 0 && maxshowdevs < num_devices_specified)
  389. maxshowdevs = num_devices_specified;
  390. /*
  391. * People are generally only interested in disk statistics when
  392. * they're running vmstat. So, that's what we're going to give
  393. * them if they don't specify anything by default. We'll also give
  394. * them any other random devices in the system so that we get to
  395. * maxshowdevs devices, if that many devices exist. If the user
  396. * specifies devices on the command line, either through a pattern
  397. * match or by naming them explicitly, we will give the user only
  398. * those devices.
  399. */
  400. if ((num_devices_specified == 0) && (num_matches == 0)) {
  401. if (devstat_buildmatch(da, &matches, &num_matches) != 0)
  402. xo_errx(1, "%s", devstat_errbuf);
  403. select_mode = DS_SELECT_ADD;
  404. } else
  405. select_mode = DS_SELECT_ONLY;
  406. /*
  407. * At this point, selectdevs will almost surely indicate that the
  408. * device list has changed, so we don't look for return values of 0
  409. * or 1. If we get back -1, though, there is an error.
  410. */
  411. if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
  412. &select_generation, generation, cur.dinfo->devices,
  413. num_devices, matches, num_matches, specified_devices,
  414. num_devices_specified, select_mode,
  415. maxshowdevs, 0) == -1)
  416. xo_errx(1, "%s", devstat_errbuf);
  417. return(argv);
  418. }
  419. /* Return system uptime in nanoseconds */
  420. static long long
  421. getuptime(void)
  422. {
  423. struct timespec sp;
  424. (void)clock_gettime(CLOCK_UPTIME, &sp);
  425. return((long long)sp.tv_sec * 1000000000LL + sp.tv_nsec);
  426. }
  427. static void
  428. fill_vmmeter(struct __vmmeter *vmmp)
  429. {
  430. struct vmmeter vm_cnt;
  431. size_t size;
  432. if (kd != NULL) {
  433. kread(X_SUM, &vm_cnt, sizeof(vm_cnt));
  434. #define GET_COUNTER(name) \
  435. vmmp->name = kvm_counter_u64_fetch(kd, (u_long)vm_cnt.name)
  436. GET_COUNTER(v_swtch);
  437. GET_COUNTER(v_trap);
  438. GET_COUNTER(v_syscall);
  439. GET_COUNTER(v_intr);
  440. GET_COUNTER(v_soft);
  441. GET_COUNTER(v_vm_faults);
  442. GET_COUNTER(v_io_faults);
  443. GET_COUNTER(v_cow_faults);
  444. GET_COUNTER(v_cow_optim);
  445. GET_COUNTER(v_zfod);
  446. GET_COUNTER(v_ozfod);
  447. GET_COUNTER(v_swapin);
  448. GET_COUNTER(v_swapout);
  449. GET_COUNTER(v_swappgsin);
  450. GET_COUNTER(v_swappgsout);
  451. GET_COUNTER(v_vnodein);
  452. GET_COUNTER(v_vnodeout);
  453. GET_COUNTER(v_vnodepgsin);
  454. GET_COUNTER(v_vnodepgsout);
  455. GET_COUNTER(v_intrans);
  456. GET_COUNTER(v_tfree);
  457. GET_COUNTER(v_forks);
  458. GET_COUNTER(v_vforks);
  459. GET_COUNTER(v_rforks);
  460. GET_COUNTER(v_kthreads);
  461. GET_COUNTER(v_forkpages);
  462. GET_COUNTER(v_vforkpages);
  463. GET_COUNTER(v_rforkpages);
  464. GET_COUNTER(v_kthreadpages);
  465. #undef GET_COUNTER
  466. } else {
  467. #define GET_VM_STATS(cat, name) do { \
  468. size = sizeof(vmmp->name); \
  469. mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size); \
  470. } while (0)
  471. /* sys */
  472. GET_VM_STATS(sys, v_swtch);
  473. GET_VM_STATS(sys, v_trap);
  474. GET_VM_STATS(sys, v_syscall);
  475. GET_VM_STATS(sys, v_intr);
  476. GET_VM_STATS(sys, v_soft);
  477. /* vm */
  478. GET_VM_STATS(vm, v_vm_faults);
  479. GET_VM_STATS(vm, v_io_faults);
  480. GET_VM_STATS(vm, v_cow_faults);
  481. GET_VM_STATS(vm, v_cow_optim);
  482. GET_VM_STATS(vm, v_zfod);
  483. GET_VM_STATS(vm, v_ozfod);
  484. GET_VM_STATS(vm, v_swapin);
  485. GET_VM_STATS(vm, v_swapout);
  486. GET_VM_STATS(vm, v_swappgsin);
  487. GET_VM_STATS(vm, v_swappgsout);
  488. GET_VM_STATS(vm, v_vnodein);
  489. GET_VM_STATS(vm, v_vnodeout);
  490. GET_VM_STATS(vm, v_vnodepgsin);
  491. GET_VM_STATS(vm, v_vnodepgsout);
  492. GET_VM_STATS(vm, v_intrans);
  493. GET_VM_STATS(vm, v_reactivated);
  494. GET_VM_STATS(vm, v_pdwakeups);
  495. GET_VM_STATS(vm, v_pdpages);
  496. GET_VM_STATS(vm, v_pdshortfalls);
  497. GET_VM_STATS(vm, v_dfree);
  498. GET_VM_STATS(vm, v_pfree);
  499. GET_VM_STATS(vm, v_tfree);
  500. GET_VM_STATS(vm, v_page_size);
  501. GET_VM_STATS(vm, v_page_count);
  502. GET_VM_STATS(vm, v_free_reserved);
  503. GET_VM_STATS(vm, v_free_target);
  504. GET_VM_STATS(vm, v_free_min);
  505. GET_VM_STATS(vm, v_free_count);
  506. GET_VM_STATS(vm, v_wire_count);
  507. GET_VM_STATS(vm, v_user_wire_count);
  508. GET_VM_STATS(vm, v_active_count);
  509. GET_VM_STATS(vm, v_inactive_target);
  510. GET_VM_STATS(vm, v_inactive_count);
  511. GET_VM_STATS(vm, v_laundry_count);
  512. GET_VM_STATS(vm, v_pageout_free_min);
  513. GET_VM_STATS(vm, v_interrupt_free_min);
  514. /*GET_VM_STATS(vm, v_free_severe);*/
  515. GET_VM_STATS(vm, v_forks);
  516. GET_VM_STATS(vm, v_vforks);
  517. GET_VM_STATS(vm, v_rforks);
  518. GET_VM_STATS(vm, v_kthreads);
  519. GET_VM_STATS(vm, v_forkpages);
  520. GET_VM_STATS(vm, v_vforkpages);
  521. GET_VM_STATS(vm, v_rforkpages);
  522. GET_VM_STATS(vm, v_kthreadpages);
  523. #undef GET_VM_STATS
  524. }
  525. }
  526. static void
  527. fill_vmtotal(struct vmtotal *vmtp)
  528. {
  529. size_t size;
  530. if (kd != NULL) {
  531. /* XXX fill vmtp */
  532. xo_errx(1, "not implemented");
  533. } else {
  534. size = sizeof(*vmtp);
  535. mysysctl("vm.vmtotal", vmtp, &size);
  536. if (size != sizeof(*vmtp))
  537. xo_errx(1, "vm.total size mismatch");
  538. }
  539. }
  540. /* Determine how many cpu columns, and what index they are in kern.cp_times */
  541. static void
  542. getcpuinfo(u_long *maskp, int *maxidp)
  543. {
  544. long *times;
  545. u_long mask;
  546. size_t size;
  547. int empty, i, j, maxcpu, maxid;
  548. if (kd != NULL)
  549. xo_errx(1, "not implemented");
  550. mask = 0;
  551. size = sizeof(maxcpu);
  552. mysysctl("kern.smp.maxcpus", &maxcpu, &size);
  553. if (size != sizeof(maxcpu))
  554. xo_errx(1, "sysctl kern.smp.maxcpus");
  555. size = sizeof(long) * maxcpu * CPUSTATES;
  556. times = malloc(size);
  557. if (times == NULL)
  558. xo_err(1, "malloc %zd bytes", size);
  559. mysysctl("kern.cp_times", times, &size);
  560. maxid = (size / CPUSTATES / sizeof(long)) - 1;
  561. for (i = 0; i <= maxid; i++) {
  562. empty = 1;
  563. for (j = 0; empty && j < CPUSTATES; j++) {
  564. if (times[i * CPUSTATES + j] != 0)
  565. empty = 0;
  566. }
  567. if (!empty)
  568. mask |= (1ul << i);
  569. }
  570. if (maskp)
  571. *maskp = mask;
  572. if (maxidp)
  573. *maxidp = maxid;
  574. }
  575. static void
  576. dovmstat(unsigned int interval, int reps)
  577. {
  578. struct clockinfo clockrate;
  579. struct vmtotal total;
  580. struct devinfo *tmp_dinfo;
  581. u_long cpumask;
  582. size_t size;
  583. time_t uptime, halfuptime;
  584. int maxid, rate_adj, retval;
  585. uptime = getuptime() / 1000000000LL;
  586. halfuptime = uptime / 2;
  587. rate_adj = 1;
  588. maxid = 0;
  589. cpumask = 0;
  590. /*
  591. * If the user stops the program (control-Z) and then resumes it,
  592. * print out the header again.
  593. */
  594. (void)signal(SIGCONT, needhdr);
  595. /*
  596. * If our standard output is a tty, then install a SIGWINCH handler
  597. * and set wresized so that our first iteration through the main
  598. * vmstat loop will peek at the terminal's current rows to find out
  599. * how many lines can fit in a screenful of output.
  600. */
  601. if (isatty(fileno(stdout)) != 0) {
  602. wresized = 1;
  603. (void)signal(SIGWINCH, needresize);
  604. } else {
  605. wresized = 0;
  606. winlines = VMSTAT_DEFAULT_LINES;
  607. }
  608. if (kd != NULL) {
  609. if (namelist[X_STATHZ].n_type != 0 &&
  610. namelist[X_STATHZ].n_value != 0)
  611. kread(X_STATHZ, &hz, sizeof(hz));
  612. if (!hz)
  613. kread(X_HZ, &hz, sizeof(hz));
  614. } else {
  615. size = sizeof(clockrate);
  616. mysysctl("kern.clockrate", &clockrate, &size);
  617. if (size != sizeof(clockrate))
  618. xo_errx(1, "clockrate size mismatch");
  619. hz = clockrate.hz;
  620. }
  621. if (Pflag) {
  622. getcpuinfo(&cpumask, &maxid);
  623. size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES;
  624. cur_cp_times = calloc(1, size_cp_times);
  625. last_cp_times = calloc(1, size_cp_times);
  626. }
  627. for (hdrcnt = 1;;) {
  628. if (!--hdrcnt)
  629. printhdr(maxid, cpumask);
  630. if (kd != NULL) {
  631. if (kvm_getcptime(kd, cur.cp_time) < 0)
  632. xo_errx(1, "kvm_getcptime: %s", kvm_geterr(kd));
  633. } else {
  634. size = sizeof(cur.cp_time);
  635. mysysctl("kern.cp_time", &cur.cp_time, &size);
  636. if (size != sizeof(cur.cp_time))
  637. xo_errx(1, "cp_time size mismatch");
  638. }
  639. if (Pflag) {
  640. size = size_cp_times;
  641. mysysctl("kern.cp_times", cur_cp_times, &size);
  642. if (size != size_cp_times)
  643. xo_errx(1, "cp_times mismatch");
  644. }
  645. tmp_dinfo = last.dinfo;
  646. last.dinfo = cur.dinfo;
  647. cur.dinfo = tmp_dinfo;
  648. last.snap_time = cur.snap_time;
  649. /*
  650. * Here what we want to do is refresh our device stats.
  651. * getdevs() returns 1 when the device list has changed.
  652. * If the device list has changed, we want to go through
  653. * the selection process again, in case a device that we
  654. * were previously displaying has gone away.
  655. */
  656. switch (devstat_getdevs(NULL, &cur)) {
  657. case -1:
  658. xo_errx(1, "%s", devstat_errbuf);
  659. break;
  660. case 1:
  661. num_devices = cur.dinfo->numdevs;
  662. generation = cur.dinfo->generation;
  663. retval = devstat_selectdevs(&dev_select, &num_selected,
  664. &num_selections, &select_generation,
  665. generation, cur.dinfo->devices,
  666. num_devices, matches, num_matches,
  667. specified_devices,
  668. num_devices_specified, select_mode,
  669. maxshowdevs, 0);
  670. switch (retval) {
  671. case -1:
  672. xo_errx(1, "%s", devstat_errbuf);
  673. break;
  674. case 1:
  675. printhdr(maxid, cpumask);
  676. break;
  677. default:
  678. break;
  679. }
  680. break;
  681. default:
  682. break;
  683. }
  684. fill_vmmeter(&sum);
  685. fill_vmtotal(&total);
  686. xo_open_container("processes");
  687. xo_emit("{:runnable/%2d} {:waiting/%2ld} "
  688. "{:swapped-out/%2ld}", total.t_rq - 1, total.t_dw +
  689. total.t_pw, total.t_sw);
  690. xo_close_container("processes");
  691. xo_open_container("memory");
  692. #define rate(x) (unsigned long)(((x) * rate_adj + halfuptime) / uptime)
  693. xo_emit(" {[:4}{h,hn-decimal:available-memory/%ju}{]:}",
  694. (uintmax_t)total.t_avm * sum.v_page_size);
  695. xo_emit(" {[:4}{h,hn-decimal:free-memory/%ju}{]:}",
  696. (uintmax_t)total.t_free * sum.v_page_size);
  697. xo_emit(" {[:4}{h,hn-decimal,hn-1000:total-page-faults/%lu}{]:} ",
  698. rate(sum.v_vm_faults - osum.v_vm_faults));
  699. xo_close_container("memory");
  700. xo_open_container("paging-rates");
  701. xo_emit("{:page-reactivated/%3lu} ",
  702. rate(sum.v_reactivated - osum.v_reactivated));
  703. xo_emit("{:paged-in/%3lu} ",
  704. rate(sum.v_swapin + sum.v_vnodein -
  705. (osum.v_swapin + osum.v_vnodein)));
  706. xo_emit("{:paged-out/%3lu}",
  707. rate(sum.v_swapout + sum.v_vnodeout -
  708. (osum.v_swapout + osum.v_vnodeout)));
  709. xo_emit(" {[:4}{h,hn-decimal,hn-1000:freed/%lu}{]:}",
  710. rate(sum.v_tfree - osum.v_tfree));
  711. xo_emit(" {[:4}{h,hn-decimal,hn-1000:scanned/%lu}{]:}",
  712. rate(sum.v_pdpages - osum.v_pdpages));
  713. xo_close_container("paging-rates");
  714. devstats();
  715. xo_open_container("fault-rates");
  716. xo_emit(" {[:4}{h,hn-decimal,hn-1000:interrupts/%lu}{]:}"
  717. " {[:4}{h,hn-decimal,hn-1000:system-calls/%lu}{]:}"
  718. " {[:4}{h,hn-decimal,hn-1000:context-switches/%lu}{]:}",
  719. rate(sum.v_intr - osum.v_intr),
  720. rate(sum.v_syscall - osum.v_syscall),
  721. rate(sum.v_swtch - osum.v_swtch));
  722. xo_close_container("fault-rates");
  723. if (Pflag)
  724. pcpustats(cpumask, maxid);
  725. else
  726. cpustats();
  727. xo_emit("\n");
  728. xo_flush();
  729. if (reps >= 0 && --reps <= 0)
  730. break;
  731. osum = sum;
  732. uptime = interval;
  733. rate_adj = 1000;
  734. /*
  735. * We round upward to avoid losing low-frequency events
  736. * (i.e., >= 1 per interval but < 1 per millisecond).
  737. */
  738. if (interval != 1)
  739. halfuptime = (uptime + 1) / 2;
  740. else
  741. halfuptime = 0;
  742. (void)usleep(interval * 1000);
  743. }
  744. }
  745. static void
  746. printhdr(int maxid, u_long cpumask)
  747. {
  748. int i, num_shown;
  749. num_shown = MIN(num_selected, maxshowdevs);
  750. xo_emit(" {T:procs} {T:memory} {T:/page%*s}", 19, "");
  751. if (num_shown > 1)
  752. xo_emit(" {T:/disks %*s} ", num_shown * 5 - 7, "");
  753. else if (num_shown == 1)
  754. xo_emit(" {T:disks} ");
  755. xo_emit(" {T:faults} ");
  756. if (Pflag) {
  757. for (i = 0; i <= maxid; i++) {
  758. if (cpumask & (1ul << i))
  759. xo_emit(" {T:/cpu%d} ", i);
  760. }
  761. xo_emit("\n");
  762. } else
  763. xo_emit(" {T:cpu}\n");
  764. xo_emit(" {T:r} {T:b} {T:w} {T:avm} {T:fre} {T:flt} {T:re}"
  765. " {T:pi} {T:po} {T:fr} {T:sr} ");
  766. for (i = 0; i < num_devices; i++)
  767. if ((dev_select[i].selected) &&
  768. (dev_select[i].selected <= maxshowdevs))
  769. xo_emit("{T:/%3.3s%d} ", dev_select[i].device_name,
  770. dev_select[i].unit_number);
  771. xo_emit(" {T:in} {T:sy} {T:cs}");
  772. if (Pflag) {
  773. for (i = 0; i <= maxid; i++) {
  774. if (cpumask & (1ul << i))
  775. xo_emit(" {T:us} {T:sy} {T:id}");
  776. }
  777. xo_emit("\n");
  778. } else
  779. xo_emit(" {T:us} {T:sy} {T:id}\n");
  780. if (wresized != 0)
  781. doresize();
  782. hdrcnt = winlines;
  783. }
  784. /*
  785. * Force a header to be prepended to the next output.
  786. */
  787. static void
  788. needhdr(int dummy __unused)
  789. {
  790. hdrcnt = 1;
  791. }
  792. /*
  793. * When the terminal is resized, force an update of the maximum number of rows
  794. * printed between each header repetition. Then force a new header to be
  795. * prepended to the next output.
  796. */
  797. void
  798. needresize(int signo __unused)
  799. {
  800. wresized = 1;
  801. hdrcnt = 1;
  802. }
  803. /*
  804. * Update the global `winlines' count of terminal rows.
  805. */
  806. void
  807. doresize(void)
  808. {
  809. struct winsize w;
  810. int status;
  811. for (;;) {
  812. status = ioctl(fileno(stdout), TIOCGWINSZ, &w);
  813. if (status == -1 && errno == EINTR)
  814. continue;
  815. else if (status == -1)
  816. xo_err(1, "ioctl");
  817. if (w.ws_row > 3)
  818. winlines = w.ws_row - 3;
  819. else
  820. winlines = VMSTAT_DEFAULT_LINES;
  821. break;
  822. }
  823. /*
  824. * Inhibit doresize() calls until we are rescheduled by SIGWINCH.
  825. */
  826. wresized = 0;
  827. }
  828. static long
  829. pct(long top, long bot)
  830. {
  831. long ans;
  832. if (bot == 0)
  833. return(0);
  834. ans = (quad_t)top * 100 / bot;
  835. return (ans);
  836. }
  837. #define PCT(top, bot) pct((long)(top), (long)(bot))
  838. static void
  839. dosum(void)
  840. {
  841. struct nchstats lnchstats;
  842. size_t size;
  843. long nchtotal;
  844. fill_vmmeter(&sum);
  845. xo_open_container("summary-statistics");
  846. xo_emit("{:context-switches/%9u} {N:cpu context switches}\n",
  847. sum.v_swtch);
  848. xo_emit("{:interrupts/%9u} {N:device interrupts}\n",
  849. sum.v_intr);
  850. xo_emit("{:software-interrupts/%9u} {N:software interrupts}\n",
  851. sum.v_soft);
  852. xo_emit("{:traps/%9u} {N:traps}\n", sum.v_trap);
  853. xo_emit("{:system-calls/%9u} {N:system calls}\n",
  854. sum.v_syscall);
  855. xo_emit("{:kernel-threads/%9u} {N:kernel threads created}\n",
  856. sum.v_kthreads);
  857. xo_emit("{:forks/%9u} {N: fork() calls}\n", sum.v_forks);
  858. xo_emit("{:vforks/%9u} {N:vfork() calls}\n",
  859. sum.v_vforks);
  860. xo_emit("{:rforks/%9u} {N:rfork() calls}\n",
  861. sum.v_rforks);
  862. xo_emit("{:swap-ins/%9u} {N:swap pager pageins}\n",
  863. sum.v_swapin);
  864. xo_emit("{:swap-in-pages/%9u} {N:swap pager pages paged in}\n",
  865. sum.v_swappgsin);
  866. xo_emit("{:swap-outs/%9u} {N:swap pager pageouts}\n",
  867. sum.v_swapout);
  868. xo_emit("{:swap-out-pages/%9u} {N:swap pager pages paged out}\n",
  869. sum.v_swappgsout);
  870. xo_emit("{:vnode-page-ins/%9u} {N:vnode pager pageins}\n",
  871. sum.v_vnodein);
  872. xo_emit("{:vnode-page-in-pages/%9u} {N:vnode pager pages paged in}\n",
  873. sum.v_vnodepgsin);
  874. xo_emit("{:vnode-page-outs/%9u} {N:vnode pager pageouts}\n",
  875. sum.v_vnodeout);
  876. xo_emit("{:vnode-page-out-pages/%9u} {N:vnode pager pages paged out}\n",
  877. sum.v_vnodepgsout);
  878. xo_emit("{:page-daemon-wakeups/%9u} {N:page daemon wakeups}\n",
  879. sum.v_pdwakeups);
  880. xo_emit("{:page-daemon-pages/%9u} {N:pages examined by the page "
  881. "daemon}\n", sum.v_pdpages);
  882. xo_emit("{:page-reclamation-shortfalls/%9u} {N:clean page reclamation "
  883. "shortfalls}\n", sum.v_pdshortfalls);
  884. xo_emit("{:reactivated/%9u} {N:pages reactivated by the page daemon}\n",
  885. sum.v_reactivated);
  886. xo_emit("{:copy-on-write-faults/%9u} {N:copy-on-write faults}\n",
  887. sum.v_cow_faults);
  888. xo_emit("{:copy-on-write-optimized-faults/%9u} {N:copy-on-write "
  889. "optimized faults}\n", sum.v_cow_optim);
  890. xo_emit("{:zero-fill-pages/%9u} {N:zero fill pages zeroed}\n",
  891. sum.v_zfod);
  892. xo_emit("{:zero-fill-prezeroed/%9u} {N:zero fill pages prezeroed}\n",
  893. sum.v_ozfod);
  894. xo_emit("{:intransit-blocking/%9u} {N:intransit blocking page faults}\n",
  895. sum.v_intrans);
  896. xo_emit("{:total-faults/%9u} {N:total VM faults taken}\n",
  897. sum.v_vm_faults);
  898. xo_emit("{:faults-requiring-io/%9u} {N:page faults requiring I\\/O}\n",
  899. sum.v_io_faults);
  900. xo_emit("{:faults-from-thread-creation/%9u} {N:pages affected by "
  901. "kernel thread creation}\n", sum.v_kthreadpages);
  902. xo_emit("{:faults-from-fork/%9u} {N:pages affected by fork}()\n",
  903. sum.v_forkpages);
  904. xo_emit("{:faults-from-vfork/%9u} {N:pages affected by vfork}()\n",
  905. sum.v_vforkpages);
  906. xo_emit("{:pages-rfork/%9u} {N:pages affected by rfork}()\n",
  907. sum.v_rforkpages);
  908. xo_emit("{:pages-freed/%9u} {N:pages freed}\n",
  909. sum.v_tfree);
  910. xo_emit("{:pages-freed-by-daemon/%9u} {N:pages freed by daemon}\n",
  911. sum.v_dfree);
  912. xo_emit("{:pages-freed-on-exit/%9u} {N:pages freed by exiting processes}\n",
  913. sum.v_pfree);
  914. xo_emit("{:active-pages/%9u} {N:pages active}\n",
  915. sum.v_active_count);
  916. xo_emit("{:inactive-pages/%9u} {N:pages inactive}\n",
  917. sum.v_inactive_count);
  918. xo_emit("{:laundry-pages/%9u} {N:pages in the laundry queue}\n",
  919. sum.v_laundry_count);
  920. xo_emit("{:wired-pages/%9u} {N:pages wired down}\n",
  921. sum.v_wire_count);
  922. xo_emit("{:virtual-user-wired-pages/%9lu} {N:virtual user pages wired "
  923. "down}\n", sum.v_user_wire_count);
  924. xo_emit("{:free-pages/%9u} {N:pages free}\n",
  925. sum.v_free_count);
  926. xo_emit("{:bytes-per-page/%9u} {N:bytes per page}\n", sum.v_page_size);
  927. if (kd != NULL) {
  928. kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats));
  929. } else {
  930. size = sizeof(lnchstats);
  931. mysysctl("vfs.cache.nchstats", &lnchstats, &size);
  932. if (size != sizeof(lnchstats))
  933. xo_errx(1, "vfs.cache.nchstats size mismatch");
  934. }
  935. nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits +
  936. lnchstats.ncs_badhits + lnchstats.ncs_falsehits +
  937. lnchstats.ncs_miss + lnchstats.ncs_long;
  938. xo_emit("{:total-name-lookups/%9ld} {N:total name lookups}\n",
  939. nchtotal);
  940. xo_emit("{P:/%9s} {N:cache hits} "
  941. "({:positive-cache-hits/%ld}% pos + "
  942. "{:negative-cache-hits/%ld}% {N:neg}) "
  943. "system {:cache-hit-percent/%ld}% per-directory\n",
  944. "", PCT(lnchstats.ncs_goodhits, nchtotal),
  945. PCT(lnchstats.ncs_neghits, nchtotal),
  946. PCT(lnchstats.ncs_pass2, nchtotal));
  947. xo_emit("{P:/%9s} {L:deletions} {:deletions/%ld}%, "
  948. "{L:falsehits} {:false-hits/%ld}%, "
  949. "{L:toolong} {:too-long/%ld}%\n", "",
  950. PCT(lnchstats.ncs_badhits, nchtotal),
  951. PCT(lnchstats.ncs_falsehits, nchtotal),
  952. PCT(lnchstats.ncs_long, nchtotal));
  953. xo_close_container("summary-statistics");
  954. }
  955. static void
  956. doforkst(void)
  957. {
  958. fill_vmmeter(&sum);
  959. xo_open_container("fork-statistics");
  960. xo_emit("{:fork/%u} {N:forks}, {:fork-pages/%u} {N:pages}, "
  961. "{L:average} {:fork-average/%.2f}\n",
  962. sum.v_forks, sum.v_forkpages,
  963. sum.v_forks == 0 ? 0.0 :
  964. (double)sum.v_forkpages / sum.v_forks);
  965. xo_emit("{:vfork/%u} {N:vforks}, {:vfork-pages/%u} {N:pages}, "
  966. "{L:average} {:vfork-average/%.2f}\n",
  967. sum.v_vforks, sum.v_vforkpages,
  968. sum.v_vforks == 0 ? 0.0 :
  969. (double)sum.v_vforkpages / sum.v_vforks);
  970. xo_emit("{:rfork/%u} {N:rforks}, {:rfork-pages/%u} {N:pages}, "
  971. "{L:average} {:rfork-average/%.2f}\n",
  972. sum.v_rforks, sum.v_rforkpages,
  973. sum.v_rforks == 0 ? 0.0 :
  974. (double)sum.v_rforkpages / sum.v_rforks);
  975. xo_close_container("fork-statistics");
  976. }
  977. static void
  978. devstats(void)
  979. {
  980. long double busy_seconds, transfers_per_second;
  981. long tmp;
  982. int di, dn, state;
  983. for (state = 0; state < CPUSTATES; ++state) {
  984. tmp = cur.cp_time[state];
  985. cur.cp_time[state] -= last.cp_time[state];
  986. last.cp_time[state] = tmp;
  987. }
  988. busy_seconds = cur.snap_time - last.snap_time;
  989. xo_open_list("device");
  990. for (dn = 0; dn < num_devices; dn++) {
  991. if (dev_select[dn].selected == 0 ||
  992. dev_select[dn].selected > maxshowdevs)
  993. continue;
  994. di = dev_select[dn].position;
  995. if (devstat_compute_statistics(&cur.dinfo->devices[di],
  996. &last.dinfo->devices[di], busy_seconds,
  997. DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
  998. DSM_NONE) != 0)
  999. xo_errx(1, "%s", devstat_errbuf);
  1000. xo_open_instance("device");
  1001. xo_emit("{ekq:name/%s%d}",
  1002. dev_select[dn].device_name,
  1003. dev_select[dn].unit_number);
  1004. xo_emit("{[:5}{h,hn-decimal,hn-1000:transfers/%ju}{]:}",
  1005. (uintmax_t)transfers_per_second);
  1006. xo_close_instance("device");
  1007. }
  1008. xo_close_list("device");
  1009. }
  1010. static void
  1011. percent(const char *name, long pctv, int *over)
  1012. {
  1013. char fmt[64];
  1014. snprintf(fmt, sizeof(fmt), " {:%s/%%%ulld/%%lld}", name,
  1015. (*over && pctv <= 9) ? 1 : 2);
  1016. xo_emit(fmt, pctv);
  1017. if (*over && pctv <= 9)
  1018. (*over)--;
  1019. else if (pctv >= 100)
  1020. (*over)++;
  1021. }
  1022. static void
  1023. cpustats(void)
  1024. {
  1025. long total;
  1026. int state, over;
  1027. total = 0;
  1028. for (state = 0; state < CPUSTATES; ++state)
  1029. total += cur.cp_time[state];
  1030. if (total == 0)
  1031. total = 1;
  1032. over = 0;
  1033. xo_open_container("cpu-statistics");
  1034. percent("user", 100LL * (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) /
  1035. total, &over);
  1036. percent("system", 100LL * (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) /
  1037. total, &over);
  1038. percent("idle", 100LL * cur.cp_time[CP_IDLE] / total, &over);
  1039. xo_close_container("cpu-statistics");
  1040. }
  1041. static void
  1042. pcpustats(u_long cpumask, int maxid)
  1043. {
  1044. long tmp, total;
  1045. int i, state, over;
  1046. /* devstats does this for cp_time */
  1047. for (i = 0; i <= maxid; i++) {
  1048. if ((cpumask & (1ul << i)) == 0)
  1049. continue;
  1050. for (state = 0; state < CPUSTATES; ++state) {
  1051. tmp = cur_cp_times[i * CPUSTATES + state];
  1052. cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i *
  1053. CPUSTATES + state];
  1054. last_cp_times[i * CPUSTATES + state] = tmp;
  1055. }
  1056. }
  1057. over = 0;
  1058. xo_open_list("cpu");
  1059. for (i = 0; i <= maxid; i++) {
  1060. if ((cpumask & (1ul << i)) == 0)
  1061. continue;
  1062. xo_open_instance("cpu");
  1063. xo_emit("{ke:name/%d}", i);
  1064. total = 0;
  1065. for (state = 0; state < CPUSTATES; ++state)
  1066. total += cur_cp_times[i * CPUSTATES + state];
  1067. if (total == 0)
  1068. total = 1;
  1069. percent("user",
  1070. 100LL * (cur_cp_times[i * CPUSTATES + CP_USER] +
  1071. cur_cp_times[i * CPUSTATES + CP_NICE]) / total, &over);
  1072. percent("system",
  1073. 100LL * (cur_cp_times[i * CPUSTATES + CP_SYS] +
  1074. cur_cp_times[i * CPUSTATES + CP_INTR]) / total, &over);
  1075. percent("idle",
  1076. 100LL * cur_cp_times[i * CPUSTATES + CP_IDLE] / total,
  1077. &over);
  1078. xo_close_instance("cpu");
  1079. }
  1080. xo_close_list("cpu");
  1081. }
  1082. static unsigned int
  1083. read_intrcnts(unsigned long **intrcnts)
  1084. {
  1085. size_t intrcntlen;
  1086. uintptr_t kaddr;
  1087. if (kd != NULL) {
  1088. kread(X_SINTRCNT, &intrcntlen, sizeof(intrcntlen));
  1089. if ((*intrcnts = malloc(intrcntlen)) == NULL)
  1090. err(1, "malloc()");
  1091. if (namelist[X_NINTRCNT].n_type == 0)
  1092. kread(X_INTRCNT, *intrcnts, intrcntlen);
  1093. else {
  1094. kread(X_INTRCNT, &kaddr, sizeof(kaddr));
  1095. kreadptr(kaddr, *intrcnts, intrcntlen);
  1096. }
  1097. } else {
  1098. for (*intrcnts = NULL, intrcntlen = 1024; ; intrcntlen *= 2) {
  1099. *intrcnts = reallocf(*intrcnts, intrcntlen);
  1100. if (*intrcnts == NULL)
  1101. err(1, "reallocf()");
  1102. if (mysysctl("hw.intrcnt", *intrcnts, &intrcntlen) == 0)
  1103. break;
  1104. }
  1105. }
  1106. return (intrcntlen / sizeof(unsigned long));
  1107. }
  1108. static void
  1109. print_intrcnts(unsigned long *intrcnts, unsigned long *old_intrcnts,
  1110. char *intrnames, unsigned int nintr, size_t istrnamlen, long long period_ms)
  1111. {
  1112. uint64_t inttotal, old_inttotal, total_count, total_rate;
  1113. unsigned long count, rate;
  1114. unsigned int i;
  1115. inttotal = 0;
  1116. old_inttotal = 0;
  1117. xo_open_list("interrupt");
  1118. for (i = 0; i < nintr; i++) {
  1119. if (intrnames[0] != '\0' && (*intrcnts != 0 || aflag)) {
  1120. count = *intrcnts - *old_intrcnts;
  1121. rate = ((uint64_t)count * 1000 + period_ms / 2) / period_ms;
  1122. xo_open_instance("interrupt");
  1123. xo_emit("{d:name/%-*s}{ket:name/%s} "
  1124. "{:total/%20lu} {:rate/%10lu}\n",
  1125. (int)istrnamlen, intrnames, intrnames, count, rate);
  1126. xo_close_instance("interrupt");
  1127. }
  1128. intrnames += strlen(intrnames) + 1;
  1129. inttotal += *intrcnts++;
  1130. old_inttotal += *old_intrcnts++;
  1131. }
  1132. total_count = inttotal - old_inttotal;
  1133. total_rate = (total_count * 1000 + period_ms / 2) / period_ms;
  1134. xo_close_list("interrupt");
  1135. xo_emit("{L:/%-*s} {:total-interrupts/%20ju} "
  1136. "{:total-rate/%10ju}\n", (int)istrnamlen,
  1137. "Total", (uintmax_t)total_count, (uintmax_t)total_rate);
  1138. }
  1139. static void
  1140. dointr(unsigned int interval, int reps)
  1141. {
  1142. unsigned long *intrcnts, *old_intrcnts;
  1143. char *intrname, *intrnames;
  1144. long long period_ms, old_uptime, uptime;
  1145. size_t clen, inamlen, istrnamlen;
  1146. uintptr_t kaddr;
  1147. unsigned int nintr;
  1148. old_intrcnts = NULL;
  1149. uptime = getuptime();
  1150. /* Get the names of each interrupt source */
  1151. if (kd != NULL) {
  1152. kread(X_SINTRNAMES, &inamlen, sizeof(inamlen));
  1153. if ((intrnames = malloc(inamlen)) == NULL)
  1154. xo_err(1, "malloc()");
  1155. if (namelist[X_NINTRCNT].n_type == 0)
  1156. kread(X_INTRNAMES, intrnames, inamlen);
  1157. else {
  1158. kread(X_INTRNAMES, &kaddr, sizeof(kaddr));
  1159. kreadptr(kaddr, intrnames, inamlen);
  1160. }
  1161. } else {
  1162. for (intrnames = NULL, inamlen = 1024; ; inamlen *= 2) {
  1163. if ((intrnames = reallocf(intrnames, inamlen)) == NULL)
  1164. xo_err(1, "reallocf()");
  1165. if (mysysctl("hw.intrnames", intrnames, &inamlen) == 0)
  1166. break;
  1167. }
  1168. }
  1169. /* Determine the length of the longest interrupt name */
  1170. intrname = intrnames;
  1171. istrnamlen = strlen("interrupt");
  1172. while (intrname < intrnames + inamlen) {
  1173. clen = strlen(intrname);
  1174. if (clen > istrnamlen)
  1175. istrnamlen = clen;
  1176. intrname += strlen(intrname) + 1;
  1177. }
  1178. xo_emit("{T:/%-*s} {T:/%20s} {T:/%10s}\n",
  1179. (int)istrnamlen, "interrupt", "total", "rate");
  1180. /*
  1181. * Loop reps times printing differential interrupt counts. If reps is
  1182. * zero, then run just once, printing total counts
  1183. */
  1184. xo_open_container("interrupt-statistics");
  1185. period_ms = uptime / 1000000;
  1186. while(1) {
  1187. nintr = read_intrcnts(&intrcnts);
  1188. /*
  1189. * Initialize old_intrcnts to 0 for the first pass, so
  1190. * print_intrcnts will print total interrupts since boot
  1191. */
  1192. if (old_intrcnts == NULL) {
  1193. old_intrcnts = calloc(nintr, sizeof(unsigned long));
  1194. if (old_intrcnts == NULL)
  1195. xo_err(1, "calloc()");
  1196. }
  1197. print_intrcnts(intrcnts, old_intrcnts, intrnames, nintr,
  1198. istrnamlen, period_ms);
  1199. xo_flush();
  1200. free(old_intrcnts);
  1201. old_intrcnts = intrcnts;
  1202. if (reps >= 0 && --reps <= 0)
  1203. break;
  1204. usleep(interval * 1000);
  1205. old_uptime = uptime;
  1206. uptime = getuptime();
  1207. period_ms = (uptime - old_uptime) / 1000000;
  1208. }
  1209. xo_close_container("interrupt-statistics");
  1210. }
  1211. static void
  1212. domemstat_malloc(void)
  1213. {
  1214. struct memory_type_list *mtlp;
  1215. struct memory_type *mtp;
  1216. size_t i, zones;
  1217. int error, first;
  1218. mtlp = memstat_mtl_alloc();
  1219. if (mtlp == NULL) {
  1220. xo_warn("memstat_mtl_alloc");
  1221. return;
  1222. }
  1223. if (kd == NULL) {
  1224. if (memstat_sysctl_malloc(mtlp, 0) < 0) {
  1225. xo_warnx("memstat_sysctl_malloc: %s",
  1226. memstat_strerror(memstat_mtl_geterror(mtlp)));
  1227. return;
  1228. }
  1229. } else {
  1230. if (memstat_kvm_malloc(mtlp, kd) < 0) {
  1231. error = memstat_mtl_geterror(mtlp);
  1232. if (error == MEMSTAT_ERROR_KVM)
  1233. xo_warnx("memstat_kvm_malloc: %s",
  1234. kvm_geterr(kd));
  1235. else
  1236. xo_warnx("memstat_kvm_malloc: %s",
  1237. memstat_strerror(error));
  1238. }
  1239. }
  1240. xo_open_container("malloc-statistics");
  1241. xo_emit("{T:/%16s} {T:/%4s} {T:/%5s} {T:/%3s} {T:Size(s)}\n",
  1242. "Type", "Use", "Memory", "Req");
  1243. xo_open_list("memory");
  1244. zones = memstat_malloc_zone_get_count();
  1245. for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
  1246. mtp = memstat_mtl_next(mtp)) {
  1247. if (memstat_get_numallocs(mtp) == 0 &&
  1248. memstat_get_count(mtp) == 0)
  1249. continue;
  1250. xo_open_instance("memory");
  1251. xo_emit("{k:type/%16s/%s} "
  1252. "{[:4}{h,hn-decimal,hn-1000:in-use/%ju}{]:} "
  1253. "{[:5}{h,hn-decimal:memory-use/%ju}{]:} "
  1254. "{[:4}{h,hn-decimal,hn-1000:requests/%ju}{]:} ",
  1255. memstat_get_name(mtp), (uintmax_t)memstat_get_count(mtp),
  1256. (uintmax_t)memstat_get_bytes(mtp),
  1257. (uintmax_t)memstat_get_numallocs(mtp));
  1258. first = 1;
  1259. xo_open_list("size");
  1260. for (i = 0; i < zones; i++) {
  1261. if (memstat_malloc_zone_used(mtp, i)) {
  1262. if (!first)
  1263. xo_emit(",");
  1264. xo_emit("{lh:size/%d}", memstat_malloc_zone_get_size(i));
  1265. first = 0;
  1266. }
  1267. }
  1268. xo_close_list("size");
  1269. xo_close_instance("memory");
  1270. xo_emit("\n");
  1271. }
  1272. xo_close_list("memory");
  1273. xo_close_container("malloc-statistics");
  1274. memstat_mtl_free(mtlp);
  1275. }
  1276. static void
  1277. domemstat_zone(void)
  1278. {
  1279. struct memory_type_list *mtlp;
  1280. struct memory_type *mtp;
  1281. int error, len;
  1282. mtlp = memstat_mtl_alloc();
  1283. if (mtlp == NULL) {
  1284. xo_warn("memstat_mtl_alloc");
  1285. return;
  1286. }
  1287. if (kd == NULL) {
  1288. if (memstat_sysctl_uma(mtlp, 0) < 0) {
  1289. xo_warnx("memstat_sysctl_uma: %s",
  1290. memstat_strerror(memstat_mtl_geterror(mtlp)));
  1291. return;
  1292. }
  1293. } else {
  1294. if (memstat_kvm_uma(mtlp, kd) < 0) {
  1295. error = memstat_mtl_geterror(mtlp);
  1296. if (error == MEMSTAT_ERROR_KVM)
  1297. xo_warnx("memstat_kvm_uma: %s",
  1298. kvm_geterr(kd));
  1299. else
  1300. xo_warnx("memstat_kvm_uma: %s",
  1301. memstat_strerror(error));
  1302. }
  1303. }
  1304. xo_open_container("memory-zone-statistics");
  1305. xo_emit("{T:/%-19s} {T:/%7s} {T:/%7s} {T:/%8s} {T:/%8s} {T:/%8s} "
  1306. "{T:/%4s} {T:/%4s} {T:/%4s}\n", "ITEM", "SIZE",
  1307. "LIMIT", "USED", "FREE", "REQ", "FAIL", "SLEEP", "XDOM");
  1308. xo_open_list("zone");
  1309. for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
  1310. mtp = memstat_mtl_next(mtp)) {
  1311. len = strlen(memstat_get_name(mtp));
  1312. xo_open_instance("zone");
  1313. xo_emit("{k:name/%s}:{d:size/%*ju}{e:size/%ju},"
  1314. "{:limit/%7ju},{:used/%8ju},"
  1315. "{:free/%8ju},{:requests/%8ju},"
  1316. "{:fail/%4ju},{:sleep/%4ju},{:xdomain/%4ju}\n",
  1317. memstat_get_name(mtp), MAX(1, 26 - len),
  1318. (uintmax_t)memstat_get_size(mtp),
  1319. (uintmax_t)memstat_get_size(mtp),
  1320. (uintmax_t)memstat_get_countlimit(mtp),
  1321. (uintmax_t)memstat_get_count(mtp),
  1322. (uintmax_t)memstat_get_free(mtp),
  1323. (uintmax_t)memstat_get_numallocs(mtp),
  1324. (uintmax_t)memstat_get_failures(mtp),
  1325. (uintmax_t)memstat_get_sleeps(mtp),
  1326. (uintmax_t)memstat_get_xdomain(mtp));
  1327. xo_close_instance("zone");
  1328. }
  1329. memstat_mtl_free(mtlp);
  1330. xo_close_list("zone");
  1331. xo_close_container("memory-zone-statistics");
  1332. }
  1333. static void
  1334. display_object(struct kinfo_vmobject *kvo)
  1335. {
  1336. const char *str;
  1337. xo_open_instance("object");
  1338. xo_emit("{:resident/%5ju} ", (uintmax_t)kvo->kvo_resident);
  1339. xo_emit("{:active/%5ju} ", (uintmax_t)kvo->kvo_active);
  1340. xo_emit("{:inactive/%5ju} ", (uintmax_t)kvo->kvo_inactive);
  1341. xo_emit("{:refcount/%3d} ", kvo->kvo_ref_count);
  1342. xo_emit("{:shadowcount/%3d} ", kvo->kvo_shadow_count);
  1343. #define MEMATTR_STR(type, val) \
  1344. if (kvo->kvo_memattr == (type)) { \
  1345. str = (val); \
  1346. } else
  1347. #ifdef VM_MEMATTR_UNCACHEABLE
  1348. MEMATTR_STR(VM_MEMATTR_UNCACHEABLE, "UC")
  1349. #endif
  1350. #ifdef VM_MEMATTR_WRITE_COMBINING
  1351. MEMATTR_STR(VM_MEMATTR_WRITE_COMBINING, "WC")
  1352. #endif
  1353. #ifdef VM_MEMATTR_WRITE_THROUGH
  1354. MEMATTR_STR(VM_MEMATTR_WRITE_THROUGH, "WT")
  1355. #endif
  1356. #ifdef VM_MEMATTR_WRITE_PROTECTED
  1357. MEMATTR_STR(VM_MEMATTR_WRITE_PROTECTED, "WP")
  1358. #endif
  1359. #ifdef VM_MEMATTR_WRITE_BACK
  1360. MEMATTR_STR(VM_MEMATTR_WRITE_BACK, "WB")
  1361. #endif
  1362. #ifdef VM_MEMATTR_WEAK_UNCACHEABLE
  1363. MEMATTR_STR(VM_MEMATTR_WEAK_UNCACHEABLE, "UC-")
  1364. #endif
  1365. #ifdef VM_MEMATTR_WB_WA
  1366. MEMATTR_STR(VM_MEMATTR_WB_WA, "WB")
  1367. #endif
  1368. #ifdef VM_MEMATTR_NOCACHE
  1369. MEMATTR_STR(VM_MEMATTR_NOCACHE, "NC")
  1370. #endif
  1371. #ifdef VM_MEMATTR_DEVICE
  1372. MEMATTR_STR(VM_MEMATTR_DEVICE, "DEV")
  1373. #endif
  1374. #ifdef VM_MEMATTR_DEVICE_NP
  1375. MEMATTR_STR(VM_MEMATTR_DEVICE, "NP")
  1376. #endif
  1377. #ifdef VM_MEMATTR_CACHEABLE
  1378. MEMATTR_STR(VM_MEMATTR_CACHEABLE, "C")
  1379. #endif
  1380. #ifdef VM_MEMATTR_PREFETCHABLE
  1381. MEMATTR_STR(VM_MEMATTR_PREFETCHABLE, "PRE")
  1382. #endif
  1383. {
  1384. str = "??";
  1385. }
  1386. #undef MEMATTR_STR
  1387. xo_emit("{:attribute/%-3s} ", str);
  1388. switch (kvo->kvo_type) {
  1389. case KVME_TYPE_NONE:
  1390. str = "--";
  1391. break;
  1392. case KVME_TYPE_DEFAULT:
  1393. str = "df";
  1394. break;
  1395. case KVME_TYPE_VNODE:
  1396. str = "vn";
  1397. break;
  1398. case KVME_TYPE_SWAP:
  1399. str = "sw";
  1400. break;
  1401. case KVME_TYPE_DEVICE:
  1402. str = "dv";
  1403. break;
  1404. case KVME_TYPE_PHYS:
  1405. str = "ph";
  1406. break;
  1407. case KVME_TYPE_DEAD:
  1408. str = "dd";
  1409. break;
  1410. case KVME_TYPE_SG:
  1411. str = "sg";
  1412. break;
  1413. case KVME_TYPE_MGTDEVICE:
  1414. str = "md";
  1415. break;
  1416. case KVME_TYPE_UNKNOWN:
  1417. default:
  1418. str = "??";
  1419. break;
  1420. }
  1421. xo_emit("{:type/%-2s} ", str);
  1422. xo_emit("{:path/%-s}\n", kvo->kvo_path);
  1423. xo_close_instance("object");
  1424. }
  1425. static void
  1426. doobjstat(void)
  1427. {
  1428. struct kinfo_vmobject *kvo;
  1429. int cnt, i;
  1430. kvo = kinfo_getvmobject(&cnt);
  1431. if (kvo == NULL) {
  1432. xo_warn("Failed to fetch VM object list");
  1433. return;
  1434. }
  1435. xo_emit("{T:RES/%5s} {T:ACT/%5s} {T:INACT/%5s} {T:REF/%3s} {T:SHD/%3s} "
  1436. "{T:CM/%3s} {T:TP/%2s} {T:PATH/%s}\n");
  1437. xo_open_list("object");
  1438. for (i = 0; i < cnt; i++)
  1439. display_object(&kvo[i]);
  1440. free(kvo);
  1441. xo_close_list("object");
  1442. }
  1443. /*
  1444. * kread reads something from the kernel, given its nlist index.
  1445. */
  1446. static void
  1447. kreado(int nlx, void *addr, size_t size, size_t offset)
  1448. {
  1449. const char *sym;
  1450. if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
  1451. sym = namelist[nlx].n_name;
  1452. if (*sym == '_')
  1453. ++sym;
  1454. xo_errx(1, "symbol %s not defined", sym);
  1455. }
  1456. if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr,
  1457. size) != size) {
  1458. sym = namelist[nlx].n_name;
  1459. if (*sym == '_')
  1460. ++sym;
  1461. xo_errx(1, "%s: %s", sym, kvm_geterr(kd));
  1462. }
  1463. }
  1464. static void
  1465. kread(int nlx, void *addr, size_t size)
  1466. {
  1467. kreado(nlx, addr, size, 0);
  1468. }
  1469. static void
  1470. kreadptr(uintptr_t addr, void *buf, size_t size)
  1471. {
  1472. if ((size_t)kvm_read(kd, addr, buf, size) != size)
  1473. xo_errx(1, "%s", kvm_geterr(kd));
  1474. }
  1475. static void __dead2
  1476. usage(void)
  1477. {
  1478. xo_error("%s%s",
  1479. "usage: vmstat [-afHhimoPsz] [-M core [-N system]] [-c count] [-n devs]\n",
  1480. " [-p type,if,pass] [-w wait] [disks] [wait [count]]\n");
  1481. xo_finish();
  1482. exit(1);
  1483. }