about summary refs log tree commit diff
path: root/Src/Modules/zprof.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/zprof.c')
-rw-r--r--Src/Modules/zprof.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/Src/Modules/zprof.c b/Src/Modules/zprof.c
new file mode 100644
index 000000000..2dacd45a2
--- /dev/null
+++ b/Src/Modules/zprof.c
@@ -0,0 +1,328 @@
+/*
+ * 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 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(char *nam, char **args, char *ops, int func)
+{
+    if (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  %5.2f%%  %8.2f %8.2f  %5.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  %5.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  %5.2f%%  %8.2f %8.2f  %5.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  %5.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(List list, FuncWrap w, char *name)
+{
+    struct sfunc sf, *sp;
+    Pfunc f;
+    Parc a = NULL;
+    struct timeval tv;
+    struct timezone dummy;
+    double prev, now;
+
+    if (!(f = findpfunc(name))) {
+	PERMALLOC {
+	    f = (Pfunc) zalloc(sizeof(*f));
+	    f->name = ztrdup(name);
+	    f->calls = 0;
+	    f->time = f->self = 0.0;
+	    f->next = calls;
+	    calls = f;
+	    ncalls++;
+	} LASTALLOC;
+    }
+    if (stack) {
+	if (!(a = findparc(stack->p, f))) {
+	    PERMALLOC {
+		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++;
+	    } LASTALLOC;
+	}
+    }
+    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(list, w, name);
+    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;
+    }
+    return 0;
+}
+
+static struct builtin bintab[] = {
+    BUILTIN("zprof", 0, bin_zprof, 0, 0, 0, "c", NULL),
+};
+
+static struct funcwrap wrapper[] = {
+    WRAPDEF(zprof_wrapper),
+};
+
+/**/
+int
+setup_zprof(Module m)
+{
+    return 0;
+}
+
+/**/
+int
+boot_zprof(Module m)
+{
+    calls = NULL;
+    ncalls = 0;
+    arcs = NULL;
+    narcs = 0;
+    stack = NULL;
+    return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
+	     !addwrapper(m, wrapper));
+}
+
+/**/
+int
+cleanup_zprof(Module m)
+{
+    freepfuncs(calls);
+    freeparcs(arcs);
+    deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    deletewrapper(m, wrapper);
+    return 0;
+}
+
+/**/
+int
+finish_zprof(Module m)
+{
+    return 0;
+}