mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 13:33:52 +01:00
336 lines
7.9 KiB
C
336 lines
7.9 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->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->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),
|
|
};
|
|
|
|
/**/
|
|
int
|
|
setup_(Module m)
|
|
{
|
|
zprof_module = m;
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
boot_(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_(Module m)
|
|
{
|
|
freepfuncs(calls);
|
|
freeparcs(arcs);
|
|
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
|
|
deletewrapper(m, wrapper);
|
|
return 0;
|
|
}
|
|
|
|
/**/
|
|
int
|
|
finish_(UNUSED(Module m))
|
|
{
|
|
return 0;
|
|
}
|