1/* 2 * zprof.c - a shell function profiling module for zsh 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1996-1997 Sven Wischnowsky 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Sven Wischnowsky or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Sven Wischnowsky and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Sven Wischnowsky and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zprof.mdh" 31#include "zprof.pro" 32 33#include <sys/time.h> 34#include <unistd.h> 35 36typedef struct pfunc *Pfunc; 37 38struct pfunc { 39 Pfunc next; 40 char *name; 41 long calls; 42 double time; 43 double self; 44 long num; 45}; 46 47typedef struct sfunc *Sfunc; 48 49struct sfunc { 50 Pfunc p; 51 Sfunc prev; 52 double beg; 53}; 54 55typedef struct parc *Parc; 56 57struct parc { 58 Parc next; 59 Pfunc from; 60 Pfunc to; 61 long calls; 62 double time; 63 double self; 64}; 65 66static Pfunc calls; 67static int ncalls; 68static Parc arcs; 69static int narcs; 70static Sfunc stack; 71static Module zprof_module; 72 73static void 74freepfuncs(Pfunc f) 75{ 76 Pfunc n; 77 78 for (; f; f = n) { 79 n = f->next; 80 zsfree(f->name); 81 zfree(f, sizeof(*f)); 82 } 83} 84 85static void 86freeparcs(Parc a) 87{ 88 Parc n; 89 90 for (; a; a = n) { 91 n = a->next; 92 zfree(a, sizeof(*a)); 93 } 94} 95 96static Pfunc 97findpfunc(char *name) 98{ 99 Pfunc f; 100 101 for (f = calls; f; f = f->next) 102 if (!strcmp(name, f->name)) 103 return f; 104 105 return NULL; 106} 107 108static Parc 109findparc(Pfunc f, Pfunc t) 110{ 111 Parc a; 112 113 for (a = arcs; a; a = a->next) 114 if (a->from == f && a->to == t) 115 return a; 116 117 return NULL; 118} 119 120static int 121cmpsfuncs(Pfunc *a, Pfunc *b) 122{ 123 return ((*a)->self > (*b)->self ? -1 : ((*a)->self != (*b)->self)); 124} 125 126static int 127cmptfuncs(Pfunc *a, Pfunc *b) 128{ 129 return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time)); 130} 131 132static int 133cmpparcs(Parc *a, Parc *b) 134{ 135 return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time)); 136} 137 138static int 139bin_zprof(UNUSED(char *nam), UNUSED(char **args), Options ops, UNUSED(int func)) 140{ 141 if (OPT_ISSET(ops,'c')) { 142 freepfuncs(calls); 143 calls = NULL; 144 ncalls = 0; 145 freeparcs(arcs); 146 arcs = NULL; 147 narcs = 0; 148 } else { 149 VARARR(Pfunc, fs, (ncalls + 1)); 150 Pfunc f, *fp; 151 VARARR(Parc, as, (narcs + 1)); 152 Parc a, *ap; 153 long i; 154 double total; 155 156 for (total = 0.0, f = calls, fp = fs; f; f = f->next, fp++) { 157 *fp = f; 158 total += f->self; 159 } 160 *fp = NULL; 161 for (a = arcs, ap = as; a; a = a->next, ap++) 162 *ap = a; 163 *ap = NULL; 164 165 qsort(fs, ncalls, sizeof(f), 166 (int (*) _((const void *, const void *))) cmpsfuncs); 167 qsort(as, narcs, sizeof(a), 168 (int (*) _((const void *, const void *))) cmpparcs); 169 170 printf("num calls time self name\n-----------------------------------------------------------------------------------\n"); 171 for (fp = fs, i = 1; *fp; fp++, i++) { 172 printf("%2ld) %4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %6.2f%% %s\n", 173 ((*fp)->num = i), 174 (*fp)->calls, 175 (*fp)->time, (*fp)->time / ((double) (*fp)->calls), 176 ((*fp)->time / total) * 100.0, 177 (*fp)->self, (*fp)->self / ((double) (*fp)->calls), 178 ((*fp)->self / total) * 100.0, 179 (*fp)->name); 180 } 181 qsort(fs, ncalls, sizeof(f), 182 (int (*) _((const void *, const void *))) cmptfuncs); 183 184 for (fp = fs; *fp; fp++) { 185 printf("\n-----------------------------------------------------------------------------------\n\n"); 186 for (ap = as; *ap; ap++) 187 if ((*ap)->to == *fp) { 188 printf(" %4ld/%-4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %s [%ld]\n", 189 (*ap)->calls, (*fp)->calls, 190 (*ap)->time, (*ap)->time / ((double) (*ap)->calls), 191 ((*ap)->time / total) * 100.0, 192 (*ap)->self, (*ap)->self / ((double) (*ap)->calls), 193 (*ap)->from->name, (*ap)->from->num); 194 } 195 printf("%2ld) %4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %6.2f%% %s\n", 196 (*fp)->num, (*fp)->calls, 197 (*fp)->time, (*fp)->time / ((double) (*fp)->calls), 198 ((*fp)->time / total) * 100.0, 199 (*fp)->self, (*fp)->self / ((double) (*fp)->calls), 200 ((*fp)->self / total) * 100.0, 201 (*fp)->name); 202 for (ap = as + narcs - 1; ap >= as; ap--) 203 if ((*ap)->from == *fp) { 204 printf(" %4ld/%-4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %s [%ld]\n", 205 (*ap)->calls, (*ap)->to->calls, 206 (*ap)->time, (*ap)->time / ((double) (*ap)->calls), 207 ((*ap)->time / total) * 100.0, 208 (*ap)->self, (*ap)->self / ((double) (*ap)->calls), 209 (*ap)->to->name, (*ap)->to->num); 210 } 211 } 212 } 213 return 0; 214} 215 216/**/ 217static int 218zprof_wrapper(Eprog prog, FuncWrap w, char *name) 219{ 220 int active = 0; 221 struct sfunc sf, *sp; 222 Pfunc f = NULL; 223 Parc a = NULL; 224 struct timeval tv; 225 struct timezone dummy; 226 double prev = 0, now; 227 228 if (zprof_module && !(zprof_module->node.flags & MOD_UNLOAD)) { 229 active = 1; 230 if (!(f = findpfunc(name))) { 231 f = (Pfunc) zalloc(sizeof(*f)); 232 f->name = ztrdup(name); 233 f->calls = 0; 234 f->time = f->self = 0.0; 235 f->next = calls; 236 calls = f; 237 ncalls++; 238 } 239 if (stack) { 240 if (!(a = findparc(stack->p, f))) { 241 a = (Parc) zalloc(sizeof(*a)); 242 a->from = stack->p; 243 a->to = f; 244 a->calls = 0; 245 a->time = a->self = 0.0; 246 a->next = arcs; 247 arcs = a; 248 narcs++; 249 } 250 } 251 sf.prev = stack; 252 sf.p = f; 253 stack = &sf; 254 255 f->calls++; 256 tv.tv_sec = tv.tv_usec = 0; 257 gettimeofday(&tv, &dummy); 258 sf.beg = prev = ((((double) tv.tv_sec) * 1000.0) + 259 (((double) tv.tv_usec) / 1000.0)); 260 } 261 runshfunc(prog, w, name); 262 if (active) { 263 if (zprof_module && !(zprof_module->node.flags & MOD_UNLOAD)) { 264 tv.tv_sec = tv.tv_usec = 0; 265 gettimeofday(&tv, &dummy); 266 267 now = ((((double) tv.tv_sec) * 1000.0) + 268 (((double) tv.tv_usec) / 1000.0)); 269 f->self += now - sf.beg; 270 for (sp = sf.prev; sp && sp->p != f; sp = sp->prev); 271 if (!sp) 272 f->time += now - prev; 273 if (a) { 274 a->calls++; 275 a->self += now - sf.beg; 276 } 277 stack = sf.prev; 278 279 if (stack) { 280 stack->beg += now - prev; 281 if (a) 282 a->time += now - prev; 283 } 284 } else 285 stack = sf.prev; 286 } 287 return 0; 288} 289 290static struct builtin bintab[] = { 291 BUILTIN("zprof", 0, bin_zprof, 0, 0, 0, "c", NULL), 292}; 293 294static struct funcwrap wrapper[] = { 295 WRAPDEF(zprof_wrapper), 296}; 297 298static struct features module_features = { 299 bintab, sizeof(bintab)/sizeof(*bintab), 300 NULL, 0, 301 NULL, 0, 302 NULL, 0, 303 0 304}; 305 306/**/ 307int 308setup_(Module m) 309{ 310 zprof_module = m; 311 return 0; 312} 313 314/**/ 315int 316features_(Module m, char ***features) 317{ 318 *features = featuresarray(m, &module_features); 319 return 0; 320} 321 322/**/ 323int 324enables_(Module m, int **enables) 325{ 326 return handlefeatures(m, &module_features, enables); 327} 328 329/**/ 330int 331boot_(Module m) 332{ 333 calls = NULL; 334 ncalls = 0; 335 arcs = NULL; 336 narcs = 0; 337 stack = NULL; 338 return addwrapper(m, wrapper); 339} 340 341/**/ 342int 343cleanup_(Module m) 344{ 345 freepfuncs(calls); 346 freeparcs(arcs); 347 deletewrapper(m, wrapper); 348 return setfeatureenables(m, &module_features, NULL); 349} 350 351/**/ 352int 353finish_(UNUSED(Module m)) 354{ 355 return 0; 356} 357