8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / stat / mpstat / mpstat.c
blob64324224fd4927b36deb094ce72b1d5985efe6c0
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/pset.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <sys/sysinfo.h>
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <ctype.h>
36 #include <unistd.h>
37 #include <memory.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <kstat.h>
43 #include <poll.h>
44 #include <signal.h>
45 #include <locale.h>
47 #include "statcommon.h"
49 #define SNAP(s, i, l, n) ((s) ? agg_proc_snap(s, i, l, n) : 0)
51 #define REPRINT 20
53 char *cmdname = "mpstat";
54 int caught_cont = 0;
56 static uint_t timestamp_fmt = NODATE;
58 static int hz;
59 static int display_pset = -1;
60 static int show_set = 0;
61 static int suppress_state;
63 static void print_header(int, int);
64 static void show_cpu_usage(struct snapshot *, struct snapshot *, int);
65 static void usage(void);
67 int
68 main(int argc, char **argv)
70 int c;
71 int display_agg = 0;
72 int iter = 1;
73 int interval = 0;
74 char *endptr;
75 int infinite_cycles = 0;
76 kstat_ctl_t *kc;
77 struct snapshot *old = NULL;
78 struct snapshot *new = NULL;
79 enum snapshot_types types = SNAP_CPUS;
80 hrtime_t start_n;
81 hrtime_t period_n;
83 (void) setlocale(LC_ALL, "");
84 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
85 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
86 #endif
87 (void) textdomain(TEXT_DOMAIN);
89 while ((c = getopt(argc, argv, "apP:qT:")) != (int)EOF)
90 switch (c) {
91 case 'a':
93 * Display aggregate data for processor sets.
95 display_agg = 1;
96 break;
97 case 'p':
99 * Display all processor sets.
101 if (display_pset != -1)
102 usage();
103 show_set = 1;
104 break;
105 case 'P':
107 * Display specific processor set.
109 if (show_set == 1)
110 usage();
111 display_pset = (int)strtol
112 (optarg, &endptr, 10);
113 if (*endptr != NULL)
114 usage();
116 * Not valid to specify a negative processor
117 * set value.
119 if (display_pset < 0)
120 usage();
121 break;
122 case 'q':
123 suppress_state = 1;
124 break;
125 case 'T':
126 if (optarg) {
127 if (*optarg == 'u')
128 timestamp_fmt = UDATE;
129 else if (*optarg == 'd')
130 timestamp_fmt = DDATE;
131 else
132 usage();
133 } else {
134 usage();
136 break;
137 case '?':
138 usage();
139 break;
142 hz = sysconf(_SC_CLK_TCK);
144 if (argc > optind) {
145 interval = (int)strtol(argv[optind], &endptr, 10);
146 if (*endptr != NULL)
147 usage();
148 period_n = (hrtime_t)interval * NANOSEC;
149 if (argc > optind + 1) {
150 iter = (unsigned int)strtoul
151 (argv[optind + 1], &endptr, 10);
152 if (*endptr != NULL || iter < 0)
153 usage();
154 if (iter == 0)
155 return (0);
156 } else {
157 infinite_cycles = 1;
161 if (display_agg || show_set || display_pset != -1)
162 types |= SNAP_PSETS;
164 kc = open_kstat();
166 /* Set up handler for SIGCONT */
167 if (signal(SIGCONT, cont_handler) == SIG_ERR)
168 fail(1, "signal failed");
170 start_n = gethrtime();
172 while (infinite_cycles || iter > 0) {
173 free_snapshot(old);
174 old = new;
175 new = acquire_snapshot(kc, types, NULL);
177 if (!suppress_state)
178 snapshot_report_changes(old, new);
180 /* if config changed, show stats from boot */
181 if (snapshot_has_changed(old, new)) {
182 free_snapshot(old);
183 old = NULL;
186 show_cpu_usage(old, new, display_agg);
188 if (!infinite_cycles && --iter < 1)
189 break;
191 /* Have a kip */
192 sleep_until(&start_n, period_n, infinite_cycles, &caught_cont);
194 (void) kstat_close(kc);
196 return (0);
200 * Print an mpstat output header.
202 static void
203 print_header(int display_agg, int show_set)
205 if (display_agg == 1)
206 (void) printf("SET minf mjf xcal intr ithr csw icsw migr "
207 "smtx srw syscl usr sys wt idl sze");
208 else {
209 (void) printf("CPU minf mjf xcal intr ithr csw icsw migr "
210 "smtx srw syscl usr sys wt idl");
211 if (show_set == 1)
212 (void) printf(" set");
214 (void) printf("\n");
217 static void
218 print_cpu(struct cpu_snapshot *c1, struct cpu_snapshot *c2)
220 uint64_t ticks = 0;
221 double etime, percent;
222 kstat_t *old_vm = NULL;
223 kstat_t *old_sys = NULL;
225 if (display_pset != -1 && display_pset != c2->cs_pset_id)
226 return;
229 * the first mpstat output will have c1 = NULL, to give
230 * results since boot
232 if (c1) {
233 old_vm = &c1->cs_vm;
234 old_sys = &c1->cs_sys;
236 /* check there are stats to report */
237 if (!CPU_ACTIVE(c1))
238 return;
241 /* check there are stats to report */
242 if (!CPU_ACTIVE(c2))
243 return;
245 ticks = cpu_ticks_delta(old_sys, &c2->cs_sys);
247 etime = (double)ticks / hz;
248 if (etime == 0.0) /* Prevent divide by zero errors */
249 etime = 1.0;
250 percent = 100.0 / etime / hz;
252 (void) printf("%3d %4.0f %3.0f %4.0f %5.0f %4.0f "
253 "%4.0f %4.0f %4.0f %4.0f %4.0f %5.0f %3.0f %3.0f "
254 "%3.0f %3.0f",
255 c2->cs_id,
256 (kstat_delta(old_vm, &c2->cs_vm, "hat_fault") +
257 kstat_delta(old_vm, &c2->cs_vm, "as_fault")) / etime,
258 kstat_delta(old_vm, &c2->cs_vm, "maj_fault") / etime,
259 kstat_delta(old_sys, &c2->cs_sys, "xcalls") / etime,
260 kstat_delta(old_sys, &c2->cs_sys, "intr") / etime,
261 kstat_delta(old_sys, &c2->cs_sys, "intrthread") / etime,
262 kstat_delta(old_sys, &c2->cs_sys, "pswitch") / etime,
263 kstat_delta(old_sys, &c2->cs_sys, "inv_swtch") / etime,
264 kstat_delta(old_sys, &c2->cs_sys, "cpumigrate") / etime,
265 kstat_delta(old_sys, &c2->cs_sys, "mutex_adenters") / etime,
266 (kstat_delta(old_sys, &c2->cs_sys, "rw_rdfails") +
267 kstat_delta(old_sys, &c2->cs_sys, "rw_wrfails")) / etime,
268 kstat_delta(old_sys, &c2->cs_sys, "syscall") / etime,
269 kstat_delta(old_sys, &c2->cs_sys, "cpu_ticks_user") * percent,
270 kstat_delta(old_sys, &c2->cs_sys, "cpu_ticks_kernel") * percent,
271 kstat_delta(old_sys, &c2->cs_sys, "cpu_ticks_wait") * percent,
272 kstat_delta(old_sys, &c2->cs_sys, "cpu_ticks_idle") * percent);
274 if (show_set)
275 (void) printf(" %3d", c2->cs_pset_id);
276 (void) printf("\n");
279 /*ARGSUSED*/
280 static void
281 compare_cpu(void *v1, void *v2, void *data)
283 struct cpu_snapshot *c1 = (struct cpu_snapshot *)v1;
284 struct cpu_snapshot *c2 = (struct cpu_snapshot *)v2;
286 if (c2 == NULL)
287 return;
289 print_cpu(c1, c2);
292 static int
293 pset_has_stats(struct pset_snapshot *p)
295 int count = 0;
296 size_t i;
297 for (i = 0; i < p->ps_nr_cpus; i++) {
298 if (CPU_ACTIVE(p->ps_cpus[i]))
299 count++;
301 return (count);
304 static void
305 agg_stat(kstat_t *k1, kstat_t *k2, char *name)
307 kstat_named_t *ksn = kstat_data_lookup(k1, name);
308 kstat_named_t *ksn2 = kstat_data_lookup(k2, name);
309 ksn->value.ui64 += ksn2->value.ui64;
312 static kstat_t *
313 agg_vm(struct pset_snapshot *p, kstat_t *ks)
315 size_t i;
317 if (p->ps_nr_cpus == NULL)
318 return (NULL);
320 if (kstat_copy(&p->ps_cpus[0]->cs_vm, ks))
321 return (NULL);
323 for (i = 1; i < p->ps_nr_cpus; i++) {
324 agg_stat(ks, &p->ps_cpus[i]->cs_vm, "hat_fault");
325 agg_stat(ks, &p->ps_cpus[i]->cs_vm, "as_fault");
326 agg_stat(ks, &p->ps_cpus[i]->cs_vm, "maj_fault");
329 return (ks);
332 static kstat_t *
333 agg_sys(struct pset_snapshot *p, kstat_t *ks)
335 size_t i;
337 if (p->ps_nr_cpus == NULL)
338 return (NULL);
340 if (kstat_copy(&p->ps_cpus[0]->cs_sys, ks))
341 return (NULL);
343 for (i = 1; i < p->ps_nr_cpus; i++) {
344 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "xcalls");
345 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "intr");
346 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "intrthread");
347 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "pswitch");
348 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "inv_swtch");
349 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "cpumigrate");
350 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "mutex_adenters");
351 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "rw_rdfails");
352 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "rw_wrfails");
353 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "syscall");
354 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "cpu_ticks_user");
355 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "cpu_ticks_kernel");
356 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "cpu_ticks_wait");
357 agg_stat(ks, &p->ps_cpus[i]->cs_sys, "cpu_ticks_idle");
360 return (ks);
363 static uint64_t
364 get_nr_ticks(struct pset_snapshot *p1, struct pset_snapshot *p2)
366 kstat_t *old = NULL;
367 kstat_t *new = NULL;
368 size_t i = 0;
370 for (i = 0; p1 && i < p1->ps_nr_cpus; i++) {
371 if (p1->ps_cpus[i]->cs_sys.ks_data) {
372 old = &p1->ps_cpus[i]->cs_sys;
373 break;
377 for (i = 0; p2 && i < p2->ps_nr_cpus; i++) {
378 if (p2->ps_cpus[i]->cs_sys.ks_data) {
379 new = &p2->ps_cpus[i]->cs_sys;
380 break;
384 if (old == NULL && new == NULL)
385 return (0);
387 if (new == NULL) {
388 new = old;
389 old = NULL;
392 return (cpu_ticks_delta(old, new));
395 static void
396 print_pset(struct pset_snapshot *p1, struct pset_snapshot *p2)
398 uint64_t ticks = 0;
399 double etime, percent;
400 kstat_t old_vm;
401 kstat_t old_sys;
402 kstat_t new_vm;
403 kstat_t new_sys;
405 if (display_pset != -1 && display_pset != p2->ps_id)
406 return;
408 if ((p1 && !pset_has_stats(p1)) || !pset_has_stats(p2))
409 return;
411 old_vm.ks_data = old_sys.ks_data = NULL;
412 new_vm.ks_data = new_sys.ks_data = NULL;
415 * FIXME: these aggs will count "new" or disappeared cpus
416 * in a set, leaving an apparent huge change.
420 * the first mpstat output will have p1 = NULL, to give
421 * results since boot
423 if (p1) {
424 if (!agg_vm(p1, &old_vm) || !agg_sys(p1, &old_sys))
425 goto out;
428 if (!agg_vm(p2, &new_vm) || !agg_sys(p2, &new_sys))
429 goto out;
431 ticks = get_nr_ticks(p1, p2);
433 etime = (double)ticks / hz;
434 if (etime == 0.0) /* Prevent divide by zero errors */
435 etime = 1.0;
436 percent = 100.0 / p2->ps_nr_cpus / etime / hz;
438 (void) printf("%3d %4.0f %3.0f %4.0f %5.0f %4.0f "
439 "%4.0f %4.0f %4.0f %4.0f %4.0f %5.0f %3.0f %3.0f "
440 "%3.0f %3.0f %3d\n",
441 p2->ps_id,
442 (kstat_delta(&old_vm, &new_vm, "hat_fault") +
443 kstat_delta(&old_vm, &new_vm, "as_fault")) / etime,
444 kstat_delta(&old_vm, &new_vm, "maj_fault") / etime,
445 kstat_delta(&old_sys, &new_sys, "xcalls") / etime,
446 kstat_delta(&old_sys, &new_sys, "intr") / etime,
447 kstat_delta(&old_sys, &new_sys, "intrthread") / etime,
448 kstat_delta(&old_sys, &new_sys, "pswitch") / etime,
449 kstat_delta(&old_sys, &new_sys, "inv_swtch") / etime,
450 kstat_delta(&old_sys, &new_sys, "cpumigrate") / etime,
451 kstat_delta(&old_sys, &new_sys, "mutex_adenters") / etime,
452 (kstat_delta(&old_sys, &new_sys, "rw_rdfails") +
453 kstat_delta(&old_sys, &new_sys, "rw_wrfails")) / etime,
454 kstat_delta(&old_sys, &new_sys, "syscall") / etime,
455 kstat_delta(&old_sys, &new_sys, "cpu_ticks_user") * percent,
456 kstat_delta(&old_sys, &new_sys, "cpu_ticks_kernel") * percent,
457 kstat_delta(&old_sys, &new_sys, "cpu_ticks_wait") * percent,
458 kstat_delta(&old_sys, &new_sys, "cpu_ticks_idle") * percent,
459 p2->ps_nr_cpus);
461 out:
462 free(old_vm.ks_data);
463 free(old_sys.ks_data);
464 free(new_vm.ks_data);
465 free(new_sys.ks_data);
468 /*ARGSUSED*/
469 static void
470 compare_pset(void *v1, void *v2, void *data)
472 struct pset_snapshot *p1 = (struct pset_snapshot *)v1;
473 struct pset_snapshot *p2 = (struct pset_snapshot *)v2;
475 if (p2 == NULL)
476 return;
478 print_pset(p1, p2);
483 * Report statistics for a sample interval.
485 static void
486 show_cpu_usage(struct snapshot *old, struct snapshot *new, int display_agg)
488 static int lines_until_reprint = 0;
489 enum snapshot_types type = SNAP_CPUS;
490 snapshot_cb cb = compare_cpu;
492 if (timestamp_fmt != NODATE)
493 print_timestamp(timestamp_fmt);
495 if (lines_until_reprint == 0 || nr_active_cpus(new) > 1) {
496 print_header(display_agg, show_set);
497 lines_until_reprint = REPRINT;
500 lines_until_reprint--;
502 if (display_agg) {
503 type = SNAP_PSETS;
504 cb = compare_pset;
507 /* print stats since boot the first time round */
508 (void) snapshot_walk(type, old, new, cb, NULL);
509 (void) fflush(stdout);
513 * Usage message on error.
515 static void
516 usage(void)
518 (void) fprintf(stderr,
519 "Usage: mpstat [-aq] [-p | -P processor_set] [-T d|u] "
520 "[interval [count]]\n");
521 exit(1);