Mercurial > projects > ldc
comparison druntime/src/compiler/dmd/trace.d @ 759:d3eb054172f9
Added copy of druntime from DMD 2.020 modified for LDC.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:52:37 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
758:f04dde6e882c | 759:d3eb054172f9 |
---|---|
1 | |
2 /* Trace dynamic profiler. | |
3 * For use with the Digital Mars DMD compiler. | |
4 * Copyright (C) 1995-2006 by Digital Mars | |
5 * All Rights Reserved | |
6 * Written by Walter Bright | |
7 * www.digitalmars.com | |
8 */ | |
9 | |
10 /* | |
11 * Modified by Sean Kelly for use with the D Runtime Project | |
12 */ | |
13 | |
14 module rt.trace; | |
15 | |
16 private | |
17 { | |
18 import util.string; | |
19 import stdc.ctype; | |
20 import stdc.stdio; | |
21 import stdc.string; | |
22 import stdc.stdlib; | |
23 } | |
24 | |
25 extern (C): | |
26 | |
27 char* unmangle_ident(char*); // from DMC++ runtime library | |
28 | |
29 alias long timer_t; | |
30 | |
31 ///////////////////////////////////// | |
32 // | |
33 | |
34 struct SymPair | |
35 { | |
36 SymPair* next; | |
37 Symbol* sym; // function that is called | |
38 uint count; // number of times sym is called | |
39 } | |
40 | |
41 ///////////////////////////////////// | |
42 // A Symbol for each function name. | |
43 | |
44 struct Symbol | |
45 { | |
46 Symbol* Sl, Sr; // left, right children | |
47 SymPair* Sfanin; // list of calling functions | |
48 SymPair* Sfanout; // list of called functions | |
49 timer_t totaltime; // aggregate time | |
50 timer_t functime; // time excluding subfunction calls | |
51 ubyte Sflags; | |
52 char[] Sident; // name of symbol | |
53 } | |
54 | |
55 const ubyte SFvisited = 1; // visited | |
56 | |
57 static Symbol* root; // root of symbol table | |
58 | |
59 ////////////////////////////////// | |
60 // Build a linked list of these. | |
61 | |
62 struct Stack | |
63 { | |
64 Stack* prev; | |
65 Symbol* sym; | |
66 timer_t starttime; // time when function was entered | |
67 timer_t ohd; // overhead of all the bookkeeping code | |
68 timer_t subtime; // time used by all subfunctions | |
69 } | |
70 | |
71 static Stack* stack_freelist; | |
72 static Stack* trace_tos; // top of stack | |
73 static int trace_inited; // !=0 if initialized | |
74 static timer_t trace_ohd; | |
75 | |
76 static Symbol** psymbols; | |
77 static uint nsymbols; // number of symbols | |
78 | |
79 static string trace_logfilename = "trace.log"; | |
80 static FILE* fplog; | |
81 | |
82 static string trace_deffilename = "trace.def"; | |
83 static FILE* fpdef; | |
84 | |
85 | |
86 //////////////////////////////////////// | |
87 // Set file name for output. | |
88 // A file name of "" means write results to stdout. | |
89 // Returns: | |
90 // 0 success | |
91 // !=0 failure | |
92 | |
93 int trace_setlogfilename(string name) | |
94 { | |
95 trace_logfilename = name; | |
96 return 0; | |
97 } | |
98 | |
99 //////////////////////////////////////// | |
100 // Set file name for output. | |
101 // A file name of "" means write results to stdout. | |
102 // Returns: | |
103 // 0 success | |
104 // !=0 failure | |
105 | |
106 int trace_setdeffilename(string name) | |
107 { | |
108 trace_deffilename = name; | |
109 return 0; | |
110 } | |
111 | |
112 //////////////////////////////////////// | |
113 // Output optimal function link order. | |
114 | |
115 static void trace_order(Symbol *s) | |
116 { | |
117 while (s) | |
118 { | |
119 trace_place(s,0); | |
120 if (s.Sl) | |
121 trace_order(s.Sl); | |
122 s = s.Sr; | |
123 } | |
124 } | |
125 | |
126 ////////////////////////////////////////////// | |
127 // | |
128 | |
129 static Stack* stack_malloc() | |
130 { Stack *s; | |
131 | |
132 if (stack_freelist) | |
133 { s = stack_freelist; | |
134 stack_freelist = s.prev; | |
135 } | |
136 else | |
137 s = cast(Stack *)trace_malloc(Stack.sizeof); | |
138 return s; | |
139 } | |
140 | |
141 ////////////////////////////////////////////// | |
142 // | |
143 | |
144 static void stack_free(Stack *s) | |
145 { | |
146 s.prev = stack_freelist; | |
147 stack_freelist = s; | |
148 } | |
149 | |
150 ////////////////////////////////////// | |
151 // Qsort() comparison routine for array of pointers to SymPair's. | |
152 | |
153 static int sympair_cmp(in void* e1, in void* e2) | |
154 { SymPair** psp1; | |
155 SymPair** psp2; | |
156 | |
157 psp1 = cast(SymPair**)e1; | |
158 psp2 = cast(SymPair**)e2; | |
159 | |
160 return (*psp2).count - (*psp1).count; | |
161 } | |
162 | |
163 ////////////////////////////////////// | |
164 // Place symbol s, and then place any fan ins or fan outs with | |
165 // counts greater than count. | |
166 | |
167 static void trace_place(Symbol *s, uint count) | |
168 { SymPair* sp; | |
169 SymPair** base; | |
170 | |
171 if (!(s.Sflags & SFvisited)) | |
172 { size_t num; | |
173 uint u; | |
174 | |
175 //printf("\t%.*s\t%u\n", s.Sident, count); | |
176 fprintf(fpdef,"\t%.*s\n", s.Sident); | |
177 s.Sflags |= SFvisited; | |
178 | |
179 // Compute number of items in array | |
180 num = 0; | |
181 for (sp = s.Sfanin; sp; sp = sp.next) | |
182 num++; | |
183 for (sp = s.Sfanout; sp; sp = sp.next) | |
184 num++; | |
185 if (!num) | |
186 return; | |
187 | |
188 // Allocate and fill array | |
189 base = cast(SymPair**)trace_malloc(SymPair.sizeof * num); | |
190 u = 0; | |
191 for (sp = s.Sfanin; sp; sp = sp.next) | |
192 base[u++] = sp; | |
193 for (sp = s.Sfanout; sp; sp = sp.next) | |
194 base[u++] = sp; | |
195 | |
196 // Sort array | |
197 qsort(base, num, (SymPair *).sizeof, &sympair_cmp); | |
198 | |
199 //for (u = 0; u < num; u++) | |
200 //printf("\t\t%.*s\t%u\n", base[u].sym.Sident, base[u].count); | |
201 | |
202 // Place symbols | |
203 for (u = 0; u < num; u++) | |
204 { | |
205 if (base[u].count >= count) | |
206 { uint u2; | |
207 uint c2; | |
208 | |
209 u2 = (u + 1 < num) ? u + 1 : u; | |
210 c2 = base[u2].count; | |
211 if (c2 < count) | |
212 c2 = count; | |
213 trace_place(base[u].sym,c2); | |
214 } | |
215 else | |
216 break; | |
217 } | |
218 | |
219 // Clean up | |
220 trace_free(base); | |
221 } | |
222 } | |
223 | |
224 ///////////////////////////////////// | |
225 // Initialize and terminate. | |
226 | |
227 static this() | |
228 { | |
229 trace_init(); | |
230 } | |
231 | |
232 static ~this() | |
233 { | |
234 trace_term(); | |
235 } | |
236 | |
237 /////////////////////////////////// | |
238 // Report results. | |
239 // Also compute nsymbols. | |
240 | |
241 static void trace_report(Symbol* s) | |
242 { SymPair* sp; | |
243 uint count; | |
244 | |
245 //printf("trace_report()\n"); | |
246 while (s) | |
247 { nsymbols++; | |
248 if (s.Sl) | |
249 trace_report(s.Sl); | |
250 fprintf(fplog,"------------------\n"); | |
251 count = 0; | |
252 for (sp = s.Sfanin; sp; sp = sp.next) | |
253 { | |
254 fprintf(fplog,"\t%5d\t%.*s\n", sp.count, sp.sym.Sident); | |
255 count += sp.count; | |
256 } | |
257 fprintf(fplog,"%.*s\t%u\t%lld\t%lld\n",s.Sident,count,s.totaltime,s.functime); | |
258 for (sp = s.Sfanout; sp; sp = sp.next) | |
259 { | |
260 fprintf(fplog,"\t%5d\t%.*s\n",sp.count,sp.sym.Sident); | |
261 } | |
262 s = s.Sr; | |
263 } | |
264 } | |
265 | |
266 //////////////////////////////////// | |
267 // Allocate and fill array of symbols. | |
268 | |
269 static void trace_array(Symbol *s) | |
270 { static uint u; | |
271 | |
272 if (!psymbols) | |
273 { u = 0; | |
274 psymbols = cast(Symbol **)trace_malloc((Symbol *).sizeof * nsymbols); | |
275 } | |
276 while (s) | |
277 { | |
278 psymbols[u++] = s; | |
279 trace_array(s.Sl); | |
280 s = s.Sr; | |
281 } | |
282 } | |
283 | |
284 | |
285 ////////////////////////////////////// | |
286 // Qsort() comparison routine for array of pointers to Symbol's. | |
287 | |
288 static int symbol_cmp(in void* e1, in void* e2) | |
289 { Symbol** ps1; | |
290 Symbol** ps2; | |
291 timer_t diff; | |
292 | |
293 ps1 = cast(Symbol **)e1; | |
294 ps2 = cast(Symbol **)e2; | |
295 | |
296 diff = (*ps2).functime - (*ps1).functime; | |
297 return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1); | |
298 } | |
299 | |
300 | |
301 /////////////////////////////////// | |
302 // Report function timings | |
303 | |
304 static void trace_times(Symbol* root) | |
305 { uint u; | |
306 timer_t freq; | |
307 | |
308 // Sort array | |
309 qsort(psymbols, nsymbols, (Symbol *).sizeof, &symbol_cmp); | |
310 | |
311 // Print array | |
312 QueryPerformanceFrequency(&freq); | |
313 fprintf(fplog,"\n======== Timer Is %lld Ticks/Sec, Times are in Microsecs ========\n\n",freq); | |
314 fprintf(fplog," Num Tree Func Per\n"); | |
315 fprintf(fplog," Calls Time Time Call\n\n"); | |
316 for (u = 0; u < nsymbols; u++) | |
317 { Symbol* s = psymbols[u]; | |
318 timer_t tl,tr; | |
319 timer_t fl,fr; | |
320 timer_t pl,pr; | |
321 timer_t percall; | |
322 SymPair* sp; | |
323 uint calls; | |
324 char[] id; | |
325 | |
326 version (Windows) | |
327 { | |
328 char* p = (s.Sident ~ '\0').ptr; | |
329 p = unmangle_ident(p); | |
330 if (p) | |
331 id = p[0 .. strlen(p)]; | |
332 } | |
333 if (!id) | |
334 id = s.Sident; | |
335 calls = 0; | |
336 for (sp = s.Sfanin; sp; sp = sp.next) | |
337 calls += sp.count; | |
338 if (calls == 0) | |
339 calls = 1; | |
340 | |
341 version (all) | |
342 { | |
343 tl = (s.totaltime * 1000000) / freq; | |
344 fl = (s.functime * 1000000) / freq; | |
345 percall = s.functime / calls; | |
346 pl = (s.functime * 1000000) / calls / freq; | |
347 | |
348 fprintf(fplog,"%7d%12lld%12lld%12lld %.*s\n", | |
349 calls,tl,fl,pl,id); | |
350 } | |
351 else | |
352 { | |
353 tl = s.totaltime / freq; | |
354 tr = ((s.totaltime - tl * freq) * 10000000) / freq; | |
355 | |
356 fl = s.functime / freq; | |
357 fr = ((s.functime - fl * freq) * 10000000) / freq; | |
358 | |
359 percall = s.functime / calls; | |
360 pl = percall / freq; | |
361 pr = ((percall - pl * freq) * 10000000) / freq; | |
362 | |
363 fprintf(fplog,"%7d\t%3lld.%07lld\t%3lld.%07lld\t%3lld.%07lld\t%.*s\n", | |
364 calls,tl,tr,fl,fr,pl,pr,id); | |
365 } | |
366 if (id !is s.Sident) | |
367 free(id.ptr); | |
368 } | |
369 } | |
370 | |
371 | |
372 /////////////////////////////////// | |
373 // Initialize. | |
374 | |
375 static void trace_init() | |
376 { | |
377 if (!trace_inited) | |
378 { | |
379 trace_inited = 1; | |
380 | |
381 { // See if we can determine the overhead. | |
382 uint u; | |
383 timer_t starttime; | |
384 timer_t endtime; | |
385 Stack *st; | |
386 | |
387 st = trace_tos; | |
388 trace_tos = null; | |
389 QueryPerformanceCounter(&starttime); | |
390 for (u = 0; u < 100; u++) | |
391 { | |
392 asm | |
393 { | |
394 call _trace_pro_n ; | |
395 db 0 ; | |
396 call _trace_epi_n ; | |
397 } | |
398 } | |
399 QueryPerformanceCounter(&endtime); | |
400 trace_ohd = (endtime - starttime) / u; | |
401 //printf("trace_ohd = %lld\n",trace_ohd); | |
402 if (trace_ohd > 0) | |
403 trace_ohd--; // round down | |
404 trace_tos = st; | |
405 } | |
406 } | |
407 } | |
408 | |
409 ///////////////////////////////// | |
410 // Terminate. | |
411 | |
412 void trace_term() | |
413 { | |
414 //printf("trace_term()\n"); | |
415 if (trace_inited == 1) | |
416 { Stack *n; | |
417 | |
418 trace_inited = 2; | |
419 | |
420 // Free remainder of the stack | |
421 while (trace_tos) | |
422 { | |
423 n = trace_tos.prev; | |
424 stack_free(trace_tos); | |
425 trace_tos = n; | |
426 } | |
427 | |
428 while (stack_freelist) | |
429 { | |
430 n = stack_freelist.prev; | |
431 stack_free(stack_freelist); | |
432 stack_freelist = n; | |
433 } | |
434 | |
435 // Merge in data from any existing file | |
436 trace_merge(); | |
437 | |
438 // Report results | |
439 fplog = fopen(trace_logfilename.ptr, "w"); | |
440 if (fplog) | |
441 { nsymbols = 0; | |
442 trace_report(root); | |
443 trace_array(root); | |
444 trace_times(root); | |
445 fclose(fplog); | |
446 } | |
447 | |
448 // Output function link order | |
449 fpdef = fopen(trace_deffilename.ptr,"w"); | |
450 if (fpdef) | |
451 { fprintf(fpdef,"\nFUNCTIONS\n"); | |
452 trace_order(root); | |
453 fclose(fpdef); | |
454 } | |
455 | |
456 trace_free(psymbols); | |
457 psymbols = null; | |
458 } | |
459 } | |
460 | |
461 ///////////////////////////////// | |
462 // Our storage allocator. | |
463 | |
464 static void *trace_malloc(size_t nbytes) | |
465 { void *p; | |
466 | |
467 p = malloc(nbytes); | |
468 if (!p) | |
469 exit(EXIT_FAILURE); | |
470 return p; | |
471 } | |
472 | |
473 static void trace_free(void *p) | |
474 { | |
475 free(p); | |
476 } | |
477 | |
478 ////////////////////////////////////////////// | |
479 // | |
480 | |
481 static Symbol* trace_addsym(char[] id) | |
482 { | |
483 Symbol** parent; | |
484 Symbol* rover; | |
485 Symbol* s; | |
486 int cmp; | |
487 char c; | |
488 | |
489 //printf("trace_addsym('%s',%d)\n",p,len); | |
490 parent = &root; | |
491 rover = *parent; | |
492 while (rover !is null) // while we haven't run out of tree | |
493 { | |
494 cmp = dstrcmp(id, rover.Sident); | |
495 if (cmp == 0) | |
496 { | |
497 return rover; | |
498 } | |
499 parent = (cmp < 0) ? /* if we go down left side */ | |
500 &(rover.Sl) : /* then get left child */ | |
501 &(rover.Sr); /* else get right child */ | |
502 rover = *parent; /* get child */ | |
503 } | |
504 /* not in table, so insert into table */ | |
505 s = cast(Symbol *)trace_malloc(Symbol.sizeof); | |
506 memset(s,0,Symbol.sizeof); | |
507 s.Sident = id; | |
508 *parent = s; // link new symbol into tree | |
509 return s; | |
510 } | |
511 | |
512 /*********************************** | |
513 * Add symbol s with count to SymPair list. | |
514 */ | |
515 | |
516 static void trace_sympair_add(SymPair** psp, Symbol* s, uint count) | |
517 { SymPair* sp; | |
518 | |
519 for (; 1; psp = &sp.next) | |
520 { | |
521 sp = *psp; | |
522 if (!sp) | |
523 { | |
524 sp = cast(SymPair *)trace_malloc(SymPair.sizeof); | |
525 sp.sym = s; | |
526 sp.count = 0; | |
527 sp.next = null; | |
528 *psp = sp; | |
529 break; | |
530 } | |
531 else if (sp.sym == s) | |
532 { | |
533 break; | |
534 } | |
535 } | |
536 sp.count += count; | |
537 } | |
538 | |
539 ////////////////////////////////////////////// | |
540 // | |
541 | |
542 static void trace_pro(char[] id) | |
543 { | |
544 Stack* n; | |
545 Symbol* s; | |
546 timer_t starttime; | |
547 timer_t t; | |
548 | |
549 QueryPerformanceCounter(&starttime); | |
550 if (id.length == 0) | |
551 return; | |
552 if (!trace_inited) | |
553 trace_init(); // initialize package | |
554 n = stack_malloc(); | |
555 n.prev = trace_tos; | |
556 trace_tos = n; | |
557 s = trace_addsym(id); | |
558 trace_tos.sym = s; | |
559 if (trace_tos.prev) | |
560 { | |
561 Symbol* prev; | |
562 int i; | |
563 | |
564 // Accumulate Sfanout and Sfanin | |
565 prev = trace_tos.prev.sym; | |
566 trace_sympair_add(&prev.Sfanout,s,1); | |
567 trace_sympair_add(&s.Sfanin,prev,1); | |
568 } | |
569 QueryPerformanceCounter(&t); | |
570 trace_tos.starttime = starttime; | |
571 trace_tos.ohd = trace_ohd + t - starttime; | |
572 trace_tos.subtime = 0; | |
573 //printf("trace_tos.ohd=%lld, trace_ohd=%lld + t=%lld - starttime=%lld\n", | |
574 // trace_tos.ohd,trace_ohd,t,starttime); | |
575 } | |
576 | |
577 ///////////////////////////////////////// | |
578 // | |
579 | |
580 static void trace_epi() | |
581 { Stack* n; | |
582 timer_t endtime; | |
583 timer_t t; | |
584 timer_t ohd; | |
585 | |
586 //printf("trace_epi()\n"); | |
587 if (trace_tos) | |
588 { | |
589 timer_t starttime; | |
590 timer_t totaltime; | |
591 | |
592 QueryPerformanceCounter(&endtime); | |
593 starttime = trace_tos.starttime; | |
594 totaltime = endtime - starttime - trace_tos.ohd; | |
595 if (totaltime < 0) | |
596 { //printf("endtime=%lld - starttime=%lld - trace_tos.ohd=%lld < 0\n", | |
597 // endtime,starttime,trace_tos.ohd); | |
598 totaltime = 0; // round off error, just make it 0 | |
599 } | |
600 | |
601 // totaltime is time spent in this function + all time spent in | |
602 // subfunctions - bookkeeping overhead. | |
603 trace_tos.sym.totaltime += totaltime; | |
604 | |
605 //if (totaltime < trace_tos.subtime) | |
606 //printf("totaltime=%lld < trace_tos.subtime=%lld\n",totaltime,trace_tos.subtime); | |
607 trace_tos.sym.functime += totaltime - trace_tos.subtime; | |
608 ohd = trace_tos.ohd; | |
609 n = trace_tos.prev; | |
610 stack_free(trace_tos); | |
611 trace_tos = n; | |
612 if (n) | |
613 { QueryPerformanceCounter(&t); | |
614 n.ohd += ohd + t - endtime; | |
615 n.subtime += totaltime; | |
616 //printf("n.ohd = %lld\n",n.ohd); | |
617 } | |
618 } | |
619 } | |
620 | |
621 | |
622 ////////////////////////// FILE INTERFACE ///////////////////////// | |
623 | |
624 ///////////////////////////////////// | |
625 // Read line from file fp. | |
626 // Returns: | |
627 // trace_malloc'd line buffer | |
628 // null if end of file | |
629 | |
630 static char* trace_readline(FILE* fp) | |
631 { int c; | |
632 int dim; | |
633 int i; | |
634 char *buf; | |
635 | |
636 //printf("trace_readline(%p)\n", fp); | |
637 i = 0; | |
638 dim = 0; | |
639 buf = null; | |
640 while (1) | |
641 { | |
642 if (i == dim) | |
643 { char *p; | |
644 | |
645 dim += 80; | |
646 p = cast(char *)trace_malloc(dim); | |
647 memcpy(p,buf,i); | |
648 trace_free(buf); | |
649 buf = p; | |
650 } | |
651 c = fgetc(fp); | |
652 switch (c) | |
653 { | |
654 case EOF: | |
655 if (i == 0) | |
656 { trace_free(buf); | |
657 return null; | |
658 } | |
659 case '\n': | |
660 goto L1; | |
661 default: | |
662 break; | |
663 } | |
664 buf[i] = cast(char)c; | |
665 i++; | |
666 } | |
667 L1: | |
668 buf[i] = 0; | |
669 //printf("line '%s'\n",buf); | |
670 return buf; | |
671 } | |
672 | |
673 ////////////////////////////////////// | |
674 // Skip space | |
675 | |
676 static char *skipspace(char *p) | |
677 { | |
678 while (isspace(*p)) | |
679 p++; | |
680 return p; | |
681 } | |
682 | |
683 //////////////////////////////////////////////////////// | |
684 // Merge in profiling data from existing file. | |
685 | |
686 static void trace_merge() | |
687 { FILE *fp; | |
688 char *buf; | |
689 char *p; | |
690 uint count; | |
691 Symbol *s; | |
692 SymPair *sfanin; | |
693 SymPair **psp; | |
694 | |
695 if (trace_logfilename && (fp = fopen(trace_logfilename.ptr,"r")) !is null) | |
696 { | |
697 buf = null; | |
698 sfanin = null; | |
699 psp = &sfanin; | |
700 while (1) | |
701 { | |
702 trace_free(buf); | |
703 buf = trace_readline(fp); | |
704 if (!buf) | |
705 break; | |
706 switch (*buf) | |
707 { | |
708 case '=': // ignore rest of file | |
709 trace_free(buf); | |
710 goto L1; | |
711 case ' ': | |
712 case '\t': // fan in or fan out line | |
713 count = strtoul(buf,&p,10); | |
714 if (p == buf) // if invalid conversion | |
715 continue; | |
716 p = skipspace(p); | |
717 if (!*p) | |
718 continue; | |
719 s = trace_addsym(p[0 .. strlen(p)]); | |
720 trace_sympair_add(psp,s,count); | |
721 break; | |
722 default: | |
723 if (!isalpha(*buf)) | |
724 { | |
725 if (!sfanin) | |
726 psp = &sfanin; | |
727 continue; // regard unrecognized line as separator | |
728 } | |
729 case '?': | |
730 case '_': | |
731 case '$': | |
732 case '@': | |
733 p = buf; | |
734 while (isgraph(*p)) | |
735 p++; | |
736 *p = 0; | |
737 //printf("trace_addsym('%s')\n",buf); | |
738 s = trace_addsym(buf[0 .. strlen(buf)]); | |
739 if (s.Sfanin) | |
740 { SymPair *sp; | |
741 | |
742 for (; sfanin; sfanin = sp) | |
743 { | |
744 trace_sympair_add(&s.Sfanin,sfanin.sym,sfanin.count); | |
745 sp = sfanin.next; | |
746 trace_free(sfanin); | |
747 } | |
748 } | |
749 else | |
750 { s.Sfanin = sfanin; | |
751 } | |
752 sfanin = null; | |
753 psp = &s.Sfanout; | |
754 | |
755 { timer_t t; | |
756 | |
757 p++; | |
758 count = strtoul(p,&p,10); | |
759 t = cast(long)strtoull(p,&p,10); | |
760 s.totaltime += t; | |
761 t = cast(long)strtoull(p,&p,10); | |
762 s.functime += t; | |
763 } | |
764 break; | |
765 } | |
766 } | |
767 L1: | |
768 fclose(fp); | |
769 } | |
770 } | |
771 | |
772 ////////////////////////// COMPILER INTERFACE ///////////////////// | |
773 | |
774 ///////////////////////////////////////////// | |
775 // Function called by trace code in function prolog. | |
776 | |
777 void _trace_pro_n() | |
778 { | |
779 /* Length of string is either: | |
780 * db length | |
781 * ascii string | |
782 * or: | |
783 * db 0x0FF | |
784 * db 0 | |
785 * dw length | |
786 * ascii string | |
787 */ | |
788 | |
789 asm | |
790 { naked ; | |
791 pushad ; | |
792 mov ECX,8*4[ESP] ; | |
793 xor EAX,EAX ; | |
794 mov AL,[ECX] ; | |
795 cmp AL,0xFF ; | |
796 jne L1 ; | |
797 cmp byte ptr 1[ECX],0 ; | |
798 jne L1 ; | |
799 mov AX,2[ECX] ; | |
800 add 8*4[ESP],3 ; | |
801 add ECX,3 ; | |
802 L1: inc EAX ; | |
803 inc ECX ; | |
804 add 8*4[ESP],EAX ; | |
805 dec EAX ; | |
806 push ECX ; | |
807 push EAX ; | |
808 call trace_pro ; | |
809 add ESP,8 ; | |
810 popad ; | |
811 ret ; | |
812 } | |
813 } | |
814 | |
815 ///////////////////////////////////////////// | |
816 // Function called by trace code in function epilog. | |
817 | |
818 | |
819 void _trace_epi_n() | |
820 { | |
821 asm | |
822 { naked ; | |
823 pushad ; | |
824 } | |
825 trace_epi(); | |
826 asm | |
827 { | |
828 popad ; | |
829 ret ; | |
830 } | |
831 } | |
832 | |
833 | |
834 version (Windows) | |
835 { | |
836 extern (Windows) | |
837 { | |
838 export int QueryPerformanceCounter(timer_t *); | |
839 export int QueryPerformanceFrequency(timer_t *); | |
840 } | |
841 } | |
842 else version (X86) | |
843 { | |
844 extern (D) | |
845 { | |
846 void QueryPerformanceCounter(timer_t* ctr) | |
847 { | |
848 asm | |
849 { naked ; | |
850 mov ECX,EAX ; | |
851 rdtsc ; | |
852 mov [ECX],EAX ; | |
853 mov 4[ECX],EDX ; | |
854 ret ; | |
855 } | |
856 } | |
857 | |
858 void QueryPerformanceFrequency(timer_t* freq) | |
859 { | |
860 *freq = 3579545; | |
861 } | |
862 } | |
863 } | |
864 else | |
865 { | |
866 static assert(0); | |
867 } |