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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/syscall.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <errno.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <stdarg.h> 37 #include <signal.h> 38 #include <libintl.h> 39 #include <dirent.h> 40 #include <sys/cpc_impl.h> 41 42 #include "libcpc.h" 43 #include "libcpc_impl.h" 44 45 /* 46 * CPC library handle for use by CPCv1 implementation. 47 */ 48 cpc_t *__cpc = NULL; 49 mutex_t __cpc_lock; /* protects __cpc handle */ 50 int __cpc_v1_cpuver; /* CPU version in use by CPCv1 client */ 51 52 #ifdef __sparc 53 uint64_t __cpc_v1_pcr; /* last bound %pcr value */ 54 #else 55 uint32_t __cpc_v1_pes[2]; /* last bound %pes values */ 56 #endif /* __sparc */ 57 58 int 59 __cpc_init(void) 60 { 61 const char *fn = "__cpc_init"; 62 extern cpc_t *__cpc; /* CPC handle for obsolete clients to share */ 63 64 (void) mutex_lock(&__cpc_lock); 65 if (__cpc == NULL && (__cpc = cpc_open(CPC_VER_CURRENT)) == NULL) { 66 __cpc_error(fn, dgettext(TEXT_DOMAIN, 67 "Couldn't open CPC library handle\n")); 68 (void) mutex_unlock(&__cpc_lock); 69 return (-1); 70 } 71 (void) mutex_unlock(&__cpc_lock); 72 73 return (0); 74 } 75 76 int 77 cpc_bind_event(cpc_event_t *this, int flags) 78 { 79 cpc_set_t *set; 80 cpc_request_t *rp; 81 int ret; 82 83 if (this == NULL) { 84 (void) cpc_rele(); 85 return (0); 86 } 87 88 if (__cpc_init() != 0) { 89 errno = ENXIO; 90 return (-1); 91 } 92 93 /* 94 * The cpuver and control fields of the cpc_event_t must be saved off 95 * for later. The user may call cpc_take_sample(), expecting these to 96 * be copied into a different cpc_event_t struct by the kernel. We have 97 * to fake that behavior for CPCv1 clients. 98 */ 99 __cpc_v1_cpuver = this->ce_cpuver; 100 #ifdef __sparc 101 __cpc_v1_pcr = this->ce_pcr; 102 #else 103 __cpc_v1_pes[0] = this->ce_pes[0]; 104 __cpc_v1_pes[1] = this->ce_pes[1]; 105 #endif /* __sparc */ 106 107 if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) { 108 errno = EINVAL; 109 return (-1); 110 } 111 112 /* 113 * Convert flags to CPC2. 114 */ 115 if (flags & CPC_BIND_EMT_OVF) { 116 for (rp = set->cs_request; rp != NULL; rp = rp->cr_next) 117 rp->cr_flags |= CPC_OVF_NOTIFY_EMT; 118 flags &= ~CPC_BIND_EMT_OVF; 119 } 120 121 ret = cpc_bind_curlwp(__cpc, set, flags); 122 123 (void) cpc_set_destroy(__cpc, set); 124 125 return (ret); 126 } 127 128 int 129 cpc_take_sample(cpc_event_t *this) 130 { 131 this->ce_cpuver = __cpc_v1_cpuver; 132 #ifdef __sparc 133 this->ce_pcr = __cpc_v1_pcr; 134 #else 135 this->ce_pes[0] = __cpc_v1_pes[0]; 136 this->ce_pes[1] = __cpc_v1_pes[1]; 137 #endif /* __sparc */ 138 139 return (syscall(SYS_cpc, CPC_SAMPLE, -1, this->ce_pic, &this->ce_hrt, 140 &CPC_TICKREG(this), 0)); 141 } 142 143 int 144 cpc_count_usr_events(int enable) 145 { 146 return (syscall(SYS_cpc, CPC_USR_EVENTS, -1, enable, 0)); 147 } 148 149 int 150 cpc_count_sys_events(int enable) 151 { 152 return (syscall(SYS_cpc, CPC_SYS_EVENTS, -1, enable, 0)); 153 } 154 155 int 156 cpc_rele(void) 157 { 158 return (syscall(SYS_cpc, CPC_RELE, -1, NULL, 0)); 159 } 160 161 /* 162 * See if the system call is working and installed. 163 * 164 * We invoke the system call with nonsense arguments - if it's 165 * there and working correctly, it will return EINVAL. 166 * 167 * (This avoids the user getting a SIGSYS core dump when they attempt 168 * to bind on older hardware) 169 */ 170 int 171 cpc_access(void) 172 { 173 void (*handler)(int); 174 int error = 0; 175 const char fn[] = "access"; 176 177 handler = signal(SIGSYS, SIG_IGN); 178 if (syscall(SYS_cpc, -1, -1, NULL, 0) == -1 && 179 errno != EINVAL) 180 error = errno; 181 (void) signal(SIGSYS, handler); 182 183 switch (error) { 184 case EAGAIN: 185 __cpc_error(fn, dgettext(TEXT_DOMAIN, "Another process may be " 186 "sampling system-wide CPU statistics\n")); 187 break; 188 case ENOSYS: 189 __cpc_error(fn, 190 dgettext(TEXT_DOMAIN, "CPU performance counters " 191 "are inaccessible on this machine\n")); 192 break; 193 default: 194 __cpc_error(fn, "%s\n", strerror(errno)); 195 break; 196 case 0: 197 return (0); 198 } 199 200 errno = error; 201 return (-1); 202 } 203 204 /* 205 * To look at the system-wide counters, we have to open the 206 * 'shared' device. Once that device is open, no further contexts 207 * can be installed (though one open is needed per CPU) 208 */ 209 int 210 cpc_shared_open(void) 211 { 212 const char driver[] = CPUDRV_SHARED; 213 214 return (open(driver, O_RDWR)); 215 } 216 217 void 218 cpc_shared_close(int fd) 219 { 220 (void) cpc_shared_rele(fd); 221 (void) close(fd); 222 } 223 224 int 225 cpc_shared_bind_event(int fd, cpc_event_t *this, int flags) 226 { 227 extern cpc_t *__cpc; 228 cpc_set_t *set; 229 int ret; 230 char *packed_set; 231 size_t packsize; 232 int subcode; 233 __cpc_args_t cpc_args; 234 235 if (this == NULL) { 236 (void) cpc_shared_rele(fd); 237 return (0); 238 } else if (flags != 0) { 239 errno = EINVAL; 240 return (-1); 241 } 242 243 if (__cpc_init() != 0) { 244 errno = ENXIO; 245 return (-1); 246 } 247 248 if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) { 249 errno = EINVAL; 250 return (-1); 251 } 252 253 __cpc_v1_cpuver = this->ce_cpuver; 254 255 if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 256 errno = ENOMEM; 257 return (-1); 258 } 259 260 cpc_args.udata1 = packed_set; 261 cpc_args.udata2 = (void *)packsize; 262 cpc_args.udata3 = (void *)&subcode; 263 264 ret = ioctl(fd, CPCIO_BIND, &cpc_args); 265 266 free(packed_set); 267 (void) cpc_set_destroy(__cpc, set); 268 269 return (ret); 270 } 271 272 int 273 cpc_shared_take_sample(int fd, cpc_event_t *this) 274 { 275 __cpc_args_t args; 276 277 args.udata1 = this->ce_pic; 278 args.udata2 = &this->ce_hrt; 279 args.udata3 = &CPC_TICKREG(this); 280 281 this->ce_cpuver = __cpc_v1_cpuver; 282 283 return (ioctl(fd, CPCIO_SAMPLE, &args)); 284 } 285 286 int 287 cpc_shared_rele(int fd) 288 { 289 return (ioctl(fd, CPCIO_RELE, 0)); 290 } 291 292 int 293 cpc_pctx_bind_event(pctx_t *pctx, id_t lwpid, cpc_event_t *event, int flags) 294 { 295 cpc_set_t *set; 296 int ret; 297 298 if (event == NULL) 299 return (cpc_pctx_rele(pctx, lwpid)); 300 301 if (__cpc_init() != 0) { 302 errno = ENXIO; 303 return (-1); 304 } 305 306 else if (flags != 0) { 307 errno = EINVAL; 308 return (-1); 309 } 310 311 if ((set = __cpc_eventtoset(__cpc, event, flags)) == NULL) { 312 errno = EINVAL; 313 return (-1); 314 } 315 316 /* 317 * The cpuver and control fields of the cpc_event_t must be saved off 318 * for later. The user may call cpc_take_sample(), expecting these to 319 * be copied into a different cpc_event_t struct by the kernel. We have 320 * to fake that behavior for CPCv1 clients. 321 */ 322 __cpc_v1_cpuver = event->ce_cpuver; 323 324 ret = cpc_bind_pctx(__cpc, pctx, lwpid, set, 0); 325 326 (void) cpc_set_destroy(__cpc, set); 327 328 return (ret); 329 } 330 331 int 332 cpc_pctx_take_sample(pctx_t *pctx, id_t lwpid, cpc_event_t *event) 333 { 334 event->ce_cpuver = __cpc_v1_cpuver; 335 336 return (__pctx_cpc(pctx, __cpc, CPC_SAMPLE, lwpid, event->ce_pic, 337 &event->ce_hrt, &CPC_TICKREG(event), CPC1_BUFSIZE)); 338 } 339 340 /* 341 * Given a process context and an lwpid, mark the CPU performance 342 * counter context as invalid. 343 */ 344 int 345 cpc_pctx_invalidate(pctx_t *pctx, id_t lwpid) 346 { 347 return (__pctx_cpc(pctx, __cpc, CPC_INVALIDATE, lwpid, 0, 0, 0, 0)); 348 } 349 350 /* 351 * Given a process context and an lwpid, remove all our 352 * hardware context from it. 353 */ 354 int 355 cpc_pctx_rele(pctx_t *pctx, id_t lwpid) 356 { 357 return (__pctx_cpc(pctx, __cpc, CPC_RELE, lwpid, 0, 0, 0, 0)); 358 } 359 360 static cpc_errfn_t *__cpc_uerrfn; 361 362 /*PRINTFLIKE2*/ 363 void 364 __cpc_error(const char *fn, const char *fmt, ...) 365 { 366 va_list ap; 367 368 va_start(ap, fmt); 369 if (__cpc_uerrfn) 370 __cpc_uerrfn(fn, fmt, ap); 371 else { 372 (void) fprintf(stderr, "libcpc: %s: ", fn); 373 (void) vfprintf(stderr, fmt, ap); 374 } 375 va_end(ap); 376 } 377 378 void 379 cpc_seterrfn(cpc_errfn_t *errfn) 380 { 381 __cpc_uerrfn = errfn; 382 } 383 384 /* 385 * cpc_version() is only for CPC1 clients. 386 */ 387 uint_t __cpc_workver = CPC_VER_1; 388 389 uint_t 390 cpc_version(uint_t ver) 391 { 392 __cpc_workver = CPC_VER_1; 393 394 switch (ver) { 395 case CPC_VER_NONE: 396 case CPC_VER_CURRENT: 397 return (CPC_VER_CURRENT); 398 case CPC_VER_1: 399 /* 400 * As long as the client is using cpc_version() at all, it is 401 * a CPCv1 client. We still allow CPCv1 clients to compile on 402 * CPCv2 systems. 403 */ 404 return (CPC_VER_1); 405 } 406 407 return (CPC_VER_NONE); 408 } 409