perfcnt.c revision 12927:a27c46eb192b
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/* 23 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25#include <errno.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <stropts.h> 30#include <link.h> 31#include <sys/types.h> 32#include <sys/regset.h> 33#include <sys/frame.h> 34#include <sys/procfs.h> 35#include <fcntl.h> 36#include <signal.h> 37#include "env.h" 38#include "hash.h" 39 40 41typedef struct { 42 float d_time; 43 int d_count; 44 const char *d_symname; 45} d_entry; 46 47typedef struct list { 48 d_entry *l_dep; 49 struct list *l_next; 50} List; 51 52 53static Elist *bindto_list = NULL; 54static Elist *bindfrom_list = NULL; 55 56static int initialized; 57extern long long gethrvtime(); 58 59static const char *progname; 60static long long starts[1000]; 61static long long accounted[1000]; /* time accounted for */ 62static int counter = 0; 63 64static float total_time = 0.0; 65static List *list_head = NULL; 66 67static hash *tbl; 68 69static sigset_t iset; 70 71static void 72list_insert(d_entry *dep) 73{ 74 List *new_list; 75 List *cur; 76 List *prev; 77 78 if ((new_list = malloc(sizeof (List))) == NULL) { 79 (void) printf("libperfcnt.so: malloc failed - " 80 "can't print summary\n"); 81 exit(1); 82 } 83 new_list->l_dep = dep; 84 85 if (list_head == NULL) { 86 list_head = new_list; 87 new_list->l_next = NULL; 88 return; 89 } 90 for (cur = list_head, prev = NULL; 91 (cur && (cur->l_dep->d_time < dep->d_time)); 92 prev = cur, cur = cur->l_next) 93 ; 94 /* 95 * insert at head of list 96 */ 97 if (prev == NULL) { 98 new_list->l_next = list_head; 99 list_head = new_list; 100 return; 101 } 102 prev->l_next = new_list; 103 new_list->l_next = cur; 104} 105 106uint_t 107la_version(uint_t version) 108{ 109 int fd; 110 char buffer[100]; 111 112 if (version > LAV_CURRENT) 113 (void) fprintf(stderr, "perfcnt.so.1: unexpected version: %d\n", 114 version); 115 116 (void) sprintf(buffer, "/proc/%d", (int)getpid()); 117 if ((fd = open(buffer, O_RDWR)) >= 0) { 118 long state = PR_MSACCT; 119 if (ioctl(fd, PIOCSET, &state) == -1) 120 perror("PIOCSET"); 121 (void) close(fd); 122 } 123 124 initialized++; 125 tbl = make_hash(213); 126 127 build_env_list(&bindto_list, (const char *)"PERFCNT_BINDTO"); 128 build_env_list(&bindto_list, (const char *)"PERFCNT_BINDFROM"); 129 130 /* 131 * Initalize iset to the full set of signals to be masked durring 132 * pltenter/pltexit 133 */ 134 (void) sigfillset(&iset); 135 136 return (LAV_CURRENT); 137} 138 139 140/* ARGSUSED1 */ 141uint_t 142la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) 143{ 144 static int first = 1; 145 uint_t flags = 0; 146 147 if (first) { 148 progname = lmp->l_name; 149 first = 0; 150 } 151 152 if (bindto_list == NULL) 153 flags = LA_FLG_BINDTO; 154 else { 155 if (check_list(bindto_list, lmp->l_name)) 156 flags = LA_FLG_BINDTO; 157 } 158 if (bindfrom_list == NULL) 159 flags |= LA_FLG_BINDFROM; 160 else { 161 if (check_list(bindfrom_list, lmp->l_name)) 162 flags |= LA_FLG_BINDFROM; 163 } 164 165 return (flags); 166} 167 168/* ARGSUSED1 */ 169#if defined(__sparcv9) 170uintptr_t 171la_sparcv9_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 172 uintptr_t *defcookie, La_sparcv9_regs *regset, uint_t *sb_flags, 173 const char *sym_name) 174#elif defined(__sparc) 175uintptr_t 176la_sparcv8_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 177 uintptr_t *defcookie, La_sparcv8_regs *regset, uint_t *sb_flags) 178#elif defined(__amd64) 179uintptr_t 180la_amd64_pltenter(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 181 uintptr_t *defcookie, La_amd64_regs *regset, uint_t *sb_flags, 182 const char *sym_name) 183#elif defined(__i386) 184uintptr_t 185la_i86_pltenter(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcooke, 186 uintptr_t *defcook, La_i86_regs *regset, uint_t *sb_flags) 187#endif 188{ 189 accounted[counter] = 0; 190 starts[counter] = gethrvtime(); 191 counter++; 192 return (symp->st_value); 193} 194 195 196 197/* ARGSUSED1 */ 198#if defined(_LP64) 199/* ARGSUSED */ 200uintptr_t 201la_pltexit64(Elf64_Sym *symp, uint_t symndx, uintptr_t *refcookie, 202 uintptr_t *defcookie, uintptr_t retval, const char *sym_name) 203#else 204uintptr_t 205la_pltexit(Elf32_Sym *symp, uint_t symndx, uintptr_t *refcookie, 206 uintptr_t *defcookie, uintptr_t retval) 207#endif 208{ 209 d_entry **dep; 210 long long time_used; 211 sigset_t oset; 212#if !defined(_LP64) 213 const char *sym_name = (const char *)symp->st_name; 214#endif 215 216 (void) sigprocmask(SIG_BLOCK, &iset, &oset); 217 218 counter--; 219 time_used = gethrvtime() - starts[counter]; 220 221 dep = (d_entry **)get_hash(tbl, (char *)sym_name); 222 if (*dep == NULL) { 223 char *ptr = malloc(sizeof (d_entry)); 224 /* LINTED */ 225 (*dep) = (d_entry *)ptr; 226 (*dep)->d_count = 0; 227 (*dep)->d_time = 0.0; 228 (*dep)->d_symname = sym_name; 229 } 230 231 if (counter) 232 accounted[counter - 1] += time_used; 233 234 ((*dep)->d_count)++; 235 (*dep)->d_time += (double)((time_used - accounted[counter]) / 1.0e9); 236 237 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 238 239 return (retval); 240} 241 242/* ARGSUSED1 */ 243static void 244scanlist(d_entry *dep, void *food, char *name) 245{ 246 total_time += dep->d_time; 247 list_insert(dep); 248} 249 250#pragma fini(cleanup) 251static void 252cleanup() 253{ 254 List *cur; 255 (void) operate_hash(tbl, scanlist, NULL); 256 (void) printf("\n\nPerf Counts for: %s\n\n", progname); 257 (void) printf("%20s\tc_count\t tim\t\tavg. tim\ttot. %%\n", 258 "SYMBOL"); 259 (void) printf("--------------------------------------------------" 260 "-------------------\n"); 261 for (cur = list_head; cur; cur = cur->l_next) { 262 d_entry *dep = cur->l_dep; 263 float tim = dep->d_time * 1000000; 264 265 (void) printf("%20s\t%d\t%8.2f\t%8.2f\t%2.2f%%\n", 266 dep->d_symname, dep->d_count, tim, tim / dep->d_count, 267 ((dep->d_time / total_time) * 100.0)); 268 } 269 (void) printf("--------------------------------------------------" 270 "-------------------\n"); 271 (void) printf("\t\t\t\t\t\tTotal Time: %8.2f\n", 272 total_time * 1000000); 273} 274