Print this page
1100 cpustat usage message is incorrect
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cpc/common/cpustat.c
+++ new/usr/src/cmd/cpc/common/cpustat.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <sys/processor.h>
28 28 #include <sys/pset.h>
29 29 #include <sys/lwp.h>
30 30 #include <sys/priocntl.h>
31 31 #include <sys/fxpriocntl.h>
32 32 #include <time.h>
33 33 #include <stdio.h>
34 34 #include <stdlib.h>
35 35 #include <inttypes.h>
36 36 #include <unistd.h>
37 37 #include <limits.h>
38 38 #include <string.h>
39 39 #include <strings.h>
40 40 #include <thread.h>
41 41 #include <errno.h>
42 42 #include <libintl.h>
43 43 #include <locale.h>
44 44 #include <kstat.h>
45 45 #include <synch.h>
46 46 #include <libcpc.h>
47 47 #include <sys/resource.h>
48 48
49 49 #include "cpucmds.h"
50 50 #include "statcommon.h"
51 51
52 52 static struct options {
53 53 int debug;
54 54 int dotitle;
55 55 int dohelp;
56 56 int dotick;
57 57 int dosoaker;
58 58 int doperiod;
59 59 char *pgmname;
60 60 uint_t mseconds;
61 61 uint_t nsamples;
62 62 uint_t nsets;
63 63 uint_t mseconds_rest;
64 64 cpc_setgrp_t *master;
65 65 } __options;
66 66
67 67 /*
68 68 * States for soaker threads.
69 69 */
70 70 #define SOAK_PAUSE 0
71 71 #define SOAK_RUN 1
72 72
73 73 struct tstate {
74 74 processorid_t cpuid;
75 75 int chip_id;
76 76 cpc_setgrp_t *sgrp;
77 77 int status;
78 78 thread_t tid;
79 79 int soak_state;
80 80 mutex_t soak_lock;
81 81 cond_t soak_cv;
82 82 };
83 83
84 84 static const struct options *opts = (const struct options *)&__options;
85 85
86 86 static cpc_t *cpc;
87 87
88 88 struct tstate *gstate;
89 89 static int ncpus;
90 90 static int max_chip_id;
91 91 static int *chip_designees; /* cpuid of CPU which counts for phs chip */
92 92 static int smt = 0; /* If set, cpustat needs to be SMT-aware. */
93 93 static pcinfo_t fxinfo = { 0, "FX", NULL }; /* FX scheduler class info */
94 94
95 95 static uint_t timestamp_fmt = NODATE;
96 96
97 97 /*ARGSUSED*/
98 98 static void
99 99 cpustat_errfn(const char *fn, int subcode, const char *fmt, va_list ap)
100 100 {
101 101 (void) fprintf(stderr, "%s: ", opts->pgmname);
102 102 if (opts->debug)
103 103 (void) fprintf(stderr, "%s: ", fn);
104 104 (void) vfprintf(stderr, fmt, ap);
105 105 }
106 106
107 107 static int cpustat(void);
108 108 static int get_chipid(kstat_ctl_t *kc, processorid_t cpuid);
109 109 static void *soaker(void *arg);
110 110
111 111
112 112 #if !defined(TEXT_DOMAIN)
113 113 #define TEXT_DOMAIN "SYS_TEST"
114 114 #endif
115 115
116 116 int
117 117 main(int argc, char *argv[])
118 118 {
119 119 struct options *opts = &__options;
120 120 int c, errcnt = 0, ret;
121 121 cpc_setgrp_t *sgrp;
122 122 char *errstr;
123 123 double period;
124 124 char *endp;
125 125 struct rlimit rl;
126 126
127 127 (void) setlocale(LC_ALL, "");
128 128 (void) textdomain(TEXT_DOMAIN);
129 129
130 130 if ((opts->pgmname = strrchr(argv[0], '/')) == NULL)
131 131 opts->pgmname = argv[0];
132 132 else
133 133 opts->pgmname++;
134 134
135 135 /* Make sure we can open enough files */
136 136 rl.rlim_max = rl.rlim_cur = RLIM_INFINITY;
137 137 if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
138 138 errstr = strerror(errno);
139 139 (void) fprintf(stderr,
140 140 gettext("%s: setrlimit failed - %s\n"),
141 141 opts->pgmname, errstr);
142 142 }
143 143
144 144 if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
145 145 errstr = strerror(errno);
146 146 (void) fprintf(stderr, gettext("%s: cannot access performance "
147 147 "counters - %s\n"), opts->pgmname, errstr);
148 148 return (1);
149 149 }
150 150
151 151 (void) cpc_seterrhndlr(cpc, cpustat_errfn);
152 152 strtoset_errfn = cpustat_errfn;
153 153
154 154 /*
155 155 * Check to see if cpustat needs to be SMT-aware.
156 156 */
157 157 smt = smt_limited_cpc_hw(cpc);
158 158
159 159 /*
160 160 * Establish some defaults
161 161 */
162 162 opts->mseconds = 5000;
163 163 opts->nsamples = UINT_MAX;
164 164 opts->dotitle = 1;
165 165 if ((opts->master = cpc_setgrp_new(cpc, smt)) == NULL) {
166 166 (void) fprintf(stderr, gettext("%s: out of heap\n"),
167 167 opts->pgmname);
168 168 return (1);
169 169 }
170 170
171 171 while ((c = getopt(argc, argv, "Dc:hntT:sp:")) != EOF && errcnt == 0)
172 172 switch (c) {
173 173 case 'D': /* enable debugging */
174 174 opts->debug++;
175 175 break;
176 176 case 'c': /* specify statistics */
177 177 if ((sgrp = cpc_setgrp_newset(opts->master,
178 178 optarg, &errcnt)) != NULL)
179 179 opts->master = sgrp;
180 180 break;
181 181 case 'n': /* no titles */
182 182 opts->dotitle = 0;
183 183 break;
184 184 case 'p': /* periodic behavior */
185 185 opts->doperiod = 1;
186 186 period = strtod(optarg, &endp);
187 187 if (*endp != '\0') {
188 188 (void) fprintf(stderr, gettext("%s: invalid "
189 189 "parameter \"%s\"\n"), opts->pgmname,
190 190 optarg);
191 191 errcnt++;
192 192 }
193 193 break;
194 194 case 's': /* run soaker thread */
195 195 opts->dosoaker = 1;
196 196 break;
197 197 case 't': /* print %tick */
198 198 opts->dotick = 1;
199 199 break;
200 200 case 'T':
201 201 if (optarg) {
202 202 if (*optarg == 'u')
203 203 timestamp_fmt = UDATE;
204 204 else if (*optarg == 'd')
205 205 timestamp_fmt = DDATE;
206 206 else
207 207 errcnt++;
208 208 } else {
209 209 errcnt++;
210 210 }
211 211 break;
212 212 case 'h': /* help */
213 213 opts->dohelp = 1;
214 214 break;
215 215 case '?':
216 216 default:
217 217 errcnt++;
218 218 break;
219 219 }
220 220
221 221 switch (argc - optind) {
222 222 case 0:
223 223 break;
224 224 case 2:
225 225 opts->nsamples = strtol(argv[optind + 1], &endp, 10);
226 226 if (*endp != '\0') {
227 227 (void) fprintf(stderr,
228 228 gettext("%s: invalid argument \"%s\"\n"),
229 229 opts->pgmname, argv[optind + 1]);
230 230 errcnt++;
231 231 break;
232 232 }
233 233 /*FALLTHROUGH*/
234 234 case 1:
235 235 opts->mseconds = (uint_t)(strtod(argv[optind], &endp) * 1000.0);
236 236 if (*endp != '\0') {
237 237 (void) fprintf(stderr,
238 238 gettext("%s: invalid argument \"%s\"\n"),
239 239 opts->pgmname, argv[optind]);
240 240 errcnt++;
241 241 }
242 242 break;
243 243 default:
↓ open down ↓ |
243 lines elided |
↑ open up ↑ |
244 244 errcnt++;
245 245 break;
246 246 }
247 247
248 248 if (opts->nsamples == 0 || opts->mseconds == 0)
249 249 errcnt++;
250 250
251 251 if (errcnt != 0 || opts->dohelp ||
252 252 (opts->nsets = cpc_setgrp_numsets(opts->master)) == 0) {
253 253 (void) fprintf(opts->dohelp ? stdout : stderr, gettext(
254 - "Usage:\n\t%s [-c events] [-p period] [-nstD] "
255 - "[-T d|u] [interval [count]]\n\n"
256 - "\t-c events specify processor events to be monitored\n"
254 + "Usage:\n\t%s -c spec [-c spec]... [-p period] [-T u|d]\n"
255 + "\t\t[-sntD] [interval [count]]\n\n"
256 + "\t-c spec\t specify processor events to be monitored\n"
257 257 "\t-n\t suppress titles\n"
258 258 "\t-p period cycle through event list periodically\n"
259 259 "\t-s\t run user soaker thread for system-only events\n"
260 260 "\t-t\t include %s register\n"
261 261 "\t-T d|u\t Display a timestamp in date (d) or unix "
262 262 "time_t (u)\n"
263 263 "\t-D\t enable debug mode\n"
264 264 "\t-h\t print extended usage information\n\n"
265 265 "\tUse cputrack(1) to monitor per-process statistics.\n"),
266 266 opts->pgmname, CPC_TICKREG_NAME);
267 267 if (opts->dohelp) {
268 268 (void) putchar('\n');
269 269 (void) capabilities(cpc, stdout);
270 270 exit(0);
271 271 }
272 272 exit(2);
273 273 }
274 274
275 275 /*
276 276 * If the user requested periodic behavior, calculate the rest time
277 277 * between cycles.
278 278 */
279 279 if (opts->doperiod) {
280 280 opts->mseconds_rest = (uint_t)((period * 1000.0) -
281 281 (opts->mseconds * opts->nsets));
282 282 if ((int)opts->mseconds_rest < 0)
283 283 opts->mseconds_rest = 0;
284 284 if (opts->nsamples != UINT_MAX)
285 285 opts->nsamples *= opts->nsets;
286 286 }
287 287
288 288 cpc_setgrp_reset(opts->master);
289 289 (void) setvbuf(stdout, NULL, _IOLBF, 0);
290 290
291 291 /*
292 292 * If no system-mode only sets were created, no soaker threads will be
293 293 * needed.
294 294 */
295 295 if (opts->dosoaker == 1 && cpc_setgrp_has_sysonly(opts->master) == 0)
296 296 opts->dosoaker = 0;
297 297
298 298 ret = cpustat();
299 299
300 300 (void) cpc_close(cpc);
301 301
302 302 return (ret);
303 303 }
304 304
305 305 static void
306 306 print_title(cpc_setgrp_t *sgrp)
307 307 {
308 308 (void) printf("%7s %3s %5s ", "time", "cpu", "event");
309 309 if (opts->dotick)
310 310 (void) printf("%9s ", CPC_TICKREG_NAME);
311 311 (void) printf("%s\n", cpc_setgrp_gethdr(sgrp));
312 312 }
313 313
314 314 static void
315 315 print_sample(processorid_t cpuid, cpc_buf_t *buf, int nreq, const char *setname,
316 316 int sibling)
317 317 {
318 318 char line[1024];
319 319 int ccnt;
320 320 int i;
321 321 uint64_t val;
322 322 uint64_t tick;
323 323 hrtime_t hrtime;
324 324
325 325 hrtime = cpc_buf_hrtime(cpc, buf);
326 326 tick = cpc_buf_tick(cpc, buf);
327 327
328 328 ccnt = snprintf(line, sizeof (line), "%7.3f %3d %5s ",
329 329 mstimestamp(hrtime), (int)cpuid, "tick");
330 330 if (opts->dotick)
331 331 ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
332 332 "%9" PRId64 " ", tick);
333 333 for (i = 0; i < nreq; i++) {
334 334 (void) cpc_buf_get(cpc, buf, i, &val);
335 335 ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
336 336 "%9" PRId64 " ", val);
337 337 }
338 338 if (opts->nsets > 1)
339 339 ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
340 340 " # %s\n", setname);
341 341 else
342 342 ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, "\n");
343 343
344 344 if (sibling) {
345 345 /*
346 346 * This sample is being printed for a "sibling" CPU -- that is,
347 347 * a CPU which does not have its own CPC set bound. It is being
348 348 * measured via a set bound to another CPU sharing its physical
349 349 * processor.
350 350 */
351 351 int designee = chip_designees[gstate[cpuid].chip_id];
352 352 char *p;
353 353
354 354 if ((p = strrchr(line, '#')) == NULL)
355 355 p = strrchr(line, '\n');
356 356
357 357 if (p != NULL) {
358 358 *p = '\0';
359 359 ccnt = strlen(line);
360 360 ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
361 361 "# counter shared with CPU %d\n", designee);
362 362 }
363 363 }
364 364
365 365 if (timestamp_fmt != NODATE)
366 366 print_timestamp(timestamp_fmt);
367 367 if (ccnt > sizeof (line))
368 368 ccnt = sizeof (line);
369 369 if (ccnt > 0)
370 370 (void) write(1, line, ccnt);
371 371
372 372 /*
373 373 * If this CPU is the chip designee for any other CPUs, print a line for
374 374 * them here.
375 375 */
376 376 if (smt && (sibling == 0)) {
377 377 for (i = 0; i < ncpus; i++) {
378 378 if ((i != cpuid) && (gstate[i].cpuid != -1) &&
379 379 (chip_designees[gstate[i].chip_id] == cpuid))
380 380 print_sample(i, buf, nreq, setname, 1);
381 381 }
382 382 }
383 383 }
384 384
385 385 static void
386 386 print_total(int ncpus, cpc_buf_t *buf, int nreq, const char *setname)
387 387 {
388 388 int i;
389 389 uint64_t val;
390 390
391 391 (void) printf("%7.3f %3d %5s ", mstimestamp(cpc_buf_hrtime(cpc, buf)),
392 392 ncpus, "total");
393 393 if (opts->dotick)
394 394 (void) printf("%9" PRId64 " ", cpc_buf_tick(cpc, buf));
395 395 for (i = 0; i < nreq; i++) {
396 396 (void) cpc_buf_get(cpc, buf, i, &val);
397 397 (void) printf("%9" PRId64 " ", val);
398 398 }
399 399 if (opts->nsets > 1)
400 400 (void) printf(" # %s", setname);
401 401 (void) fputc('\n', stdout);
402 402 }
403 403
404 404 #define NSECS_PER_MSEC 1000000ll
405 405 #define NSECS_PER_SEC 1000000000ll
406 406
407 407 static void *
408 408 gtick(void *arg)
409 409 {
410 410 struct tstate *state = arg;
411 411 char *errstr;
412 412 uint_t nsamples;
413 413 uint_t sample_cnt = 1;
414 414 hrtime_t ht, htdelta, restdelta;
415 415 cpc_setgrp_t *sgrp = state->sgrp;
416 416 cpc_set_t *this = cpc_setgrp_getset(sgrp);
417 417 const char *name = cpc_setgrp_getname(sgrp);
418 418 cpc_buf_t **data1, **data2, **scratch;
419 419 cpc_buf_t *tmp;
420 420 int nreqs;
421 421 thread_t tid;
422 422
423 423 htdelta = NSECS_PER_MSEC * opts->mseconds;
424 424 restdelta = NSECS_PER_MSEC * opts->mseconds_rest;
425 425 ht = gethrtime();
426 426
427 427 /*
428 428 * If this CPU is SMT, we run one gtick() thread per _physical_ CPU,
429 429 * instead of per cpu_t. The following check returns if it detects that
430 430 * this cpu_t has not been designated to do the counting for this
431 431 * physical CPU.
432 432 */
433 433 if (smt && chip_designees[state->chip_id] != state->cpuid)
434 434 return (NULL);
435 435
436 436 /*
437 437 * If we need to run a soaker thread on this CPU, start it here.
438 438 */
439 439 if (opts->dosoaker) {
440 440 if (cond_init(&state->soak_cv, USYNC_THREAD, NULL) != 0)
441 441 goto bad;
442 442 if (mutex_init(&state->soak_lock, USYNC_THREAD,
443 443 NULL) != 0)
444 444 goto bad;
445 445 (void) mutex_lock(&state->soak_lock);
446 446 state->soak_state = SOAK_PAUSE;
447 447 if (thr_create(NULL, 0, soaker, state, NULL, &tid) != 0)
448 448 goto bad;
449 449
450 450 while (state->soak_state == SOAK_PAUSE)
451 451 (void) cond_wait(&state->soak_cv,
452 452 &state->soak_lock);
453 453 (void) mutex_unlock(&state->soak_lock);
454 454
455 455 /*
456 456 * If the soaker needs to pause for the first set, stop it now.
457 457 */
458 458 if (cpc_setgrp_sysonly(sgrp) == 0) {
459 459 (void) mutex_lock(&state->soak_lock);
460 460 state->soak_state = SOAK_PAUSE;
461 461 (void) mutex_unlock(&state->soak_lock);
462 462 }
463 463 }
464 464 if (cpc_bind_cpu(cpc, state->cpuid, this, 0) == -1)
465 465 goto bad;
466 466
467 467 for (nsamples = opts->nsamples; nsamples; nsamples--, sample_cnt++) {
468 468 hrtime_t htnow;
469 469 struct timespec ts;
470 470
471 471 nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch);
472 472
473 473 ht += htdelta;
474 474 htnow = gethrtime();
475 475 if (ht <= htnow)
476 476 continue;
477 477 ts.tv_sec = (time_t)((ht - htnow) / NSECS_PER_SEC);
478 478 ts.tv_nsec = (suseconds_t)((ht - htnow) % NSECS_PER_SEC);
479 479
480 480 (void) nanosleep(&ts, NULL);
481 481
482 482 if (opts->nsets == 1) {
483 483 /*
484 484 * If we're dealing with one set, buffer usage is:
485 485 *
486 486 * data1 = most recent data snapshot
487 487 * data2 = previous data snapshot
488 488 * scratch = used for diffing data1 and data2
489 489 *
490 490 * Save the snapshot from the previous sample in data2
491 491 * before putting the current sample in data1.
492 492 */
493 493 tmp = *data1;
494 494 *data1 = *data2;
495 495 *data2 = tmp;
496 496 if (cpc_set_sample(cpc, this, *data1) != 0)
497 497 goto bad;
498 498 cpc_buf_sub(cpc, *scratch, *data1, *data2);
499 499
500 500 print_sample(state->cpuid, *scratch, nreqs, name, 0);
501 501 } else {
502 502 /*
503 503 * More than one set is in use (multiple -c options
504 504 * given). Buffer usage in this case is:
505 505 *
506 506 * data1 = total counts for this set since program began
507 507 * data2 = unused
508 508 * scratch = most recent data snapshot
509 509 */
510 510 name = cpc_setgrp_getname(sgrp);
511 511 nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2,
512 512 &scratch);
513 513
514 514 if (cpc_set_sample(cpc, this, *scratch) != 0)
515 515 goto bad;
516 516
517 517 cpc_buf_add(cpc, *data1, *data1, *scratch);
518 518
519 519 if (cpc_unbind(cpc, this) != 0)
520 520 (void) fprintf(stderr, gettext("%s: error "
521 521 "unbinding on cpu %d - %s\n"),
522 522 opts->pgmname, state->cpuid,
523 523 strerror(errno));
524 524
525 525 this = cpc_setgrp_nextset(sgrp);
526 526
527 527 print_sample(state->cpuid, *scratch, nreqs, name, 0);
528 528
529 529 /*
530 530 * If periodic behavior was requested, rest here.
531 531 */
532 532 if (opts->doperiod && opts->mseconds_rest > 0 &&
533 533 (sample_cnt % opts->nsets) == 0) {
534 534 /*
535 535 * Stop the soaker while the tool rests.
536 536 */
537 537 if (opts->dosoaker) {
538 538 (void) mutex_lock(&state->soak_lock);
539 539 if (state->soak_state == SOAK_RUN)
540 540 state->soak_state = SOAK_PAUSE;
541 541 (void) mutex_unlock(&state->soak_lock);
542 542 }
543 543
544 544 htnow = gethrtime();
545 545 ht += restdelta;
546 546 ts.tv_sec = (time_t)((ht - htnow) /
547 547 NSECS_PER_SEC);
548 548 ts.tv_nsec = (suseconds_t)((ht - htnow) %
549 549 NSECS_PER_SEC);
550 550
551 551 (void) nanosleep(&ts, NULL);
552 552 }
553 553
554 554 /*
555 555 * Start or stop the soaker if needed.
556 556 */
557 557 if (opts->dosoaker) {
558 558 (void) mutex_lock(&state->soak_lock);
559 559 if (cpc_setgrp_sysonly(sgrp) &&
560 560 state->soak_state == SOAK_PAUSE) {
561 561 /*
562 562 * Soaker is paused but the next set is
563 563 * sysonly: start the soaker.
564 564 */
565 565 state->soak_state = SOAK_RUN;
566 566 (void) cond_signal(&state->soak_cv);
567 567 } else if (cpc_setgrp_sysonly(sgrp) == 0 &&
568 568 state->soak_state == SOAK_RUN)
569 569 /*
570 570 * Soaker is running but the next set
571 571 * counts user events: stop the soaker.
572 572 */
573 573 state->soak_state = SOAK_PAUSE;
574 574 (void) mutex_unlock(&state->soak_lock);
575 575 }
576 576
577 577 if (cpc_bind_cpu(cpc, state->cpuid, this, 0) != 0)
578 578 goto bad;
579 579 }
580 580 }
581 581
582 582 if (cpc_unbind(cpc, this) != 0)
583 583 (void) fprintf(stderr, gettext("%s: error unbinding on"
584 584 " cpu %d - %s\n"), opts->pgmname,
585 585 state->cpuid, strerror(errno));
586 586
587 587 /*
588 588 * We're done, so stop the soaker if needed.
589 589 */
590 590 if (opts->dosoaker) {
591 591 (void) mutex_lock(&state->soak_lock);
592 592 if (state->soak_state == SOAK_RUN)
593 593 state->soak_state = SOAK_PAUSE;
594 594 (void) mutex_unlock(&state->soak_lock);
595 595 }
596 596
597 597 return (NULL);
598 598 bad:
599 599 state->status = 3;
600 600 errstr = strerror(errno);
601 601 (void) fprintf(stderr, gettext("%s: cpu%d - %s\n"),
602 602 opts->pgmname, state->cpuid, errstr);
603 603 return (NULL);
604 604 }
605 605
606 606 static int
607 607 cpustat(void)
608 608 {
609 609 cpc_setgrp_t *accum;
610 610 cpc_set_t *start;
611 611 int c, i, retval;
612 612 int lwps = 0;
613 613 psetid_t mypset, cpupset;
614 614 char *errstr;
615 615 cpc_buf_t **data1, **data2, **scratch;
616 616 int nreqs;
617 617 kstat_ctl_t *kc;
618 618
619 619 ncpus = (int)sysconf(_SC_NPROCESSORS_CONF);
620 620 if ((gstate = calloc(ncpus, sizeof (*gstate))) == NULL) {
621 621 (void) fprintf(stderr, gettext(
622 622 "%s: out of heap\n"), opts->pgmname);
623 623 return (1);
624 624 }
625 625
626 626 max_chip_id = sysconf(_SC_CPUID_MAX);
627 627 if ((chip_designees = malloc(max_chip_id * sizeof (int))) == NULL) {
628 628 (void) fprintf(stderr, gettext(
629 629 "%s: out of heap\n"), opts->pgmname);
630 630 return (1);
631 631 }
632 632 for (i = 0; i < max_chip_id; i++)
633 633 chip_designees[i] = -1;
634 634
635 635 if (smt) {
636 636 if ((kc = kstat_open()) == NULL) {
637 637 (void) fprintf(stderr, gettext(
638 638 "%s: kstat_open() failed: %s\n"), opts->pgmname,
639 639 strerror(errno));
640 640 return (1);
641 641 }
642 642 }
643 643
644 644 if (opts->dosoaker)
645 645 if (priocntl(0, 0, PC_GETCID, &fxinfo) == -1) {
646 646 (void) fprintf(stderr, gettext(
647 647 "%s: couldn't get FX scheduler class: %s\n"),
648 648 opts->pgmname, strerror(errno));
649 649 return (1);
650 650 }
651 651
652 652 /*
653 653 * Only include processors that are participating in the system
654 654 */
655 655 for (c = 0, i = 0; i < ncpus; c++) {
656 656 switch (p_online(c, P_STATUS)) {
657 657 case P_ONLINE:
658 658 case P_NOINTR:
659 659 if (smt) {
660 660
661 661 gstate[i].chip_id = get_chipid(kc, c);
662 662 if (gstate[i].chip_id != -1 &&
663 663 chip_designees[gstate[i].chip_id] == -1)
664 664 chip_designees[gstate[i].chip_id] = c;
665 665 }
666 666
667 667 gstate[i++].cpuid = c;
668 668 break;
669 669 case P_OFFLINE:
670 670 case P_POWEROFF:
671 671 case P_FAULTED:
672 672 case P_SPARE:
673 673 gstate[i++].cpuid = -1;
674 674 break;
675 675 default:
676 676 gstate[i++].cpuid = -1;
677 677 (void) fprintf(stderr,
678 678 gettext("%s: cpu%d in unknown state\n"),
679 679 opts->pgmname, c);
680 680 break;
681 681 case -1:
682 682 break;
683 683 }
684 684 }
685 685
686 686 /*
687 687 * Examine the processor sets; if we're in one, only attempt
688 688 * to report on the set we're in.
689 689 */
690 690 if (pset_bind(PS_QUERY, P_PID, P_MYID, &mypset) == -1) {
691 691 errstr = strerror(errno);
692 692 (void) fprintf(stderr, gettext("%s: pset_bind - %s\n"),
693 693 opts->pgmname, errstr);
694 694 } else {
695 695 for (i = 0; i < ncpus; i++) {
696 696 struct tstate *this = &gstate[i];
697 697
698 698 if (this->cpuid == -1)
699 699 continue;
700 700
701 701 if (pset_assign(PS_QUERY,
702 702 this->cpuid, &cpupset) == -1) {
703 703 errstr = strerror(errno);
704 704 (void) fprintf(stderr,
705 705 gettext("%s: pset_assign - %s\n"),
706 706 opts->pgmname, errstr);
707 707 continue;
708 708 }
709 709
710 710 if (mypset != cpupset)
711 711 this->cpuid = -1;
712 712 }
713 713 }
714 714
715 715 if (opts->dotitle)
716 716 print_title(opts->master);
717 717 zerotime();
718 718
719 719 for (i = 0; i < ncpus; i++) {
720 720 struct tstate *this = &gstate[i];
721 721
722 722 if (this->cpuid == -1)
723 723 continue;
724 724 this->sgrp = cpc_setgrp_clone(opts->master);
725 725 if (this->sgrp == NULL) {
726 726 this->cpuid = -1;
727 727 continue;
728 728 }
729 729 if (thr_create(NULL, 0, gtick, this,
730 730 THR_BOUND|THR_NEW_LWP, &this->tid) == 0)
731 731 lwps++;
732 732 else {
733 733 (void) fprintf(stderr,
734 734 gettext("%s: cannot create thread for cpu%d\n"),
735 735 opts->pgmname, this->cpuid);
736 736 this->status = 4;
737 737 }
738 738 }
739 739
740 740 if (lwps != 0)
741 741 for (i = 0; i < ncpus; i++)
742 742 (void) thr_join(gstate[i].tid, NULL, NULL);
743 743
744 744 if ((accum = cpc_setgrp_clone(opts->master)) == NULL) {
745 745 (void) fprintf(stderr, gettext("%s: out of heap\n"),
746 746 opts->pgmname);
747 747 return (1);
748 748 }
749 749
750 750 retval = 0;
751 751 for (i = 0; i < ncpus; i++) {
752 752 struct tstate *this = &gstate[i];
753 753
754 754 if (this->cpuid == -1)
755 755 continue;
756 756 cpc_setgrp_accum(accum, this->sgrp);
757 757 cpc_setgrp_free(this->sgrp);
758 758 this->sgrp = NULL;
759 759 if (this->status != 0)
760 760 retval = 1;
761 761 }
762 762
763 763 cpc_setgrp_reset(accum);
764 764 start = cpc_setgrp_getset(accum);
765 765 do {
766 766 nreqs = cpc_setgrp_getbufs(accum, &data1, &data2, &scratch);
767 767 print_total(lwps, *data1, nreqs, cpc_setgrp_getname(accum));
768 768 } while (cpc_setgrp_nextset(accum) != start);
769 769
770 770 cpc_setgrp_free(accum);
771 771 accum = NULL;
772 772
773 773 free(gstate);
774 774 return (retval);
775 775 }
776 776
777 777 static int
778 778 get_chipid(kstat_ctl_t *kc, processorid_t cpuid)
779 779 {
780 780 kstat_t *ksp;
781 781 kstat_named_t *k;
782 782
783 783 if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL)
784 784 return (-1);
785 785
786 786 if (kstat_read(kc, ksp, NULL) == -1) {
787 787 (void) fprintf(stderr,
788 788 gettext("%s: kstat_read() failed for cpu %d: %s\n"),
789 789 opts->pgmname, cpuid, strerror(errno));
790 790 return (-1);
791 791 }
792 792
793 793 if ((k = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id")) == NULL) {
794 794 (void) fprintf(stderr,
795 795 gettext("%s: chip_id not found for cpu %d: %s\n"),
796 796 opts->pgmname, cpuid, strerror(errno));
797 797 return (-1);
798 798 }
799 799
800 800 return (k->value.i32);
801 801 }
802 802
803 803 static void *
804 804 soaker(void *arg)
805 805 {
806 806 struct tstate *state = arg;
807 807 pcparms_t pcparms;
808 808 fxparms_t *fx = (fxparms_t *)pcparms.pc_clparms;
809 809
810 810 if (processor_bind(P_LWPID, P_MYID, state->cpuid, NULL) != 0)
811 811 (void) fprintf(stderr, gettext("%s: couldn't bind soaker "
812 812 "thread to cpu%d: %s\n"), opts->pgmname, state->cpuid,
813 813 strerror(errno));
814 814
815 815 /*
816 816 * Put the soaker thread in the fixed priority (FX) class so it runs
817 817 * at the lowest possible global priority.
818 818 */
819 819 pcparms.pc_cid = fxinfo.pc_cid;
820 820 fx->fx_upri = 0;
821 821 fx->fx_uprilim = 0;
822 822 fx->fx_tqsecs = fx->fx_tqnsecs = FX_TQDEF;
823 823
824 824 if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, &pcparms) != 0)
825 825 (void) fprintf(stderr, gettext("%s: couldn't put soaker "
826 826 "thread in FX sched class: %s\n"), opts->pgmname,
827 827 strerror(errno));
828 828
829 829 /*
830 830 * Let the parent thread know we're ready to roll.
831 831 */
832 832 (void) mutex_lock(&state->soak_lock);
833 833 state->soak_state = SOAK_RUN;
834 834 (void) cond_signal(&state->soak_cv);
835 835 (void) mutex_unlock(&state->soak_lock);
836 836
837 837 for (;;) {
838 838 spin:
839 839 (void) mutex_lock(&state->soak_lock);
840 840 if (state->soak_state == SOAK_RUN) {
841 841 (void) mutex_unlock(&state->soak_lock);
842 842 goto spin;
843 843 }
844 844
845 845 while (state->soak_state == SOAK_PAUSE)
846 846 (void) cond_wait(&state->soak_cv,
847 847 &state->soak_lock);
848 848 (void) mutex_unlock(&state->soak_lock);
849 849 }
850 850
851 851 /*NOTREACHED*/
852 852 return (NULL);
853 853 }
↓ open down ↓ |
587 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX