xref: /illumos-gate/usr/src/lib/libcpc/common/obsoleted.c (revision 012e6ce759c490003aed29439cc47d3d73a99ad3)
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