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
36 typedef struct pfunc *Pfunc;
37
38 struct pfunc {
39 Pfunc next;
40 char *name;
41 long calls;
42 double time;
43 double self;
44 long num;
45 };
46
47 typedef struct sfunc *Sfunc;
48
49 struct sfunc {
50 Pfunc p;
51 Sfunc prev;
52 double beg;
53 };
54
55 typedef struct parc *Parc;
56
57 struct parc {
58 Parc next;
59 Pfunc from;
60 Pfunc to;
61 long calls;
62 double time;
63 double self;
64 };
65
66 static Pfunc calls;
67 static int ncalls;
68 static Parc arcs;
69 static int narcs;
70 static Sfunc stack;
71 static Module zprof_module;
72
73 static void
freepfuncs(Pfunc f)74 freepfuncs(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
85 static void
freeparcs(Parc a)86 freeparcs(Parc a)
87 {
88 Parc n;
89
90 for (; a; a = n) {
91 n = a->next;
92 zfree(a, sizeof(*a));
93 }
94 }
95
96 static Pfunc
findpfunc(char * name)97 findpfunc(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
108 static Parc
findparc(Pfunc f,Pfunc t)109 findparc(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
120 static int
cmpsfuncs(Pfunc * a,Pfunc * b)121 cmpsfuncs(Pfunc *a, Pfunc *b)
122 {
123 return ((*a)->self > (*b)->self ? -1 : ((*a)->self != (*b)->self));
124 }
125
126 static int
cmptfuncs(Pfunc * a,Pfunc * b)127 cmptfuncs(Pfunc *a, Pfunc *b)
128 {
129 return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time));
130 }
131
132 static int
cmpparcs(Parc * a,Parc * b)133 cmpparcs(Parc *a, Parc *b)
134 {
135 return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time));
136 }
137
138 static int
bin_zprof(UNUSED (char * nam),UNUSED (char ** args),Options ops,UNUSED (int func))139 bin_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 /**/
217 static int
zprof_wrapper(Eprog prog,FuncWrap w,char * name)218 zprof_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
290 static struct builtin bintab[] = {
291 BUILTIN("zprof", 0, bin_zprof, 0, 0, 0, "c", NULL),
292 };
293
294 static struct funcwrap wrapper[] = {
295 WRAPDEF(zprof_wrapper),
296 };
297
298 static struct features module_features = {
299 bintab, sizeof(bintab)/sizeof(*bintab),
300 NULL, 0,
301 NULL, 0,
302 NULL, 0,
303 0
304 };
305
306 /**/
307 int
setup_(Module m)308 setup_(Module m)
309 {
310 zprof_module = m;
311 return 0;
312 }
313
314 /**/
315 int
features_(Module m,char *** features)316 features_(Module m, char ***features)
317 {
318 *features = featuresarray(m, &module_features);
319 return 0;
320 }
321
322 /**/
323 int
enables_(Module m,int ** enables)324 enables_(Module m, int **enables)
325 {
326 return handlefeatures(m, &module_features, enables);
327 }
328
329 /**/
330 int
boot_(Module m)331 boot_(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 /**/
342 int
cleanup_(Module m)343 cleanup_(Module m)
344 {
345 freepfuncs(calls);
346 freeparcs(arcs);
347 deletewrapper(m, wrapper);
348 return setfeatureenables(m, &module_features, NULL);
349 }
350
351 /**/
352 int
finish_(UNUSED (Module m))353 finish_(UNUSED(Module m))
354 {
355 return 0;
356 }
357