|
1 // |
|
2 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
3 // |
|
4 /* |
|
5 * zprof.c - a shell function profiling module for zsh |
|
6 * |
|
7 * This file is part of zsh, the Z shell. |
|
8 * |
|
9 * Copyright (c) 1996-1997 Sven Wischnowsky |
|
10 * All rights reserved. |
|
11 * |
|
12 * Permission is hereby granted, without written agreement and without |
|
13 * license or royalty fees, to use, copy, modify, and distribute this |
|
14 * software and to distribute modified versions of this software for any |
|
15 * purpose, provided that the above copyright notice and the following |
|
16 * two paragraphs appear in all copies of this software. |
|
17 * |
|
18 * In no event shall Sven Wischnowsky or the Zsh Development Group be liable |
|
19 * to any party for direct, indirect, special, incidental, or consequential |
|
20 * damages arising out of the use of this software and its documentation, |
|
21 * even if Sven Wischnowsky and the Zsh Development Group have been advised of |
|
22 * the possibility of such damage. |
|
23 * |
|
24 * Sven Wischnowsky and the Zsh Development Group specifically disclaim any |
|
25 * warranties, including, but not limited to, the implied warranties of |
|
26 * merchantability and fitness for a particular purpose. The software |
|
27 * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the |
|
28 * Zsh Development Group have no obligation to provide maintenance, |
|
29 * support, updates, enhancements, or modifications. |
|
30 * |
|
31 */ |
|
32 #include "zprof.mdh" |
|
33 #include "zprof.pro" |
|
34 |
|
35 #include <sys/time.h> |
|
36 #include <unistd.h> |
|
37 |
|
38 #ifdef __SYMBIAN32__ |
|
39 #ifdef __WINSCW__ |
|
40 #pragma warn_unusedarg off |
|
41 #pragma warn_possunwant off |
|
42 #endif//__WINSCW__ |
|
43 #endif//__SYMBIAN32__ |
|
44 |
|
45 typedef struct pfunc *Pfunc; |
|
46 |
|
47 struct pfunc { |
|
48 Pfunc next; |
|
49 char *name; |
|
50 long calls; |
|
51 double time; |
|
52 double self; |
|
53 long num; |
|
54 }; |
|
55 |
|
56 typedef struct sfunc *Sfunc; |
|
57 |
|
58 struct sfunc { |
|
59 Pfunc p; |
|
60 Sfunc prev; |
|
61 double beg; |
|
62 }; |
|
63 |
|
64 typedef struct parc *Parc; |
|
65 |
|
66 struct parc { |
|
67 Parc next; |
|
68 Pfunc from; |
|
69 Pfunc to; |
|
70 long calls; |
|
71 double time; |
|
72 double self; |
|
73 }; |
|
74 |
|
75 static Pfunc calls; |
|
76 static int ncalls; |
|
77 static Parc arcs; |
|
78 static int narcs; |
|
79 static Sfunc stack; |
|
80 static Module zprof_module; |
|
81 |
|
82 static void |
|
83 freepfuncs(Pfunc f) |
|
84 { |
|
85 Pfunc n; |
|
86 |
|
87 for (; f; f = n) { |
|
88 n = f->next; |
|
89 zsfree(f->name); |
|
90 zfree(f, sizeof(*f)); |
|
91 } |
|
92 } |
|
93 |
|
94 static void |
|
95 freeparcs(Parc a) |
|
96 { |
|
97 Parc n; |
|
98 |
|
99 for (; a; a = n) { |
|
100 n = a->next; |
|
101 zfree(a, sizeof(*a)); |
|
102 } |
|
103 } |
|
104 |
|
105 static Pfunc |
|
106 findpfunc(char *name) |
|
107 { |
|
108 Pfunc f; |
|
109 |
|
110 for (f = calls; f; f = f->next) |
|
111 if (!strcmp(name, f->name)) |
|
112 return f; |
|
113 |
|
114 return NULL; |
|
115 } |
|
116 |
|
117 static Parc |
|
118 findparc(Pfunc f, Pfunc t) |
|
119 { |
|
120 Parc a; |
|
121 |
|
122 for (a = arcs; a; a = a->next) |
|
123 if (a->from == f && a->to == t) |
|
124 return a; |
|
125 |
|
126 return NULL; |
|
127 } |
|
128 |
|
129 static int |
|
130 cmpsfuncs(Pfunc *a, Pfunc *b) |
|
131 { |
|
132 return ((*a)->self > (*b)->self ? -1 : ((*a)->self != (*b)->self)); |
|
133 } |
|
134 |
|
135 static int |
|
136 cmptfuncs(Pfunc *a, Pfunc *b) |
|
137 { |
|
138 return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time)); |
|
139 } |
|
140 |
|
141 static int |
|
142 cmpparcs(Parc *a, Parc *b) |
|
143 { |
|
144 return ((*a)->time > (*b)->time ? -1 : ((*a)->time != (*b)->time)); |
|
145 } |
|
146 |
|
147 static int |
|
148 bin_zprof(UNUSED(char *nam), UNUSED(char **args), Options ops, UNUSED(int func)) |
|
149 { |
|
150 if (OPT_ISSET(ops,'c')) { |
|
151 freepfuncs(calls); |
|
152 calls = NULL; |
|
153 ncalls = 0; |
|
154 freeparcs(arcs); |
|
155 arcs = NULL; |
|
156 narcs = 0; |
|
157 } else { |
|
158 VARARR(Pfunc, fs, (ncalls + 1)); |
|
159 Pfunc f, *fp; |
|
160 VARARR(Parc, as, (narcs + 1)); |
|
161 Parc a, *ap; |
|
162 long i; |
|
163 double total; |
|
164 |
|
165 for (total = 0.0, f = calls, fp = fs; f; f = f->next, fp++) { |
|
166 *fp = f; |
|
167 total += f->self; |
|
168 } |
|
169 *fp = NULL; |
|
170 for (a = arcs, ap = as; a; a = a->next, ap++) |
|
171 *ap = a; |
|
172 *ap = NULL; |
|
173 |
|
174 qsort(fs, ncalls, sizeof(f), |
|
175 (int (*) _((const void *, const void *))) cmpsfuncs); |
|
176 qsort(as, narcs, sizeof(a), |
|
177 (int (*) _((const void *, const void *))) cmpparcs); |
|
178 |
|
179 printf("num calls time self name\n-----------------------------------------------------------------------------------\n"); |
|
180 for (fp = fs, i = 1; *fp; fp++, i++) { |
|
181 printf("%2ld) %4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %6.2f%% %s\n", |
|
182 ((*fp)->num = i), |
|
183 (*fp)->calls, |
|
184 (*fp)->time, (*fp)->time / ((double) (*fp)->calls), |
|
185 ((*fp)->time / total) * 100.0, |
|
186 (*fp)->self, (*fp)->self / ((double) (*fp)->calls), |
|
187 ((*fp)->self / total) * 100.0, |
|
188 (*fp)->name); |
|
189 } |
|
190 qsort(fs, ncalls, sizeof(f), |
|
191 (int (*) _((const void *, const void *))) cmptfuncs); |
|
192 |
|
193 for (fp = fs; *fp; fp++) { |
|
194 printf("\n-----------------------------------------------------------------------------------\n\n"); |
|
195 for (ap = as; *ap; ap++) |
|
196 if ((*ap)->to == *fp) { |
|
197 printf(" %4ld/%-4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %s [%ld]\n", |
|
198 (*ap)->calls, (*fp)->calls, |
|
199 (*ap)->time, (*ap)->time / ((double) (*ap)->calls), |
|
200 ((*ap)->time / total) * 100.0, |
|
201 (*ap)->self, (*ap)->self / ((double) (*ap)->calls), |
|
202 (*ap)->from->name, (*ap)->from->num); |
|
203 } |
|
204 printf("%2ld) %4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %6.2f%% %s\n", |
|
205 (*fp)->num, (*fp)->calls, |
|
206 (*fp)->time, (*fp)->time / ((double) (*fp)->calls), |
|
207 ((*fp)->time / total) * 100.0, |
|
208 (*fp)->self, (*fp)->self / ((double) (*fp)->calls), |
|
209 ((*fp)->self / total) * 100.0, |
|
210 (*fp)->name); |
|
211 for (ap = as + narcs - 1; ap >= as; ap--) |
|
212 if ((*ap)->from == *fp) { |
|
213 printf(" %4ld/%-4ld %8.2f %8.2f %6.2f%% %8.2f %8.2f %s [%ld]\n", |
|
214 (*ap)->calls, (*ap)->to->calls, |
|
215 (*ap)->time, (*ap)->time / ((double) (*ap)->calls), |
|
216 ((*ap)->time / total) * 100.0, |
|
217 (*ap)->self, (*ap)->self / ((double) (*ap)->calls), |
|
218 (*ap)->to->name, (*ap)->to->num); |
|
219 } |
|
220 } |
|
221 } |
|
222 return 0; |
|
223 } |
|
224 |
|
225 /**/ |
|
226 static int |
|
227 zprof_wrapper(Eprog prog, FuncWrap w, char *name) |
|
228 { |
|
229 int active = 0; |
|
230 struct sfunc sf, *sp; |
|
231 Pfunc f = NULL; |
|
232 Parc a = NULL; |
|
233 struct timeval tv; |
|
234 struct timezone dummy; |
|
235 double prev = 0, now; |
|
236 |
|
237 if (zprof_module && !(zprof_module->flags & MOD_UNLOAD)) { |
|
238 active = 1; |
|
239 if (!(f = findpfunc(name))) { |
|
240 f = (Pfunc) zalloc(sizeof(*f)); |
|
241 f->name = ztrdup(name); |
|
242 f->calls = 0; |
|
243 f->time = f->self = 0.0; |
|
244 f->next = calls; |
|
245 calls = f; |
|
246 ncalls++; |
|
247 } |
|
248 if (stack) { |
|
249 if (!(a = findparc(stack->p, f))) { |
|
250 a = (Parc) zalloc(sizeof(*a)); |
|
251 a->from = stack->p; |
|
252 a->to = f; |
|
253 a->calls = 0; |
|
254 a->time = a->self = 0.0; |
|
255 a->next = arcs; |
|
256 arcs = a; |
|
257 narcs++; |
|
258 } |
|
259 } |
|
260 sf.prev = stack; |
|
261 sf.p = f; |
|
262 stack = &sf; |
|
263 |
|
264 f->calls++; |
|
265 tv.tv_sec = tv.tv_usec = 0; |
|
266 gettimeofday(&tv, &dummy); |
|
267 sf.beg = prev = ((((double) tv.tv_sec) * 1000.0) + |
|
268 (((double) tv.tv_usec) / 1000.0)); |
|
269 } |
|
270 runshfunc(prog, w, name); |
|
271 if (active) { |
|
272 if (zprof_module && !(zprof_module->flags & MOD_UNLOAD)) { |
|
273 tv.tv_sec = tv.tv_usec = 0; |
|
274 gettimeofday(&tv, &dummy); |
|
275 |
|
276 now = ((((double) tv.tv_sec) * 1000.0) + |
|
277 (((double) tv.tv_usec) / 1000.0)); |
|
278 f->self += now - sf.beg; |
|
279 for (sp = sf.prev; sp && sp->p != f; sp = sp->prev); |
|
280 if (!sp) |
|
281 f->time += now - prev; |
|
282 if (a) { |
|
283 a->calls++; |
|
284 a->self += now - sf.beg; |
|
285 } |
|
286 stack = sf.prev; |
|
287 |
|
288 if (stack) { |
|
289 stack->beg += now - prev; |
|
290 if (a) |
|
291 a->time += now - prev; |
|
292 } |
|
293 } else |
|
294 stack = sf.prev; |
|
295 } |
|
296 return 0; |
|
297 } |
|
298 |
|
299 static struct builtin bintab[] = { |
|
300 BUILTIN("zprof", 0, bin_zprof, 0, 0, 0, "c", NULL), |
|
301 }; |
|
302 |
|
303 static struct funcwrap wrapper[] = { |
|
304 WRAPDEF(zprof_wrapper), |
|
305 }; |
|
306 |
|
307 /**/ |
|
308 int |
|
309 setup_(Module m) |
|
310 { |
|
311 zprof_module = m; |
|
312 return 0; |
|
313 } |
|
314 |
|
315 /**/ |
|
316 int |
|
317 boot_(Module m) |
|
318 { |
|
319 calls = NULL; |
|
320 ncalls = 0; |
|
321 arcs = NULL; |
|
322 narcs = 0; |
|
323 stack = NULL; |
|
324 return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | |
|
325 !addwrapper(m, wrapper)); |
|
326 } |
|
327 |
|
328 /**/ |
|
329 int |
|
330 cleanup_(Module m) |
|
331 { |
|
332 freepfuncs(calls); |
|
333 freeparcs(arcs); |
|
334 deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); |
|
335 deletewrapper(m, wrapper); |
|
336 return 0; |
|
337 } |
|
338 |
|
339 /**/ |
|
340 int |
|
341 finish_(UNUSED(Module m)) |
|
342 { |
|
343 return 0; |
|
344 } |