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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/sysinfo.h>
47 #include "statcommon.h"
49 #define SNAP(s, i, l, n) ((s) ? agg_proc_snap(s, i, l, n) : 0)
53 char *cmdname
= "mpstat";
56 static uint_t timestamp_fmt
= NODATE
;
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);
68 main(int argc
, char **argv
)
75 int infinite_cycles
= 0;
77 struct snapshot
*old
= NULL
;
78 struct snapshot
*new = NULL
;
79 enum snapshot_types types
= SNAP_CPUS
;
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 */
87 (void) textdomain(TEXT_DOMAIN
);
89 while ((c
= getopt(argc
, argv
, "apP:qT:")) != (int)EOF
)
93 * Display aggregate data for processor sets.
99 * Display all processor sets.
101 if (display_pset
!= -1)
107 * Display specific processor set.
111 display_pset
= (int)strtol
112 (optarg
, &endptr
, 10);
116 * Not valid to specify a negative processor
119 if (display_pset
< 0)
128 timestamp_fmt
= UDATE
;
129 else if (*optarg
== 'd')
130 timestamp_fmt
= DDATE
;
142 hz
= sysconf(_SC_CLK_TCK
);
145 interval
= (int)strtol(argv
[optind
], &endptr
, 10);
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)
161 if (display_agg
|| show_set
|| display_pset
!= -1)
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) {
175 new = acquire_snapshot(kc
, types
, NULL
);
178 snapshot_report_changes(old
, new);
180 /* if config changed, show stats from boot */
181 if (snapshot_has_changed(old
, new)) {
186 show_cpu_usage(old
, new, display_agg
);
188 if (!infinite_cycles
&& --iter
< 1)
192 sleep_until(&start_n
, period_n
, infinite_cycles
, &caught_cont
);
194 (void) kstat_close(kc
);
200 * Print an mpstat output header.
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");
209 (void) printf("CPU minf mjf xcal intr ithr csw icsw migr "
210 "smtx srw syscl usr sys wt idl");
212 (void) printf(" set");
218 print_cpu(struct cpu_snapshot
*c1
, struct cpu_snapshot
*c2
)
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
)
229 * the first mpstat output will have c1 = NULL, to give
234 old_sys
= &c1
->cs_sys
;
236 /* check there are stats to report */
241 /* check there are stats to report */
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 */
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 "
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
);
275 (void) printf(" %3d", c2
->cs_pset_id
);
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
;
293 pset_has_stats(struct pset_snapshot
*p
)
297 for (i
= 0; i
< p
->ps_nr_cpus
; i
++) {
298 if (CPU_ACTIVE(p
->ps_cpus
[i
]))
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
;
313 agg_vm(struct pset_snapshot
*p
, kstat_t
*ks
)
317 if (p
->ps_nr_cpus
== NULL
)
320 if (kstat_copy(&p
->ps_cpus
[0]->cs_vm
, ks
))
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");
333 agg_sys(struct pset_snapshot
*p
, kstat_t
*ks
)
337 if (p
->ps_nr_cpus
== NULL
)
340 if (kstat_copy(&p
->ps_cpus
[0]->cs_sys
, ks
))
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");
364 get_nr_ticks(struct pset_snapshot
*p1
, struct pset_snapshot
*p2
)
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
;
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
;
384 if (old
== NULL
&& new == NULL
)
392 return (cpu_ticks_delta(old
, new));
396 print_pset(struct pset_snapshot
*p1
, struct pset_snapshot
*p2
)
399 double etime
, percent
;
405 if (display_pset
!= -1 && display_pset
!= p2
->ps_id
)
408 if ((p1
&& !pset_has_stats(p1
)) || !pset_has_stats(p2
))
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
424 if (!agg_vm(p1
, &old_vm
) || !agg_sys(p1
, &old_sys
))
428 if (!agg_vm(p2
, &new_vm
) || !agg_sys(p2
, &new_sys
))
431 ticks
= get_nr_ticks(p1
, p2
);
433 etime
= (double)ticks
/ hz
;
434 if (etime
== 0.0) /* Prevent divide by zero errors */
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 "
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
,
462 free(old_vm
.ks_data
);
463 free(old_sys
.ks_data
);
464 free(new_vm
.ks_data
);
465 free(new_sys
.ks_data
);
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
;
483 * Report statistics for a sample interval.
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
--;
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.
518 (void) fprintf(stderr
,
519 "Usage: mpstat [-aq] [-p | -P processor_set] [-T d|u] "
520 "[interval [count]]\n");