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