xref: /onnv-gate/usr/src/cmd/sgs/link_audit/common/perfcnt.c (revision 12927:a27c46eb192b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*12927SRod.Evans@Sun.COM  * Common Development and Distribution License (the "License").
6*12927SRod.Evans@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*12927SRod.Evans@Sun.COM 
220Sstevel@tonic-gate /*
23*12927SRod.Evans@Sun.COM  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate #include <errno.h>
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate #include <stropts.h>
300Sstevel@tonic-gate #include <link.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/regset.h>
330Sstevel@tonic-gate #include <sys/frame.h>
340Sstevel@tonic-gate #include <sys/procfs.h>
350Sstevel@tonic-gate #include <fcntl.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include "env.h"
380Sstevel@tonic-gate #include "hash.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 
410Sstevel@tonic-gate typedef struct {
420Sstevel@tonic-gate 	float		d_time;
430Sstevel@tonic-gate 	int		d_count;
440Sstevel@tonic-gate 	const char	*d_symname;
450Sstevel@tonic-gate } d_entry;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate typedef struct list {
480Sstevel@tonic-gate 	d_entry		*l_dep;
490Sstevel@tonic-gate 	struct list	*l_next;
500Sstevel@tonic-gate } List;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 
53*12927SRod.Evans@Sun.COM static Elist	    *bindto_list = NULL;
54*12927SRod.Evans@Sun.COM static Elist	    *bindfrom_list = NULL;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate static int  initialized;
570Sstevel@tonic-gate extern long long gethrvtime();
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static const char *progname;
600Sstevel@tonic-gate static long long starts[1000];
610Sstevel@tonic-gate static long long accounted[1000];		/* time accounted for */
620Sstevel@tonic-gate static int  counter = 0;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static float	total_time = 0.0;
65*12927SRod.Evans@Sun.COM static List	*list_head = NULL;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static hash	*tbl;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static sigset_t		iset;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static void
list_insert(d_entry * dep)720Sstevel@tonic-gate list_insert(d_entry *dep)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	List *new_list;
750Sstevel@tonic-gate 	List *cur;
760Sstevel@tonic-gate 	List *prev;
770Sstevel@tonic-gate 
78*12927SRod.Evans@Sun.COM 	if ((new_list = malloc(sizeof (List))) == NULL) {
790Sstevel@tonic-gate 		(void) printf("libperfcnt.so: malloc failed - "
80*12927SRod.Evans@Sun.COM 		    "can't print summary\n");
810Sstevel@tonic-gate 		exit(1);
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 	new_list->l_dep = dep;
840Sstevel@tonic-gate 
85*12927SRod.Evans@Sun.COM 	if (list_head == NULL) {
860Sstevel@tonic-gate 		list_head = new_list;
87*12927SRod.Evans@Sun.COM 		new_list->l_next = NULL;
880Sstevel@tonic-gate 		return;
890Sstevel@tonic-gate 	}
90*12927SRod.Evans@Sun.COM 	for (cur = list_head, prev = NULL;
910Sstevel@tonic-gate 	    (cur && (cur->l_dep->d_time < dep->d_time));
920Sstevel@tonic-gate 	    prev = cur, cur = cur->l_next)
930Sstevel@tonic-gate 		;
940Sstevel@tonic-gate 	/*
950Sstevel@tonic-gate 	 * insert at head of list
960Sstevel@tonic-gate 	 */
97*12927SRod.Evans@Sun.COM 	if (prev == NULL) {
980Sstevel@tonic-gate 		new_list->l_next = list_head;
990Sstevel@tonic-gate 		list_head = new_list;
1000Sstevel@tonic-gate 		return;
1010Sstevel@tonic-gate 	}
1020Sstevel@tonic-gate 	prev->l_next = new_list;
1030Sstevel@tonic-gate 	new_list->l_next = cur;
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate uint_t
la_version(uint_t version)1070Sstevel@tonic-gate la_version(uint_t version)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	int fd;
1100Sstevel@tonic-gate 	char buffer[100];
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	if (version > LAV_CURRENT)
1130Sstevel@tonic-gate 		(void) fprintf(stderr, "perfcnt.so.1: unexpected version: %d\n",
114*12927SRod.Evans@Sun.COM 		    version);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	(void) sprintf(buffer, "/proc/%d", (int)getpid());
1170Sstevel@tonic-gate 	if ((fd = open(buffer, O_RDWR)) >= 0) {
1180Sstevel@tonic-gate 		long state = PR_MSACCT;
1190Sstevel@tonic-gate 		if (ioctl(fd, PIOCSET, &state) == -1)
1200Sstevel@tonic-gate 			perror("PIOCSET");
1210Sstevel@tonic-gate 		(void) close(fd);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	initialized++;
1250Sstevel@tonic-gate 	tbl = make_hash(213);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	build_env_list(&bindto_list, (const char *)"PERFCNT_BINDTO");
1280Sstevel@tonic-gate 	build_env_list(&bindto_list, (const char *)"PERFCNT_BINDFROM");
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/*
1310Sstevel@tonic-gate 	 * Initalize iset to the full set of signals to be masked durring
1320Sstevel@tonic-gate 	 * pltenter/pltexit
1330Sstevel@tonic-gate 	 */
1340Sstevel@tonic-gate 	(void) sigfillset(&iset);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	return (LAV_CURRENT);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /* ARGSUSED1 */
1410Sstevel@tonic-gate uint_t
la_objopen(Link_map * lmp,Lmid_t lmid,uintptr_t * cookie)1420Sstevel@tonic-gate la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	static int	first = 1;
1450Sstevel@tonic-gate 	uint_t	flags = 0;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (first) {
1480Sstevel@tonic-gate 		progname = lmp->l_name;
1490Sstevel@tonic-gate 		first = 0;
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
152*12927SRod.Evans@Sun.COM 	if (bindto_list == NULL)
1530Sstevel@tonic-gate 		flags = LA_FLG_BINDTO;
1540Sstevel@tonic-gate 	else {
1550Sstevel@tonic-gate 		if (check_list(bindto_list, lmp->l_name))
1560Sstevel@tonic-gate 			flags = LA_FLG_BINDTO;
1570Sstevel@tonic-gate 	}
158*12927SRod.Evans@Sun.COM 	if (bindfrom_list == NULL)
1590Sstevel@tonic-gate 		flags |= LA_FLG_BINDFROM;
1600Sstevel@tonic-gate 	else {
1610Sstevel@tonic-gate 		if (check_list(bindfrom_list, lmp->l_name))
1620Sstevel@tonic-gate 			flags |= LA_FLG_BINDFROM;
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	return (flags);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /* ARGSUSED1 */
1690Sstevel@tonic-gate #if	defined(__sparcv9)
1700Sstevel@tonic-gate uintptr_t
la_sparcv9_pltenter(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcookie,uintptr_t * defcookie,La_sparcv9_regs * regset,uint_t * sb_flags,const char * sym_name)1710Sstevel@tonic-gate la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
1720Sstevel@tonic-gate 	uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags,
1730Sstevel@tonic-gate 	const char *sym_name)
1740Sstevel@tonic-gate #elif	defined(__sparc)
1750Sstevel@tonic-gate uintptr_t
1760Sstevel@tonic-gate la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
1770Sstevel@tonic-gate 	uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags)
1780Sstevel@tonic-gate #elif	defined(__amd64)
1790Sstevel@tonic-gate uintptr_t
1800Sstevel@tonic-gate la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
1810Sstevel@tonic-gate 	uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags,
1820Sstevel@tonic-gate 	const char *sym_name)
1830Sstevel@tonic-gate #elif	defined(__i386)
1840Sstevel@tonic-gate uintptr_t
1850Sstevel@tonic-gate la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke,
1860Sstevel@tonic-gate 	uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags)
1870Sstevel@tonic-gate #endif
1880Sstevel@tonic-gate {
1890Sstevel@tonic-gate 	accounted[counter] = 0;
1900Sstevel@tonic-gate 	starts[counter] = gethrvtime();
1910Sstevel@tonic-gate 	counter++;
1920Sstevel@tonic-gate 	return (symp->st_value);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /* ARGSUSED1 */
1980Sstevel@tonic-gate #if	defined(_LP64)
1990Sstevel@tonic-gate /* ARGSUSED */
2000Sstevel@tonic-gate uintptr_t
la_pltexit64(Elf64_Sym * symp,uint_t symndx,uintptr_t * refcookie,uintptr_t * defcookie,uintptr_t retval,const char * sym_name)2010Sstevel@tonic-gate la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2020Sstevel@tonic-gate 	uintptr_t *defcookie, uintptr_t retval, const char *sym_name)
2030Sstevel@tonic-gate #else
2040Sstevel@tonic-gate uintptr_t
2050Sstevel@tonic-gate la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie,
2060Sstevel@tonic-gate 	uintptr_t *defcookie, uintptr_t retval)
2070Sstevel@tonic-gate #endif
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	d_entry		**dep;
2100Sstevel@tonic-gate 	long long	time_used;
2110Sstevel@tonic-gate 	sigset_t	oset;
2120Sstevel@tonic-gate #if	!defined(_LP64)
2130Sstevel@tonic-gate 	const char	*sym_name = (const char *)symp->st_name;
2140Sstevel@tonic-gate #endif
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &iset, &oset);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	counter--;
2190Sstevel@tonic-gate 	time_used = gethrvtime() - starts[counter];
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	dep = (d_entry **)get_hash(tbl, (char *)sym_name);
2220Sstevel@tonic-gate 	if (*dep == NULL) {
2230Sstevel@tonic-gate 		char *ptr = malloc(sizeof (d_entry));
2240Sstevel@tonic-gate 		/* LINTED */
2250Sstevel@tonic-gate 		(*dep) = (d_entry *)ptr;
2260Sstevel@tonic-gate 		(*dep)->d_count = 0;
2270Sstevel@tonic-gate 		(*dep)->d_time = 0.0;
2280Sstevel@tonic-gate 		(*dep)->d_symname = sym_name;
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	if (counter)
2320Sstevel@tonic-gate 		accounted[counter - 1] += time_used;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	((*dep)->d_count)++;
2350Sstevel@tonic-gate 	(*dep)->d_time += (double)((time_used - accounted[counter]) / 1.0e9);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	return (retval);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate /* ARGSUSED1 */
2430Sstevel@tonic-gate static void
scanlist(d_entry * dep,void * food,char * name)2440Sstevel@tonic-gate scanlist(d_entry *dep, void *food, char *name)
2450Sstevel@tonic-gate {
2460Sstevel@tonic-gate 	total_time += dep->d_time;
2470Sstevel@tonic-gate 	list_insert(dep);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate #pragma fini(cleanup)
2510Sstevel@tonic-gate static void
cleanup()2520Sstevel@tonic-gate cleanup()
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 	List	*cur;
2550Sstevel@tonic-gate 	(void) operate_hash(tbl, scanlist, NULL);
2560Sstevel@tonic-gate 	(void) printf("\n\nPerf Counts for: %s\n\n", progname);
2570Sstevel@tonic-gate 	(void) printf("%20s\tc_count\t    tim\t\tavg. tim\ttot. %%\n",
258*12927SRod.Evans@Sun.COM 	    "SYMBOL");
2590Sstevel@tonic-gate 	(void) printf("--------------------------------------------------"
260*12927SRod.Evans@Sun.COM 	    "-------------------\n");
2610Sstevel@tonic-gate 	for (cur = list_head; cur; cur = cur->l_next) {
2620Sstevel@tonic-gate 		d_entry		*dep = cur->l_dep;
2630Sstevel@tonic-gate 		float		tim = dep->d_time * 1000000;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 		(void) printf("%20s\t%d\t%8.2f\t%8.2f\t%2.2f%%\n",
266*12927SRod.Evans@Sun.COM 		    dep->d_symname, dep->d_count, tim, tim / dep->d_count,
267*12927SRod.Evans@Sun.COM 		    ((dep->d_time / total_time) * 100.0));
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 	(void) printf("--------------------------------------------------"
270*12927SRod.Evans@Sun.COM 	    "-------------------\n");
2710Sstevel@tonic-gate 	(void) printf("\t\t\t\t\t\tTotal Time: %8.2f\n",
272*12927SRod.Evans@Sun.COM 	    total_time * 1000000);
2730Sstevel@tonic-gate }
274