summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Src/Modules/zprof.c328
-rw-r--r--Src/Modules/zprof.mdd3
2 files changed, 331 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;
+}
diff --git a/Src/Modules/zprof.mdd b/Src/Modules/zprof.mdd
new file mode 100644
index 000000000..de473cbba
--- /dev/null
+++ b/Src/Modules/zprof.mdd
@@ -0,0 +1,3 @@
+autobins="zprof"
+
+objects="zprof.o"