mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 18:10:56 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			356 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			356 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * zprof.c - a shell function profiling module for zsh
 | |
|  *
 | |
|  * This file is part of zsh, the Z shell.
 | |
|  *
 | |
|  * Copyright (c) 1996-1997 Sven Wischnowsky
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, without written agreement and without
 | |
|  * license or royalty fees, to use, copy, modify, and distribute this
 | |
|  * software and to distribute modified versions of this software for any
 | |
|  * purpose, provided that the above copyright notice and the following
 | |
|  * two paragraphs appear in all copies of this software.
 | |
|  *
 | |
|  * In no event shall Sven Wischnowsky or the Zsh Development Group be liable
 | |
|  * to any party for direct, indirect, special, incidental, or consequential
 | |
|  * damages arising out of the use of this software and its documentation,
 | |
|  * even if Sven Wischnowsky and the Zsh Development Group have been advised of
 | |
|  * the possibility of such damage.
 | |
|  *
 | |
|  * Sven Wischnowsky and the Zsh Development Group specifically disclaim any
 | |
|  * warranties, including, but not limited to, the implied warranties of
 | |
|  * merchantability and fitness for a particular purpose.  The software
 | |
|  * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
 | |
|  * Zsh Development Group have no obligation to provide maintenance,
 | |
|  * support, updates, enhancements, or modifications.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "zprof.mdh"
 | |
| #include "zprof.pro"
 | |
| 
 | |
| #include <sys/time.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| typedef struct pfunc *Pfunc;
 | |
| 
 | |
| struct pfunc {
 | |
|     Pfunc next;
 | |
|     char *name;
 | |
|     long calls;
 | |
|     double time;
 | |
|     double self;
 | |
|     long num;
 | |
| };
 | |
| 
 | |
| typedef struct sfunc *Sfunc;
 | |
| 
 | |
| struct sfunc {
 | |
|     Pfunc p;
 | |
|     Sfunc prev;
 | |
|     double beg;
 | |
| };
 | |
| 
 | |
| typedef struct parc *Parc;
 | |
| 
 | |
| struct parc {
 | |
|     Parc next;
 | |
|     Pfunc from;
 | |
|     Pfunc to;
 | |
|     long calls;
 | |
|     double time;
 | |
|     double self;
 | |
| };
 | |
| 
 | |
| static Pfunc calls;
 | |
| static int ncalls;
 | |
| static Parc arcs;
 | |
| static int narcs;
 | |
| static Sfunc stack;
 | |
| static Module zprof_module;
 | |
| 
 | |
| static void
 | |
| freepfuncs(Pfunc f)
 | |
| {
 | |
|     Pfunc n;
 | |
| 
 | |
|     for (; f; f = n) {
 | |
| 	n = f->next;
 | |
| 	zsfree(f->name);
 | |
| 	zfree(f, sizeof(*f));
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| freeparcs(Parc a)
 | |
| {
 | |
|     Parc n;
 | |
| 
 | |
|     for (; a; a = n) {
 | |
| 	n = a->next;
 | |
| 	zfree(a, sizeof(*a));
 | |
|     }
 | |
| }
 | |
| 
 | |
| static Pfunc
 | |
| findpfunc(char *name)
 | |
| {
 | |
|     Pfunc f;
 | |
| 
 | |
|     for (f = calls; f; f = f->next)
 | |
| 	if (!strcmp(name, f->name))
 | |
| 	    return f;
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static Parc
 | |
| findparc(Pfunc f, Pfunc t)
 | |
| {
 | |
|     Parc a;
 | |
| 
 | |
|     for (a = arcs; a; a = a->next)
 | |
| 	if (a->from == f && a->to == t)
 | |
| 	    return a;
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static int
 | |
| cmpsfuncs(Pfunc *a, Pfunc *b)
 | |
| {
 | |
|     return ((*a)->self > (*b)->self ? -1 : ((*a)->self != (*b)->self));
 | |
| }
 | |
| 
 | |
| static int
 | |
| cmptfuncs(Pfunc *a, Pfunc *b)
 | |
| {
 | |
|     return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time));
 | |
| }
 | |
| 
 | |
| static int
 | |
| cmpparcs(Parc *a, Parc *b)
 | |
| {
 | |
|     return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time));
 | |
| }
 | |
| 
 | |
| static int
 | |
| bin_zprof(UNUSED(char *nam), UNUSED(char **args), Options ops, UNUSED(int func))
 | |
| {
 | |
|     if (OPT_ISSET(ops,'c')) {
 | |
| 	freepfuncs(calls);
 | |
| 	calls = NULL;
 | |
| 	ncalls = 0;
 | |
| 	freeparcs(arcs);
 | |
| 	arcs = NULL;
 | |
| 	narcs = 0;
 | |
|     } else {
 | |
| 	VARARR(Pfunc, fs, (ncalls + 1));
 | |
| 	Pfunc f, *fp;
 | |
| 	VARARR(Parc, as, (narcs + 1));
 | |
| 	Parc a, *ap;
 | |
| 	long i;
 | |
| 	double total;
 | |
| 
 | |
| 	for (total = 0.0, f = calls, fp = fs; f; f = f->next, fp++) {
 | |
| 	    *fp = f;
 | |
| 	    total += f->self;
 | |
| 	}
 | |
| 	*fp = NULL;
 | |
| 	for (a = arcs, ap = as; a; a = a->next, ap++)
 | |
| 	    *ap = a;
 | |
| 	*ap = NULL;
 | |
| 
 | |
| 	qsort(fs, ncalls, sizeof(f),
 | |
| 	      (int (*) _((const void *, const void *))) cmpsfuncs);
 | |
| 	qsort(as, narcs, sizeof(a),
 | |
| 	      (int (*) _((const void *, const void *))) cmpparcs);
 | |
| 
 | |
| 	printf("num  calls                time                       self            name\n-----------------------------------------------------------------------------------\n");
 | |
| 	for (fp = fs, i = 1; *fp; fp++, i++) {
 | |
| 	    printf("%2ld) %4ld       %8.2f %8.2f  %6.2f%%  %8.2f %8.2f  %6.2f%%  %s\n",
 | |
| 		   ((*fp)->num = i),
 | |
| 		   (*fp)->calls,
 | |
| 		   (*fp)->time, (*fp)->time / ((double) (*fp)->calls),
 | |
| 		   ((*fp)->time / total) * 100.0,
 | |
| 		   (*fp)->self, (*fp)->self / ((double) (*fp)->calls),
 | |
| 		   ((*fp)->self / total) * 100.0,
 | |
| 		   (*fp)->name);
 | |
| 	}
 | |
| 	qsort(fs, ncalls, sizeof(f),
 | |
| 	      (int (*) _((const void *, const void *))) cmptfuncs);
 | |
| 
 | |
| 	for (fp = fs; *fp; fp++) {
 | |
| 	    printf("\n-----------------------------------------------------------------------------------\n\n");
 | |
| 	    for (ap = as; *ap; ap++)
 | |
| 		if ((*ap)->to == *fp) {
 | |
| 		    printf("    %4ld/%-4ld  %8.2f %8.2f  %6.2f%%  %8.2f %8.2f             %s [%ld]\n",
 | |
| 			   (*ap)->calls, (*fp)->calls,
 | |
| 			   (*ap)->time, (*ap)->time / ((double) (*ap)->calls),
 | |
| 			   ((*ap)->time / total) * 100.0,
 | |
| 			   (*ap)->self, (*ap)->self / ((double) (*ap)->calls),
 | |
| 			   (*ap)->from->name, (*ap)->from->num);
 | |
| 		}
 | |
| 	    printf("%2ld) %4ld       %8.2f %8.2f  %6.2f%%  %8.2f %8.2f  %6.2f%%  %s\n",
 | |
| 		   (*fp)->num, (*fp)->calls,
 | |
| 		   (*fp)->time, (*fp)->time / ((double) (*fp)->calls),
 | |
| 		   ((*fp)->time / total) * 100.0,
 | |
| 		   (*fp)->self, (*fp)->self / ((double) (*fp)->calls),
 | |
| 		   ((*fp)->self / total) * 100.0,
 | |
| 		   (*fp)->name);
 | |
| 	    for (ap = as + narcs - 1; ap >= as; ap--)
 | |
| 		if ((*ap)->from == *fp) {
 | |
| 		    printf("    %4ld/%-4ld  %8.2f %8.2f  %6.2f%%  %8.2f %8.2f             %s [%ld]\n",
 | |
| 			   (*ap)->calls, (*ap)->to->calls,
 | |
| 			   (*ap)->time, (*ap)->time / ((double) (*ap)->calls),
 | |
| 			   ((*ap)->time / total) * 100.0,
 | |
| 			   (*ap)->self, (*ap)->self / ((double) (*ap)->calls),
 | |
| 			   (*ap)->to->name, (*ap)->to->num);
 | |
| 		}
 | |
| 	}
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| static int
 | |
| zprof_wrapper(Eprog prog, FuncWrap w, char *name)
 | |
| {
 | |
|     int active = 0;
 | |
|     struct sfunc sf, *sp;
 | |
|     Pfunc f = NULL;
 | |
|     Parc a = NULL;
 | |
|     struct timeval tv;
 | |
|     struct timezone dummy;
 | |
|     double prev = 0, now;
 | |
| 
 | |
|     if (zprof_module && !(zprof_module->node.flags & MOD_UNLOAD)) {
 | |
|         active = 1;
 | |
|         if (!(f = findpfunc(name))) {
 | |
|             f = (Pfunc) zalloc(sizeof(*f));
 | |
|             f->name = ztrdup(name);
 | |
|             f->calls = 0;
 | |
|             f->time = f->self = 0.0;
 | |
|             f->next = calls;
 | |
|             calls = f;
 | |
|             ncalls++;
 | |
|         }
 | |
|         if (stack) {
 | |
|             if (!(a = findparc(stack->p, f))) {
 | |
|                 a = (Parc) zalloc(sizeof(*a));
 | |
|                 a->from = stack->p;
 | |
|                 a->to = f;
 | |
|                 a->calls = 0;
 | |
|                 a->time = a->self = 0.0;
 | |
|                 a->next = arcs;
 | |
|                 arcs = a;
 | |
|                 narcs++;
 | |
|             }
 | |
|         }
 | |
|         sf.prev = stack;
 | |
|         sf.p = f;
 | |
|         stack = &sf;
 | |
| 
 | |
|         f->calls++;
 | |
|         tv.tv_sec = tv.tv_usec = 0;
 | |
|         gettimeofday(&tv, &dummy);
 | |
|         sf.beg = prev = ((((double) tv.tv_sec) * 1000.0) +
 | |
|                          (((double) tv.tv_usec) / 1000.0));
 | |
|     }
 | |
|     runshfunc(prog, w, name);
 | |
|     if (active) {
 | |
|         if (zprof_module && !(zprof_module->node.flags & MOD_UNLOAD)) {
 | |
|             tv.tv_sec = tv.tv_usec = 0;
 | |
|             gettimeofday(&tv, &dummy);
 | |
| 
 | |
|             now = ((((double) tv.tv_sec) * 1000.0) +
 | |
|                    (((double) tv.tv_usec) / 1000.0));
 | |
|             f->self += now - sf.beg;
 | |
|             for (sp = sf.prev; sp && sp->p != f; sp = sp->prev);
 | |
|             if (!sp)
 | |
|                 f->time += now - prev;
 | |
|             if (a) {
 | |
|                 a->calls++;
 | |
|                 a->self += now - sf.beg;
 | |
|             }
 | |
|             stack = sf.prev;
 | |
| 
 | |
|             if (stack) {
 | |
|                 stack->beg += now - prev;
 | |
|                 if (a)
 | |
|                     a->time += now - prev;
 | |
|             }
 | |
|         } else
 | |
|             stack = sf.prev;
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static struct builtin bintab[] = {
 | |
|     BUILTIN("zprof", 0, bin_zprof, 0, 0, 0, "c", NULL),
 | |
| };
 | |
| 
 | |
| static struct funcwrap wrapper[] = {
 | |
|     WRAPDEF(zprof_wrapper),
 | |
| };
 | |
| 
 | |
| static struct features module_features = {
 | |
|     bintab, sizeof(bintab)/sizeof(*bintab),
 | |
|     NULL, 0,
 | |
|     NULL, 0,
 | |
|     NULL, 0,
 | |
|     0
 | |
| };
 | |
| 
 | |
| /**/
 | |
| int
 | |
| setup_(Module m)
 | |
| {
 | |
|     zprof_module = m;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| features_(Module m, char ***features)
 | |
| {
 | |
|     *features = featuresarray(m, &module_features);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| enables_(Module m, int **enables)
 | |
| {
 | |
|     return handlefeatures(m, &module_features, enables);
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| boot_(Module m)
 | |
| {
 | |
|     calls = NULL;
 | |
|     ncalls = 0;
 | |
|     arcs = NULL;
 | |
|     narcs = 0;
 | |
|     stack = NULL;
 | |
|     return addwrapper(m, wrapper);
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| cleanup_(Module m)
 | |
| {
 | |
|     freepfuncs(calls);
 | |
|     freeparcs(arcs);
 | |
|     deletewrapper(m, wrapper);
 | |
|     return setfeatureenables(m, &module_features, NULL);
 | |
| }
 | |
| 
 | |
| /**/
 | |
| int
 | |
| finish_(UNUSED(Module m))
 | |
| {
 | |
|     return 0;
 | |
| }
 |