1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <libcpc.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <errno.h> 30 #include <strings.h> 31 #include <unistd.h> 32 #include <stropts.h> 33 #include <libintl.h> 34 #include <signal.h> 35 #include <sys/syscall.h> 36 #include <sys/types.h> 37 #include <sys/processor.h> 38 #include <sys/procset.h> 39 40 #include "libcpc_impl.h" 41 42 #define MASK32 0xFFFFFFFF 43 44 /* 45 * The library uses the cpc_lock field of the cpc_t struct to protect access to 46 * the linked lists inside the cpc_t, and only the linked lists. It is NOT used 47 * to protect against a user shooting his/herself in the foot (such as, for 48 * instance, destroying the same set at the same time from different threads.). 49 * 50 * SIGEMT needs to be blocked while holding the lock, to prevent deadlock among 51 * an app holding the lock and a signal handler attempting to sample or bind. 52 */ 53 54 static char *cpc_get_list(int which, int arg); 55 static void cpc_err(cpc_t *cpc, const char *fn, int subcode, ...); 56 static int cpc_set_valid(cpc_t *cpc, cpc_set_t *set); 57 static int cpc_lock(cpc_t *cpc); 58 static void cpc_unlock(cpc_t *cpc, int blocked); 59 static int cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev); 60 static int cpc_valid_attr(cpc_t *cpc, char *attr); 61 static void cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx); 62 63 cpc_t * 64 cpc_open(int ver) 65 { 66 cpc_t *cpc; 67 void (*sigsaved)(); 68 int error = 0; 69 int i; 70 int j; 71 72 if (ver != CPC_VER_CURRENT) { 73 /* 74 * v1 clients must stick to the v1 interface: cpc_version() 75 */ 76 errno = EINVAL; 77 return (NULL); 78 } 79 80 /* 81 * Call the syscall with invalid parameters. If we get ENOSYS this CPU 82 * has no CPC support. We need to block SIGSYS because the syscall code 83 * will send the signal if the system call fails to load. 84 */ 85 sigsaved = signal(SIGSYS, SIG_IGN); 86 if (syscall(SYS_cpc, -1, -1, -1, -1, -1) != -1) { 87 (void) signal(SIGSYS, sigsaved); 88 errno = EINVAL; 89 return (NULL); 90 } 91 error = errno; 92 (void) signal(SIGSYS, sigsaved); 93 94 if (error != EINVAL) { 95 errno = error; 96 return (NULL); 97 } 98 99 if ((cpc = malloc(sizeof (cpc_t))) == NULL) { 100 errno = ENOMEM; 101 return (NULL); 102 } 103 104 cpc->cpc_npic = syscall(SYS_cpc, CPC_NPIC, -1, 0, 0, 0); 105 cpc->cpc_caps = syscall(SYS_cpc, CPC_CAPS, -1, 0, 0, 0); 106 107 if (syscall(SYS_cpc, CPC_IMPL_NAME, -1, &cpc->cpc_cciname, 0, 0) != 0) 108 return (NULL); 109 if (syscall(SYS_cpc, CPC_CPUREF, -1, &cpc->cpc_cpuref, 0, 0) != 0) 110 return (NULL); 111 112 113 if ((cpc->cpc_attrlist = cpc_get_list(CPC_LIST_ATTRS, 0)) == NULL) { 114 free(cpc); 115 return (NULL); 116 } 117 118 if ((cpc->cpc_evlist = malloc(cpc->cpc_npic * sizeof (char *))) == 119 NULL) { 120 free(cpc->cpc_attrlist); 121 free(cpc); 122 return (NULL); 123 } 124 125 for (i = 0; i < cpc->cpc_npic; i++) { 126 if ((cpc->cpc_evlist[i] = cpc_get_list(CPC_LIST_EVENTS, i)) == 127 NULL) 128 break; 129 } 130 if (i != cpc->cpc_npic) { 131 for (j = 0; j < i; j++) 132 free(cpc->cpc_evlist[j]); 133 free(cpc->cpc_evlist); 134 free(cpc->cpc_attrlist); 135 free(cpc); 136 return (NULL); 137 } 138 139 cpc->cpc_sets = NULL; 140 cpc->cpc_bufs = NULL; 141 cpc->cpc_errfn = NULL; 142 (void) mutex_init(&cpc->cpc_lock, USYNC_THREAD, NULL); 143 __pctx_cpc_register_callback(cpc_invalidate_pctx); 144 145 return (cpc); 146 } 147 148 /* 149 * Ensure state is cleaned up: 150 * 151 * - Hardware is unbound 152 * - Sets are all destroyed 153 * - Bufs are all freed 154 */ 155 int 156 cpc_close(cpc_t *cpc) 157 { 158 while (cpc->cpc_sets != NULL) { 159 if (cpc->cpc_sets->cs_state != CS_UNBOUND) 160 (void) cpc_unbind(cpc, cpc->cpc_sets); 161 (void) cpc_set_destroy(cpc, cpc->cpc_sets); 162 } 163 164 while (cpc->cpc_bufs != NULL) 165 (void) cpc_buf_destroy(cpc, cpc->cpc_bufs); 166 167 free(cpc); 168 return (0); 169 } 170 171 cpc_set_t * 172 cpc_set_create(cpc_t *cpc) 173 { 174 cpc_set_t *set; 175 int sigblocked; 176 177 if ((set = malloc(sizeof (*set))) == NULL) { 178 errno = ENOMEM; 179 return (NULL); 180 } 181 182 set->cs_request = NULL; 183 set->cs_nreqs = 0; 184 set->cs_state = CS_UNBOUND; 185 set->cs_fd = -1; 186 set->cs_pctx = NULL; 187 set->cs_id = -1; 188 set->cs_thr = NULL; 189 190 sigblocked = cpc_lock(cpc); 191 set->cs_next = cpc->cpc_sets; 192 cpc->cpc_sets = set; 193 cpc_unlock(cpc, sigblocked); 194 195 return (set); 196 } 197 198 int 199 cpc_set_destroy(cpc_t *cpc, cpc_set_t *set) 200 { 201 cpc_set_t *csp, *prev; 202 cpc_request_t *req, *next; 203 int sigblocked; 204 205 /* 206 * Remove this set from the cpc handle's list of sets. 207 */ 208 sigblocked = cpc_lock(cpc); 209 for (csp = prev = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) { 210 if (csp == set) 211 break; 212 prev = csp; 213 } 214 if (csp == NULL) { 215 cpc_unlock(cpc, sigblocked); 216 errno = EINVAL; 217 return (-1); 218 } 219 if (csp == cpc->cpc_sets) 220 cpc->cpc_sets = csp->cs_next; 221 prev->cs_next = csp->cs_next; 222 cpc_unlock(cpc, sigblocked); 223 224 if (csp->cs_state != CS_UNBOUND) 225 (void) cpc_unbind(cpc, csp); 226 227 for (req = csp->cs_request; req != NULL; req = next) { 228 next = req->cr_next; 229 230 if (req->cr_nattrs != 0) 231 free(req->cr_attr); 232 233 free(req); 234 } 235 236 237 free(set); 238 239 return (0); 240 } 241 242 /*ARGSUSED*/ 243 int 244 cpc_set_add_request(cpc_t *cpc, cpc_set_t *set, const char *event, 245 uint64_t preset, uint_t flags, uint_t nattrs, const cpc_attr_t *attrs) 246 { 247 cpc_request_t *req; 248 const char *fn = "cpc_set_add_request"; 249 int i; 250 int npics = cpc_npic(cpc); 251 252 if (cpc_set_valid(cpc, set) != 0 || set->cs_state != CS_UNBOUND) { 253 errno = EINVAL; 254 return (-1); 255 } 256 257 for (i = 0; i < npics; i++) 258 if (cpc_valid_event(cpc, i, event)) 259 break; 260 if (i == npics) { 261 cpc_err(cpc, fn, CPC_INVALID_EVENT); 262 errno = EINVAL; 263 return (-1); 264 } 265 266 if ((req = malloc(sizeof (*req))) == NULL) { 267 errno = ENOMEM; 268 return (-1); 269 } 270 271 (void) strncpy(req->cr_event, event, CPC_MAX_EVENT_LEN); 272 req->cr_preset = preset; 273 req->cr_flags = flags; 274 req->cr_nattrs = nattrs; 275 req->cr_index = set->cs_nreqs; 276 req->cr_attr = NULL; 277 278 if (nattrs != 0) { 279 for (i = 0; i < nattrs; i++) { 280 /* 281 * Verify that each attribute name is legal and valid. 282 */ 283 if (attrs[i].ca_name[0] == '\0' || 284 cpc_valid_attr(cpc, attrs[i].ca_name) == 0) { 285 cpc_err(cpc, fn, CPC_INVALID_ATTRIBUTE); 286 goto inval; 287 } 288 289 /* 290 * If the user requested a specific picnum, ensure that 291 * the pic can count the requested event. 292 */ 293 if (strncmp("picnum", attrs[i].ca_name, 8) == 0) { 294 if (attrs[i].ca_val >= npics) { 295 cpc_err(cpc, fn, CPC_INVALID_PICNUM); 296 goto inval; 297 } 298 299 if (cpc_valid_event(cpc, attrs[i].ca_val, 300 req->cr_event) == 0) { 301 cpc_err(cpc, fn, CPC_PIC_NOT_CAPABLE); 302 goto inval; 303 } 304 } 305 } 306 307 if ((req->cr_attr = malloc(nattrs * sizeof (kcpc_attr_t))) 308 == NULL) { 309 free(req); 310 return (-1); 311 } 312 313 for (i = 0; i < nattrs; i++) { 314 req->cr_attr[i].ka_val = attrs[i].ca_val; 315 (void) strncpy(req->cr_attr[i].ka_name, 316 attrs[i].ca_name, CPC_MAX_ATTR_LEN); 317 } 318 } else 319 req->cr_attr = NULL; 320 321 req->cr_next = set->cs_request; 322 set->cs_request = req; 323 set->cs_nreqs++; 324 325 return (req->cr_index); 326 327 inval: 328 free(req); 329 errno = EINVAL; 330 return (-1); 331 } 332 333 cpc_buf_t * 334 cpc_buf_create(cpc_t *cpc, cpc_set_t *set) 335 { 336 cpc_buf_t *buf; 337 int sigblocked; 338 339 if (cpc_set_valid(cpc, set) != 0) { 340 errno = EINVAL; 341 return (NULL); 342 } 343 344 if ((buf = malloc(sizeof (*buf))) == NULL) 345 return (NULL); 346 347 buf->cb_size = set->cs_nreqs * sizeof (uint64_t); 348 if ((buf->cb_data = malloc(buf->cb_size)) == NULL) { 349 free(buf); 350 return (NULL); 351 } 352 353 bzero(buf->cb_data, buf->cb_size); 354 355 buf->cb_hrtime = 0; 356 buf->cb_tick = 0; 357 358 sigblocked = cpc_lock(cpc); 359 buf->cb_next = cpc->cpc_bufs; 360 cpc->cpc_bufs = buf; 361 cpc_unlock(cpc, sigblocked); 362 363 return (buf); 364 } 365 366 int 367 cpc_buf_destroy(cpc_t *cpc, cpc_buf_t *buf) 368 { 369 cpc_buf_t *cbp, *prev; 370 int sigblocked; 371 372 /* 373 * Remove this buf from the cpc handle's list of bufs. 374 */ 375 sigblocked = cpc_lock(cpc); 376 for (cbp = prev = cpc->cpc_bufs; cbp != NULL; cbp = cbp->cb_next) { 377 if (cbp == buf) 378 break; 379 prev = cbp; 380 } 381 if (cbp == NULL) { 382 cpc_unlock(cpc, sigblocked); 383 errno = EINVAL; 384 return (-1); 385 } 386 if (cbp == cpc->cpc_bufs) 387 cpc->cpc_bufs = cbp->cb_next; 388 prev->cb_next = cbp->cb_next; 389 390 cpc_unlock(cpc, sigblocked); 391 free(cbp->cb_data); 392 free(cbp); 393 394 return (0); 395 } 396 397 /*ARGSUSED*/ 398 int 399 cpc_bind_curlwp(cpc_t *cpc, cpc_set_t *set, uint_t flags) 400 { 401 char *packed_set; 402 size_t packsize; 403 int ret; 404 int subcode = -1; 405 406 /* 407 * We don't bother checking cpc_set_valid() here, because this is in the 408 * fast path of an app doing SIGEMT-based profiling as they restart the 409 * counters from their signal handler. 410 */ 411 if (CPC_SET_VALID_FLAGS(flags) == 0 || set->cs_nreqs <= 0) { 412 errno = EINVAL; 413 return (-1); 414 } 415 416 if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 417 errno = ENOMEM; 418 return (-1); 419 } 420 421 ret = syscall(SYS_cpc, CPC_BIND, -1, packed_set, packsize, &subcode); 422 free(packed_set); 423 424 if (ret != 0) { 425 if (subcode != -1) 426 cpc_err(cpc, "cpc_bind_curlwp", subcode); 427 return (-1); 428 } 429 430 set->cs_thr = thr_self(); 431 set->cs_state = CS_BOUND_CURLWP; 432 return (ret); 433 } 434 435 /*ARGSUSED*/ 436 int 437 cpc_bind_pctx(cpc_t *cpc, pctx_t *pctx, id_t id, cpc_set_t *set, uint_t flags) 438 { 439 char *packed_set; 440 size_t packsize; 441 int ret; 442 int subcode = -1; 443 444 /* 445 * cpc_bind_pctx() currently has no valid flags. 446 */ 447 if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 448 errno = EINVAL; 449 return (-1); 450 } 451 452 if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 453 errno = ENOMEM; 454 return (-1); 455 } 456 457 ret = __pctx_cpc(pctx, cpc, CPC_BIND, id, packed_set, (void *)packsize, 458 (void *)&subcode, -1); 459 460 free(packed_set); 461 462 if (ret == 0) { 463 set->cs_pctx = pctx; 464 set->cs_id = id; 465 set->cs_state = CS_BOUND_PCTX; 466 } else if (subcode != -1) 467 cpc_err(cpc, "cpc_bind_pctx", subcode); 468 469 return (ret); 470 } 471 472 /*ARGSUSED*/ 473 int 474 cpc_bind_cpu(cpc_t *cpc, processorid_t id, cpc_set_t *set, uint_t flags) 475 { 476 int fd; 477 char *packed_set; 478 size_t packsize; 479 __cpc_args_t cpc_args; 480 int error; 481 const char *fn = "cpc_bind_cpu"; 482 int subcode = -1; 483 484 /* 485 * cpc_bind_cpu() currently has no valid flags. 486 */ 487 if (flags != 0 || cpc_set_valid(cpc, set) != 0 || set->cs_nreqs <= 0) { 488 errno = EINVAL; 489 return (-1); 490 } 491 492 if (processor_bind(P_LWPID, P_MYID, id, &set->cs_obind) == -1) { 493 cpc_err(cpc, fn, CPC_PBIND_FAILED); 494 return (-1); 495 } 496 497 if ((fd = open(CPUDRV_SHARED, O_RDWR)) < 0) { 498 error = errno; 499 (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 500 errno = error; 501 return (-1); 502 } 503 504 /* 505 * To avoid leaking file descriptors, if we find an existing fd here we 506 * just close it. This is only a problem if a user attempts to bind the 507 * same set to different CPUs without first unbinding it. 508 */ 509 if (set->cs_fd != -1) 510 (void) close(set->cs_fd); 511 set->cs_fd = fd; 512 513 if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 514 (void) close(fd); 515 (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 516 errno = ENOMEM; 517 return (-1); 518 } 519 520 cpc_args.udata1 = packed_set; 521 cpc_args.udata2 = (void *)packsize; 522 cpc_args.udata3 = (void *)&subcode; 523 524 if (ioctl(fd, CPCIO_BIND, &cpc_args) != 0) { 525 error = errno; 526 free(packed_set); 527 (void) close(fd); 528 (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 529 if (subcode != -1) 530 cpc_err(cpc, fn, subcode); 531 errno = error; 532 return (-1); 533 } 534 535 free(packed_set); 536 537 set->cs_thr = thr_self(); 538 set->cs_state = CS_BOUND_CPU; 539 540 return (0); 541 } 542 543 /*ARGSUSED*/ 544 int 545 cpc_request_preset(cpc_t *cpc, int index, uint64_t preset) 546 { 547 return (syscall(SYS_cpc, CPC_PRESET, -1, index, 548 (uint32_t)(preset >> 32), (uint32_t)(preset & MASK32))); 549 } 550 551 /*ARGSUSED*/ 552 int 553 cpc_set_restart(cpc_t *cpc, cpc_set_t *set) 554 { 555 return (syscall(SYS_cpc, CPC_RESTART, -1, 0, 0, 0)); 556 } 557 558 /*ARGSUSED*/ 559 int 560 cpc_unbind(cpc_t *cpc, cpc_set_t *set) 561 { 562 int ret = 0; 563 int error; 564 565 if (cpc_set_valid(cpc, set) != 0) { 566 errno = EINVAL; 567 return (-1); 568 } 569 570 switch (set->cs_state) { 571 case CS_UNBOUND: 572 errno = EINVAL; 573 return (-1); 574 case CS_BOUND_CURLWP: 575 ret = syscall(SYS_cpc, CPC_RELE, -1, 0, 0, 0); 576 error = errno; 577 break; 578 case CS_BOUND_CPU: 579 ret = ioctl(set->cs_fd, CPCIO_RELE, NULL); 580 error = errno; 581 (void) close(set->cs_fd); 582 set->cs_fd = -1; 583 (void) processor_bind(P_LWPID, P_MYID, set->cs_obind, NULL); 584 break; 585 case CS_BOUND_PCTX: 586 if (set->cs_pctx != NULL) { 587 ret = __pctx_cpc(set->cs_pctx, cpc, CPC_RELE, 588 set->cs_id, 0, 0, 0, 0); 589 error = errno; 590 } 591 break; 592 } 593 594 set->cs_thr = NULL; 595 set->cs_id = -1; 596 set->cs_state = CS_UNBOUND; 597 if (ret != 0) 598 errno = error; 599 return (ret); 600 } 601 602 /*ARGSUSED*/ 603 int 604 cpc_set_sample(cpc_t *cpc, cpc_set_t *set, cpc_buf_t *buf) 605 { 606 __cpc_args_t args; 607 608 /* 609 * The following check ensures that only the most recently bound set 610 * can be sampled, as binding a set invalidates all other sets in the 611 * cpc_t. 612 */ 613 if (set->cs_state == CS_UNBOUND || 614 buf->cb_size != set->cs_nreqs * sizeof (uint64_t)) { 615 errno = EINVAL; 616 return (-1); 617 } 618 619 switch (set->cs_state) { 620 case CS_BOUND_CURLWP: 621 return (syscall(SYS_cpc, CPC_SAMPLE, -1, buf->cb_data, 622 &buf->cb_hrtime, &buf->cb_tick)); 623 case CS_BOUND_CPU: 624 args.udata1 = buf->cb_data; 625 args.udata2 = &buf->cb_hrtime; 626 args.udata3 = &buf->cb_tick; 627 return (ioctl(set->cs_fd, CPCIO_SAMPLE, &args)); 628 case CS_BOUND_PCTX: 629 return (__pctx_cpc(set->cs_pctx, cpc, CPC_SAMPLE, set->cs_id, 630 buf->cb_data, &buf->cb_hrtime, &buf->cb_tick, 631 buf->cb_size)); 632 } 633 634 errno = EINVAL; 635 return (-1); 636 } 637 638 /*ARGSUSED*/ 639 void 640 cpc_buf_sub(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 641 { 642 int i; 643 644 if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 645 return; 646 647 ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 648 a->cb_hrtime : b->cb_hrtime; 649 ds->cb_tick = a->cb_tick - b->cb_tick; 650 651 for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 652 ds->cb_data[i] = a->cb_data[i] - b->cb_data[i]; 653 } 654 655 /*ARGSUSED*/ 656 void 657 cpc_buf_add(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *a, cpc_buf_t *b) 658 { 659 int i; 660 661 if (a->cb_size != ds->cb_size || b->cb_size != ds->cb_size) 662 return; 663 664 ds->cb_hrtime = (a->cb_hrtime > b->cb_hrtime) ? 665 a->cb_hrtime : b->cb_hrtime; 666 ds->cb_tick = a->cb_tick + b->cb_tick; 667 668 for (i = 0; i < ds->cb_size / sizeof (uint64_t); i++) 669 ds->cb_data[i] = a->cb_data[i] + b->cb_data[i]; 670 } 671 672 /*ARGSUSED*/ 673 void 674 cpc_buf_copy(cpc_t *cpc, cpc_buf_t *ds, cpc_buf_t *src) 675 { 676 if (ds->cb_size != src->cb_size) 677 return; 678 679 bcopy(src->cb_data, ds->cb_data, ds->cb_size); 680 ds->cb_hrtime = src->cb_hrtime; 681 ds->cb_tick = src->cb_tick; 682 } 683 684 /*ARGSUSED*/ 685 void 686 cpc_buf_zero(cpc_t *cpc, cpc_buf_t *buf) 687 { 688 bzero(buf->cb_data, buf->cb_size); 689 buf->cb_hrtime = 0; 690 buf->cb_tick = 0; 691 } 692 693 /* 694 * Gets or sets the value of the request specified by index. 695 */ 696 /*ARGSUSED*/ 697 int 698 cpc_buf_get(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t *val) 699 { 700 *val = buf->cb_data[index]; 701 702 return (0); 703 } 704 705 /*ARGSUSED*/ 706 int 707 cpc_buf_set(cpc_t *cpc, cpc_buf_t *buf, int index, uint64_t val) 708 { 709 buf->cb_data[index] = val; 710 711 return (0); 712 } 713 714 /*ARGSUSED*/ 715 hrtime_t 716 cpc_buf_hrtime(cpc_t *cpc, cpc_buf_t *buf) 717 { 718 return (buf->cb_hrtime); 719 } 720 721 /*ARGSUSED*/ 722 uint64_t 723 cpc_buf_tick(cpc_t *cpc, cpc_buf_t *buf) 724 { 725 return (buf->cb_tick); 726 } 727 728 static char * 729 cpc_get_list(int which, int arg) 730 { 731 int szcmd; 732 int size; 733 char *list; 734 735 if (which == CPC_LIST_ATTRS) 736 szcmd = CPC_ATTRLIST_SIZE; 737 else 738 szcmd = CPC_EVLIST_SIZE; 739 740 if (syscall(SYS_cpc, szcmd, -1, &size, arg, 0) != 0) 741 return (NULL); 742 743 if ((list = malloc(size)) == NULL) 744 return (NULL); 745 746 if (syscall(SYS_cpc, which, -1, list, arg, 0) != 0) { 747 free(list); 748 return (NULL); 749 } 750 751 return (list); 752 } 753 754 /*ARGSUSED*/ 755 void 756 cpc_walk_requests(cpc_t *cpc, cpc_set_t *set, void *arg, 757 void (*action)(void *arg, int index, const char *event, uint64_t preset, 758 uint_t flags, int nattrs, const cpc_attr_t *attrs)) 759 { 760 cpc_request_t *rp; 761 cpc_attr_t *attrs = NULL; 762 int i; 763 764 for (rp = set->cs_request; rp != NULL; rp = rp->cr_next) { 765 /* 766 * Need to reconstruct a temporary cpc_attr_t array for req. 767 */ 768 if (rp->cr_nattrs != 0) 769 if ((attrs = malloc(rp->cr_nattrs * 770 sizeof (cpc_attr_t))) == NULL) 771 return; 772 for (i = 0; i < rp->cr_nattrs; i++) { 773 attrs[i].ca_name = rp->cr_attr[i].ka_name; 774 attrs[i].ca_val = rp->cr_attr[i].ka_val; 775 } 776 777 action(arg, rp->cr_index, rp->cr_event, rp->cr_preset, 778 rp->cr_flags, rp->cr_nattrs, attrs); 779 780 if (rp->cr_nattrs != 0) 781 free(attrs); 782 } 783 } 784 785 /*ARGSUSED*/ 786 void 787 cpc_walk_events_all(cpc_t *cpc, void *arg, 788 void (*action)(void *arg, const char *event)) 789 { 790 char **list; 791 char *p, *e; 792 int i; 793 int ncounters = cpc_npic(cpc); 794 cpc_strhash_t *hash; 795 796 if ((list = malloc(ncounters * sizeof (char *))) == NULL) 797 return; 798 799 if ((hash = __cpc_strhash_alloc()) == NULL) { 800 free(list); 801 return; 802 } 803 804 for (i = 0; i < ncounters; i++) { 805 if ((list[i] = strdup(cpc->cpc_evlist[i])) == NULL) 806 goto err; 807 p = list[i]; 808 while ((e = strchr(p, ',')) != NULL) { 809 *e = '\0'; 810 811 /* Skip any generic event names we find. */ 812 if ((strncmp(p, "PAPI", 4)) == 0) { 813 p = e + 1; 814 continue; 815 } 816 817 if (__cpc_strhash_add(hash, p) == -1) 818 goto err; 819 p = e + 1; 820 } 821 if ((strncmp(p, "PAPI", 4)) != 0) { 822 if (__cpc_strhash_add(hash, p) == -1) 823 goto err; 824 } 825 } 826 827 while ((p = __cpc_strhash_next(hash)) != NULL) 828 action(arg, p); 829 830 err: 831 __cpc_strhash_free(hash); 832 for (i = 0; i < ncounters; i++) 833 free(list[i]); 834 free(list); 835 } 836 837 /*ARGSUSED*/ 838 void 839 cpc_walk_generic_events_all(cpc_t *cpc, void *arg, 840 void (*action)(void *arg, const char *event)) 841 { 842 char **list; 843 char *p, *e; 844 int i; 845 int ncounters = cpc_npic(cpc); 846 cpc_strhash_t *hash; 847 848 if ((list = malloc(ncounters * sizeof (char *))) == NULL) 849 return; 850 851 if ((hash = __cpc_strhash_alloc()) == NULL) { 852 free(list); 853 return; 854 } 855 856 for (i = 0; i < ncounters; i++) { 857 if ((list[i] = strdup(cpc->cpc_evlist[i])) == NULL) 858 goto err; 859 p = list[i]; 860 while ((e = strchr(p, ',')) != NULL) { 861 *e = '\0'; 862 863 /* Skip any platform specific event names we find. */ 864 if ((strncmp(p, "PAPI", 4)) != 0) { 865 p = e + 1; 866 continue; 867 } 868 869 if (__cpc_strhash_add(hash, p) == -1) 870 goto err; 871 p = e + 1; 872 } 873 if ((strncmp(p, "PAPI", 4)) == 0) { 874 if (__cpc_strhash_add(hash, p) == -1) 875 goto err; 876 } 877 } 878 879 while ((p = __cpc_strhash_next(hash)) != NULL) 880 action(arg, p); 881 882 err: 883 __cpc_strhash_free(hash); 884 for (i = 0; i < ncounters; i++) 885 free(list[i]); 886 free(list); 887 } 888 889 /*ARGSUSED*/ 890 void 891 cpc_walk_events_pic(cpc_t *cpc, uint_t picno, void *arg, 892 void (*action)(void *arg, uint_t picno, const char *event)) 893 { 894 char *p; 895 char *e; 896 char *list; 897 898 if (picno >= cpc->cpc_npic) { 899 errno = EINVAL; 900 return; 901 } 902 903 if ((list = strdup(cpc->cpc_evlist[picno])) == NULL) 904 return; 905 906 /* 907 * List now points to a comma-separated list of events supported by 908 * the designated pic. 909 */ 910 p = list; 911 while ((e = strchr(p, ',')) != NULL) { 912 *e = '\0'; 913 914 /* Skip any generic event names we find. */ 915 if ((strncmp(p, "PAPI", 4)) == 0) { 916 p = e + 1; 917 continue; 918 } 919 920 action(arg, picno, p); 921 p = e + 1; 922 } 923 924 if ((strncmp(p, "PAPI", 4)) == 0) 925 goto out; 926 927 action(arg, picno, p); 928 929 out: 930 free(list); 931 } 932 933 /*ARGSUSED*/ 934 void 935 cpc_walk_generic_events_pic(cpc_t *cpc, uint_t picno, void *arg, 936 void (*action)(void *arg, uint_t picno, const char *event)) 937 { 938 char *p; 939 char *e; 940 char *list; 941 942 if (picno >= cpc->cpc_npic) { 943 errno = EINVAL; 944 return; 945 } 946 947 if ((list = strdup(cpc->cpc_evlist[picno])) == NULL) 948 return; 949 950 /* 951 * List now points to a comma-separated list of events supported by 952 * the designated pic. 953 */ 954 p = list; 955 while ((e = strchr(p, ',')) != NULL) { 956 *e = '\0'; 957 958 /* Skip any platform specific event names we find. */ 959 if ((strncmp(p, "PAPI", 4)) != 0) { 960 p = e + 1; 961 continue; 962 } 963 964 action(arg, picno, p); 965 p = e + 1; 966 } 967 968 if ((strncmp(p, "PAPI", 4)) != 0) 969 goto out; 970 971 action(arg, picno, p); 972 973 out: 974 free(list); 975 } 976 977 /*ARGSUSED*/ 978 void 979 cpc_walk_attrs(cpc_t *cpc, void *arg, 980 void (*action)(void *arg, const char *attr)) 981 { 982 char *p; 983 char *e; 984 char *list; 985 986 if ((list = strdup(cpc->cpc_attrlist)) == NULL) 987 return; 988 989 /* 990 * Platforms with no attributes will return an empty string. 991 */ 992 if (*list == '\0') 993 return; 994 995 /* 996 * List now points to a comma-separated list of attributes supported by 997 * the underlying platform. 998 */ 999 p = list; 1000 while ((e = strchr(p, ',')) != NULL) { 1001 *e = '\0'; 1002 action(arg, p); 1003 p = e + 1; 1004 } 1005 action(arg, p); 1006 1007 free(list); 1008 } 1009 1010 /*ARGSUSED*/ 1011 int 1012 cpc_enable(cpc_t *cpc) 1013 { 1014 return (syscall(SYS_cpc, CPC_ENABLE, -1, 0, 0, 0)); 1015 } 1016 1017 /*ARGSUSED*/ 1018 int 1019 cpc_disable(cpc_t *cpc) 1020 { 1021 return (syscall(SYS_cpc, CPC_DISABLE, -1, 0, 0, 0)); 1022 } 1023 1024 /*ARGSUSED*/ 1025 uint_t 1026 cpc_npic(cpc_t *cpc) 1027 { 1028 return (cpc->cpc_npic); 1029 } 1030 1031 /*ARGSUSED*/ 1032 uint_t 1033 cpc_caps(cpc_t *cpc) 1034 { 1035 return (cpc->cpc_caps); 1036 } 1037 1038 const char * 1039 cpc_cciname(cpc_t *cpc) 1040 { 1041 return (cpc->cpc_cciname); 1042 } 1043 1044 const char * 1045 cpc_cpuref(cpc_t *cpc) 1046 { 1047 return (cpc->cpc_cpuref); 1048 } 1049 1050 int 1051 cpc_seterrhndlr(cpc_t *cpc, cpc_errhndlr_t *fn) 1052 { 1053 cpc->cpc_errfn = fn; 1054 return (0); 1055 } 1056 1057 /* 1058 * These strings may contain printf() conversion specifiers. 1059 */ 1060 static const char *errstr[] = { 1061 "", /* zero slot filler */ 1062 "Unknown event\n", /* CPC_INVALID_EVENT */ 1063 "Invalid counter number\n", /* CPC_INVALID_PICNUM */ 1064 "Unknown attribute\n", /* CPC_INVALID_ATTRIBUTE */ 1065 "Attribute out of range\n", /* CPC_ATTRIBUTE_OUT_OF_RANGE */ 1066 "Hardware resource unavailable\n", /* CPC_RESOURCE_UNAVAIL */ 1067 "Counter cannot count requested event\n", /* CPC_PIC_NOT_CAPABLE */ 1068 "Invalid flags in a request\n", /* CPC_REQ_INVALID_FLAGS */ 1069 "Requests conflict with each other\n", /* CPC_CONFLICTING_REQS */ 1070 "Attribute requires the cpc_cpu privilege\n", /* CPC_ATTR_REQUIRES_PRIVILEGE */ 1071 "Couldn't bind LWP to requested processor\n", /* CPC_PBIND_FAILED */ 1072 "Hypervisor event access denied\n" /* CPC_HV_NO_ACCESS */ 1073 }; 1074 1075 /*VARARGS3*/ 1076 static void 1077 cpc_err(cpc_t *cpc, const char *fn, int subcode, ...) 1078 { 1079 va_list ap; 1080 const char *str; 1081 int error; 1082 1083 /* 1084 * If subcode is -1, there is no specific description for this error. 1085 */ 1086 if (subcode == -1) 1087 return; 1088 1089 /* 1090 * We need to preserve errno across calls to this function to prevent it 1091 * from being clobbered while here, or in the user's error handler. 1092 */ 1093 error = errno; 1094 1095 str = dgettext(TEXT_DOMAIN, errstr[subcode]); 1096 1097 va_start(ap, subcode); 1098 if (cpc->cpc_errfn != NULL) 1099 cpc->cpc_errfn(fn, subcode, str, ap); 1100 else { 1101 /* 1102 * If printf() conversion specifiers are added to the errstr[] 1103 * table, this call needs to be changed to vfprintf(). 1104 */ 1105 (void) fprintf(stderr, "libcpc: %s: %s", fn, str); 1106 } 1107 va_end(ap); 1108 1109 errno = error; 1110 } 1111 1112 /* 1113 * Hook used by libpctx to alert libcpc when a pctx handle is going away. 1114 * This is necessary to prevent libcpc from attempting a libpctx operation on a 1115 * stale and invalid pctx_t handle. Since pctx_t's are cached by libcpc, we need 1116 * to be notified when they go away. 1117 */ 1118 static void 1119 cpc_invalidate_pctx(cpc_t *cpc, pctx_t *pctx) 1120 { 1121 cpc_set_t *set; 1122 int sigblocked; 1123 1124 sigblocked = cpc_lock(cpc); 1125 for (set = cpc->cpc_sets; set != NULL; set = set->cs_next) 1126 if (set->cs_pctx == pctx) 1127 set->cs_pctx = NULL; 1128 cpc_unlock(cpc, sigblocked); 1129 } 1130 1131 /* 1132 * Check that the set is valid; if so it will be in the cpc handle's 1133 * list of sets. The lock protects the list of sets, but not the set 1134 * itself. 1135 */ 1136 static int 1137 cpc_set_valid(cpc_t *cpc, cpc_set_t *set) 1138 { 1139 cpc_set_t *csp; 1140 int sigblocked; 1141 1142 sigblocked = cpc_lock(cpc); 1143 for (csp = cpc->cpc_sets; csp != NULL; csp = csp->cs_next) 1144 if (csp == set) 1145 break; 1146 cpc_unlock(cpc, sigblocked); 1147 if (csp == NULL) 1148 return (-1); 1149 return (0); 1150 } 1151 1152 static int 1153 cpc_lock(cpc_t *cpc) 1154 { 1155 int ret = (sigset(SIGEMT, SIG_HOLD) == SIG_HOLD); 1156 (void) mutex_lock(&cpc->cpc_lock); 1157 return (ret); 1158 } 1159 1160 static void 1161 cpc_unlock(cpc_t *cpc, int sigblocked) 1162 { 1163 (void) mutex_unlock(&cpc->cpc_lock); 1164 if (sigblocked == 0) 1165 (void) sigrelse(SIGEMT); 1166 } 1167 1168 struct priv { 1169 const char *name; 1170 int found; 1171 }; 1172 1173 /*ARGSUSED*/ 1174 static void 1175 ev_walker(void *arg, uint_t picno, const char *ev) 1176 { 1177 if (strcmp(((struct priv *)arg)->name, ev) == 0) 1178 ((struct priv *)arg)->found = 1; 1179 } 1180 1181 static void 1182 at_walker(void *arg, const char *at) 1183 { 1184 if (strcmp(((struct priv *)arg)->name, at) == 0) 1185 ((struct priv *)arg)->found = 1; 1186 } 1187 1188 static int 1189 cpc_valid_event(cpc_t *cpc, uint_t pic, const char *ev) 1190 { 1191 struct priv pr = { NULL, 0 }; 1192 char *end_ev; 1193 1194 pr.name = ev; 1195 cpc_walk_events_pic(cpc, pic, &pr, ev_walker); 1196 if (pr.found) 1197 return (1); 1198 1199 cpc_walk_generic_events_pic(cpc, pic, &pr, ev_walker); 1200 if (pr.found) 1201 return (1); 1202 1203 /* 1204 * Before assuming this is an invalid event, see if we have been given 1205 * a raw event code. An event code of '0' is not recognized, as it 1206 * already has a corresponding event name in existing backends and it 1207 * is the only reasonable way to know if strtol() succeeded. 1208 * Check the second argument of strtol() to ensure invalid events 1209 * beginning with number do not go through. 1210 */ 1211 if ((strtol(ev, &end_ev, 0) != 0) && (*end_ev == '\0')) 1212 /* 1213 * Success - this is a valid raw code in hex, decimal, or octal. 1214 */ 1215 return (1); 1216 1217 return (0); 1218 } 1219 1220 static int 1221 cpc_valid_attr(cpc_t *cpc, char *attr) 1222 { 1223 struct priv pr = { NULL, 0 }; 1224 1225 pr.name = attr; 1226 cpc_walk_attrs(cpc, &pr, at_walker); 1227 return (pr.found); 1228 } 1229