mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 22:21:09 +03:00
859 lines
16 KiB
D
859 lines
16 KiB
D
|
|
/* Trace dynamic profiler.
|
|
* For use with the Digital Mars DMD compiler.
|
|
* Copyright (C) 1995-2005 by Digital Mars
|
|
* All Rights Reserved
|
|
* Written by Walter Bright
|
|
* www.digitalmars.com
|
|
*/
|
|
|
|
module internal.trace;
|
|
|
|
import std.stdio;
|
|
import std.ctype;
|
|
import std.string;
|
|
import std.c.stdlib;
|
|
|
|
extern (C):
|
|
|
|
char* unmangle_ident(char*); // from DMC++ runtime library
|
|
|
|
alias long timer_t;
|
|
|
|
/////////////////////////////////////
|
|
//
|
|
|
|
struct SymPair
|
|
{
|
|
SymPair* next;
|
|
Symbol* sym; // function that is called
|
|
uint count; // number of times sym is called
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
// A Symbol for each function name.
|
|
|
|
struct Symbol
|
|
{
|
|
Symbol* Sl, Sr; // left, right children
|
|
SymPair* Sfanin; // list of calling functions
|
|
SymPair* Sfanout; // list of called functions
|
|
timer_t totaltime; // aggregate time
|
|
timer_t functime; // time excluding subfunction calls
|
|
ubyte Sflags;
|
|
char[] Sident; // name of symbol
|
|
}
|
|
|
|
const ubyte SFvisited = 1; // visited
|
|
|
|
static Symbol* root; // root of symbol table
|
|
|
|
//////////////////////////////////
|
|
// Build a linked list of these.
|
|
|
|
struct Stack
|
|
{
|
|
Stack* prev;
|
|
Symbol* sym;
|
|
timer_t starttime; // time when function was entered
|
|
timer_t ohd; // overhead of all the bookkeeping code
|
|
timer_t subtime; // time used by all subfunctions
|
|
}
|
|
|
|
static Stack* stack_freelist;
|
|
static Stack* trace_tos; // top of stack
|
|
static int trace_inited; // !=0 if initialized
|
|
static timer_t trace_ohd;
|
|
|
|
static Symbol** psymbols;
|
|
static uint nsymbols; // number of symbols
|
|
|
|
static char[] trace_logfilename = "trace.log";
|
|
static FILE* fplog;
|
|
|
|
static char[] trace_deffilename = "trace.def";
|
|
static FILE* fpdef;
|
|
|
|
|
|
////////////////////////////////////////
|
|
// Set file name for output.
|
|
// A file name of "" means write results to stdout.
|
|
// Returns:
|
|
// 0 success
|
|
// !=0 failure
|
|
|
|
int trace_setlogfilename(char[] name)
|
|
{
|
|
trace_logfilename = name;
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
// Set file name for output.
|
|
// A file name of "" means write results to stdout.
|
|
// Returns:
|
|
// 0 success
|
|
// !=0 failure
|
|
|
|
int trace_setdeffilename(char[] name)
|
|
{
|
|
trace_deffilename = name;
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
// Output optimal function link order.
|
|
|
|
static void trace_order(Symbol *s)
|
|
{
|
|
while (s)
|
|
{
|
|
trace_place(s,0);
|
|
if (s.Sl)
|
|
trace_order(s.Sl);
|
|
s = s.Sr;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
//
|
|
|
|
static Stack* stack_malloc()
|
|
{ Stack *s;
|
|
|
|
if (stack_freelist)
|
|
{ s = stack_freelist;
|
|
stack_freelist = s.prev;
|
|
}
|
|
else
|
|
s = cast(Stack *)trace_malloc(Stack.sizeof);
|
|
return s;
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
//
|
|
|
|
static void stack_free(Stack *s)
|
|
{
|
|
s.prev = stack_freelist;
|
|
stack_freelist = s;
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
// Qsort() comparison routine for array of pointers to SymPair's.
|
|
|
|
static int sympair_cmp(void* e1, void* e2)
|
|
{ SymPair** psp1;
|
|
SymPair** psp2;
|
|
|
|
psp1 = cast(SymPair**)e1;
|
|
psp2 = cast(SymPair**)e2;
|
|
|
|
return (*psp2).count - (*psp1).count;
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
// Place symbol s, and then place any fan ins or fan outs with
|
|
// counts greater than count.
|
|
|
|
static void trace_place(Symbol *s, uint count)
|
|
{ SymPair* sp;
|
|
SymPair** base;
|
|
|
|
if (!(s.Sflags & SFvisited))
|
|
{ size_t num;
|
|
uint u;
|
|
|
|
//printf("\t%.*s\t%u\n", s.Sident, count);
|
|
fprintf(fpdef,"\t%.*s\n", s.Sident);
|
|
s.Sflags |= SFvisited;
|
|
|
|
// Compute number of items in array
|
|
num = 0;
|
|
for (sp = s.Sfanin; sp; sp = sp.next)
|
|
num++;
|
|
for (sp = s.Sfanout; sp; sp = sp.next)
|
|
num++;
|
|
if (!num)
|
|
return;
|
|
|
|
// Allocate and fill array
|
|
base = cast(SymPair**)trace_malloc(SymPair.sizeof * num);
|
|
u = 0;
|
|
for (sp = s.Sfanin; sp; sp = sp.next)
|
|
base[u++] = sp;
|
|
for (sp = s.Sfanout; sp; sp = sp.next)
|
|
base[u++] = sp;
|
|
|
|
// Sort array
|
|
qsort(base, num, (SymPair *).sizeof, &sympair_cmp);
|
|
|
|
//for (u = 0; u < num; u++)
|
|
//printf("\t\t%.*s\t%u\n", base[u].sym.Sident, base[u].count);
|
|
|
|
// Place symbols
|
|
for (u = 0; u < num; u++)
|
|
{
|
|
if (base[u].count >= count)
|
|
{ uint u2;
|
|
uint c2;
|
|
|
|
u2 = (u + 1 < num) ? u + 1 : u;
|
|
c2 = base[u2].count;
|
|
if (c2 < count)
|
|
c2 = count;
|
|
trace_place(base[u].sym,c2);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// Clean up
|
|
trace_free(base);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////
|
|
// Initialize and terminate.
|
|
|
|
static this()
|
|
{
|
|
trace_init();
|
|
}
|
|
|
|
static ~this()
|
|
{
|
|
trace_term();
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// Report results.
|
|
// Also compute nsymbols.
|
|
|
|
static void trace_report(Symbol* s)
|
|
{ SymPair* sp;
|
|
uint count;
|
|
|
|
//printf("trace_report()\n");
|
|
while (s)
|
|
{ nsymbols++;
|
|
if (s.Sl)
|
|
trace_report(s.Sl);
|
|
fprintf(fplog,"------------------\n");
|
|
count = 0;
|
|
for (sp = s.Sfanin; sp; sp = sp.next)
|
|
{
|
|
fprintf(fplog,"\t%5d\t%.*s\n", sp.count, sp.sym.Sident);
|
|
count += sp.count;
|
|
}
|
|
fprintf(fplog,"%.*s\t%u\t%lld\t%lld\n",s.Sident,count,s.totaltime,s.functime);
|
|
for (sp = s.Sfanout; sp; sp = sp.next)
|
|
{
|
|
fprintf(fplog,"\t%5d\t%.*s\n",sp.count,sp.sym.Sident);
|
|
}
|
|
s = s.Sr;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////
|
|
// Allocate and fill array of symbols.
|
|
|
|
static void trace_array(Symbol *s)
|
|
{ static uint u;
|
|
|
|
if (!psymbols)
|
|
{ u = 0;
|
|
psymbols = cast(Symbol **)trace_malloc((Symbol *).sizeof * nsymbols);
|
|
}
|
|
while (s)
|
|
{
|
|
psymbols[u++] = s;
|
|
trace_array(s.Sl);
|
|
s = s.Sr;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////
|
|
// Qsort() comparison routine for array of pointers to Symbol's.
|
|
|
|
static int symbol_cmp(void* e1, void* e2)
|
|
{ Symbol** ps1;
|
|
Symbol** ps2;
|
|
timer_t diff;
|
|
|
|
ps1 = cast(Symbol **)e1;
|
|
ps2 = cast(Symbol **)e2;
|
|
|
|
diff = (*ps2).functime - (*ps1).functime;
|
|
return (diff == 0) ? 0 : ((diff > 0) ? 1 : -1);
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
// Report function timings
|
|
|
|
static void trace_times(Symbol* root)
|
|
{ uint u;
|
|
timer_t freq;
|
|
|
|
// Sort array
|
|
qsort(psymbols, nsymbols, (Symbol *).sizeof, &symbol_cmp);
|
|
|
|
// Print array
|
|
QueryPerformanceFrequency(&freq);
|
|
fprintf(fplog,"\n======== Timer Is %lld Ticks/Sec, Times are in Microsecs ========\n\n",freq);
|
|
fprintf(fplog," Num Tree Func Per\n");
|
|
fprintf(fplog," Calls Time Time Call\n\n");
|
|
for (u = 0; u < nsymbols; u++)
|
|
{ Symbol* s = psymbols[u];
|
|
timer_t tl,tr;
|
|
timer_t fl,fr;
|
|
timer_t pl,pr;
|
|
timer_t percall;
|
|
SymPair* sp;
|
|
uint calls;
|
|
char[] id;
|
|
|
|
version (Win32)
|
|
{ char* p = toStringz(s.Sident);
|
|
p = unmangle_ident(p);
|
|
if (p)
|
|
id = p[0 .. strlen(p)];
|
|
}
|
|
if (!id)
|
|
id = s.Sident;
|
|
calls = 0;
|
|
for (sp = s.Sfanin; sp; sp = sp.next)
|
|
calls += sp.count;
|
|
if (calls == 0)
|
|
calls = 1;
|
|
|
|
version (all)
|
|
{
|
|
tl = (s.totaltime * 1000000) / freq;
|
|
fl = (s.functime * 1000000) / freq;
|
|
percall = s.functime / calls;
|
|
pl = (s.functime * 1000000) / calls / freq;
|
|
|
|
fprintf(fplog,"%7d%12lld%12lld%12lld %.*s\n",
|
|
calls,tl,fl,pl,id);
|
|
}
|
|
else
|
|
{
|
|
tl = s.totaltime / freq;
|
|
tr = ((s.totaltime - tl * freq) * 10000000) / freq;
|
|
|
|
fl = s.functime / freq;
|
|
fr = ((s.functime - fl * freq) * 10000000) / freq;
|
|
|
|
percall = s.functime / calls;
|
|
pl = percall / freq;
|
|
pr = ((percall - pl * freq) * 10000000) / freq;
|
|
|
|
fprintf(fplog,"%7d\t%3lld.%07lld\t%3lld.%07lld\t%3lld.%07lld\t%.*s\n",
|
|
calls,tl,tr,fl,fr,pl,pr,id);
|
|
}
|
|
if (id !is s.Sident)
|
|
free(id);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
// Initialize.
|
|
|
|
static void trace_init()
|
|
{
|
|
if (!trace_inited)
|
|
{
|
|
trace_inited = 1;
|
|
|
|
{ // See if we can determine the overhead.
|
|
uint u;
|
|
timer_t starttime;
|
|
timer_t endtime;
|
|
Stack *st;
|
|
|
|
st = trace_tos;
|
|
trace_tos = null;
|
|
QueryPerformanceCounter(&starttime);
|
|
for (u = 0; u < 100; u++)
|
|
{
|
|
asm
|
|
{
|
|
call _trace_pro_n ;
|
|
db 0 ;
|
|
call _trace_epi_n ;
|
|
}
|
|
}
|
|
QueryPerformanceCounter(&endtime);
|
|
trace_ohd = (endtime - starttime) / u;
|
|
//printf("trace_ohd = %lld\n",trace_ohd);
|
|
if (trace_ohd > 0)
|
|
trace_ohd--; // round down
|
|
trace_tos = st;
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// Terminate.
|
|
|
|
void trace_term()
|
|
{
|
|
//printf("trace_term()\n");
|
|
if (trace_inited == 1)
|
|
{ Stack *n;
|
|
|
|
trace_inited = 2;
|
|
|
|
// Free remainder of the stack
|
|
while (trace_tos)
|
|
{
|
|
n = trace_tos.prev;
|
|
stack_free(trace_tos);
|
|
trace_tos = n;
|
|
}
|
|
|
|
while (stack_freelist)
|
|
{
|
|
n = stack_freelist.prev;
|
|
stack_free(stack_freelist);
|
|
stack_freelist = n;
|
|
}
|
|
|
|
// Merge in data from any existing file
|
|
trace_merge();
|
|
|
|
// Report results
|
|
fplog = fopen(trace_logfilename,"w");
|
|
//fplog = std.c.stdio.stdout;
|
|
if (fplog)
|
|
{ nsymbols = 0;
|
|
trace_report(root);
|
|
trace_array(root);
|
|
trace_times(root);
|
|
fclose(fplog);
|
|
}
|
|
|
|
// Output function link order
|
|
fpdef = fopen(trace_deffilename,"w");
|
|
if (fpdef)
|
|
{ fprintf(fpdef,"\nFUNCTIONS\n");
|
|
trace_order(root);
|
|
fclose(fpdef);
|
|
}
|
|
|
|
trace_free(psymbols);
|
|
psymbols = null;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////
|
|
// Our storage allocator.
|
|
|
|
static void *trace_malloc(size_t nbytes)
|
|
{ void *p;
|
|
|
|
p = malloc(nbytes);
|
|
if (!p)
|
|
exit(EXIT_FAILURE);
|
|
return p;
|
|
}
|
|
|
|
static void trace_free(void *p)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
//
|
|
|
|
static Symbol* trace_addsym(char[] id)
|
|
{
|
|
Symbol** parent;
|
|
Symbol* rover;
|
|
Symbol* s;
|
|
int cmp;
|
|
char c;
|
|
|
|
//printf("trace_addsym('%s',%d)\n",p,len);
|
|
parent = &root;
|
|
rover = *parent;
|
|
while (rover != null) // while we haven't run out of tree
|
|
{
|
|
cmp = std.string.cmp(id, rover.Sident);
|
|
if (cmp == 0)
|
|
{
|
|
return rover;
|
|
}
|
|
parent = (cmp < 0) ? /* if we go down left side */
|
|
&(rover.Sl) : /* then get left child */
|
|
&(rover.Sr); /* else get right child */
|
|
rover = *parent; /* get child */
|
|
}
|
|
/* not in table, so insert into table */
|
|
s = cast(Symbol *)trace_malloc(Symbol.sizeof);
|
|
memset(s,0,Symbol.sizeof);
|
|
s.Sident = id;
|
|
*parent = s; // link new symbol into tree
|
|
return s;
|
|
}
|
|
|
|
/***********************************
|
|
* Add symbol s with count to SymPair list.
|
|
*/
|
|
|
|
static void trace_sympair_add(SymPair** psp, Symbol* s, uint count)
|
|
{ SymPair* sp;
|
|
|
|
for (; 1; psp = &sp.next)
|
|
{
|
|
sp = *psp;
|
|
if (!sp)
|
|
{
|
|
sp = cast(SymPair *)trace_malloc(SymPair.sizeof);
|
|
sp.sym = s;
|
|
sp.count = 0;
|
|
sp.next = null;
|
|
*psp = sp;
|
|
break;
|
|
}
|
|
else if (sp.sym == s)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
sp.count += count;
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
//
|
|
|
|
static void trace_pro(char[] id)
|
|
{
|
|
Stack* n;
|
|
Symbol* s;
|
|
timer_t starttime;
|
|
timer_t t;
|
|
|
|
QueryPerformanceCounter(&starttime);
|
|
if (id.length == 0)
|
|
return;
|
|
if (!trace_inited)
|
|
trace_init(); // initialize package
|
|
n = stack_malloc();
|
|
n.prev = trace_tos;
|
|
trace_tos = n;
|
|
s = trace_addsym(id);
|
|
trace_tos.sym = s;
|
|
if (trace_tos.prev)
|
|
{
|
|
Symbol* prev;
|
|
int i;
|
|
|
|
// Accumulate Sfanout and Sfanin
|
|
prev = trace_tos.prev.sym;
|
|
trace_sympair_add(&prev.Sfanout,s,1);
|
|
trace_sympair_add(&s.Sfanin,prev,1);
|
|
}
|
|
QueryPerformanceCounter(&t);
|
|
trace_tos.starttime = starttime;
|
|
trace_tos.ohd = trace_ohd + t - starttime;
|
|
trace_tos.subtime = 0;
|
|
//printf("trace_tos.ohd=%lld, trace_ohd=%lld + t=%lld - starttime=%lld\n",
|
|
// trace_tos.ohd,trace_ohd,t,starttime);
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
//
|
|
|
|
static void trace_epi()
|
|
{ Stack* n;
|
|
timer_t endtime;
|
|
timer_t t;
|
|
timer_t ohd;
|
|
|
|
//printf("trace_epi()\n");
|
|
if (trace_tos)
|
|
{
|
|
timer_t starttime;
|
|
timer_t totaltime;
|
|
|
|
QueryPerformanceCounter(&endtime);
|
|
starttime = trace_tos.starttime;
|
|
totaltime = endtime - starttime - trace_tos.ohd;
|
|
if (totaltime < 0)
|
|
{ //printf("endtime=%lld - starttime=%lld - trace_tos.ohd=%lld < 0\n",
|
|
// endtime,starttime,trace_tos.ohd);
|
|
totaltime = 0; // round off error, just make it 0
|
|
}
|
|
|
|
// totaltime is time spent in this function + all time spent in
|
|
// subfunctions - bookkeeping overhead.
|
|
trace_tos.sym.totaltime += totaltime;
|
|
|
|
//if (totaltime < trace_tos.subtime)
|
|
//printf("totaltime=%lld < trace_tos.subtime=%lld\n",totaltime,trace_tos.subtime);
|
|
trace_tos.sym.functime += totaltime - trace_tos.subtime;
|
|
ohd = trace_tos.ohd;
|
|
n = trace_tos.prev;
|
|
stack_free(trace_tos);
|
|
trace_tos = n;
|
|
if (n)
|
|
{ QueryPerformanceCounter(&t);
|
|
n.ohd += ohd + t - endtime;
|
|
n.subtime += totaltime;
|
|
//printf("n.ohd = %lld\n",n.ohd);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////// FILE INTERFACE /////////////////////////
|
|
|
|
/////////////////////////////////////
|
|
// Read line from file fp.
|
|
// Returns:
|
|
// trace_malloc'd line buffer
|
|
// null if end of file
|
|
|
|
static char* trace_readline(FILE* fp)
|
|
{ int c;
|
|
int dim;
|
|
int i;
|
|
char *buf;
|
|
|
|
//printf("trace_readline(%p)\n", fp);
|
|
i = 0;
|
|
dim = 0;
|
|
buf = null;
|
|
while (1)
|
|
{
|
|
if (i == dim)
|
|
{ char *p;
|
|
|
|
dim += 80;
|
|
p = cast(char *)trace_malloc(dim);
|
|
memcpy(p,buf,i);
|
|
trace_free(buf);
|
|
buf = p;
|
|
}
|
|
c = fgetc(fp);
|
|
switch (c)
|
|
{
|
|
case EOF:
|
|
if (i == 0)
|
|
{ trace_free(buf);
|
|
return null;
|
|
}
|
|
case '\n':
|
|
goto L1;
|
|
default:
|
|
break;
|
|
}
|
|
buf[i] = c;
|
|
i++;
|
|
}
|
|
L1:
|
|
buf[i] = 0;
|
|
//printf("line '%s'\n",buf);
|
|
return buf;
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
// Skip space
|
|
|
|
static char *skipspace(char *p)
|
|
{
|
|
while (std.ctype.isspace(*p))
|
|
p++;
|
|
return p;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Merge in profiling data from existing file.
|
|
|
|
static void trace_merge()
|
|
{ FILE *fp;
|
|
char *buf;
|
|
char *p;
|
|
uint count;
|
|
Symbol *s;
|
|
SymPair *sfanin;
|
|
SymPair **psp;
|
|
|
|
if (trace_logfilename && (fp = fopen(trace_logfilename,"r")) != null)
|
|
{
|
|
buf = null;
|
|
sfanin = null;
|
|
psp = &sfanin;
|
|
while (1)
|
|
{
|
|
trace_free(buf);
|
|
buf = trace_readline(fp);
|
|
if (!buf)
|
|
break;
|
|
switch (*buf)
|
|
{
|
|
case '=': // ignore rest of file
|
|
trace_free(buf);
|
|
goto L1;
|
|
case ' ':
|
|
case '\t': // fan in or fan out line
|
|
count = strtoul(buf,&p,10);
|
|
if (p == buf) // if invalid conversion
|
|
continue;
|
|
p = skipspace(p);
|
|
if (!*p)
|
|
continue;
|
|
s = trace_addsym(p[0 .. strlen(p)]);
|
|
trace_sympair_add(psp,s,count);
|
|
break;
|
|
default:
|
|
if (!isalpha(*buf))
|
|
{
|
|
if (!sfanin)
|
|
psp = &sfanin;
|
|
continue; // regard unrecognized line as separator
|
|
}
|
|
case '?':
|
|
case '_':
|
|
case '$':
|
|
case '@':
|
|
p = buf;
|
|
while (std.ctype.isgraph(*p))
|
|
p++;
|
|
*p = 0;
|
|
//printf("trace_addsym('%s')\n",buf);
|
|
s = trace_addsym(buf[0 .. strlen(buf)]);
|
|
if (s.Sfanin)
|
|
{ SymPair *sp;
|
|
|
|
for (; sfanin; sfanin = sp)
|
|
{
|
|
trace_sympair_add(&s.Sfanin,sfanin.sym,sfanin.count);
|
|
sp = sfanin.next;
|
|
trace_free(sfanin);
|
|
}
|
|
}
|
|
else
|
|
{ s.Sfanin = sfanin;
|
|
}
|
|
sfanin = null;
|
|
psp = &s.Sfanout;
|
|
|
|
{ timer_t t;
|
|
|
|
p++;
|
|
count = strtoul(p,&p,10);
|
|
t = strtoull(p,&p,10);
|
|
s.totaltime += t;
|
|
t = strtoull(p,&p,10);
|
|
s.functime += t;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
L1:
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
////////////////////////// COMPILER INTERFACE /////////////////////
|
|
|
|
/////////////////////////////////////////////
|
|
// Function called by trace code in function prolog.
|
|
|
|
void _trace_pro_n()
|
|
{
|
|
/* Length of string is either:
|
|
* db length
|
|
* ascii string
|
|
* or:
|
|
* db 0x0FF
|
|
* db 0
|
|
* dw length
|
|
* ascii string
|
|
*/
|
|
|
|
asm
|
|
{ naked ;
|
|
pushad ;
|
|
mov ECX,8*4[ESP] ;
|
|
xor EAX,EAX ;
|
|
mov AL,[ECX] ;
|
|
cmp AL,0xFF ;
|
|
jne L1 ;
|
|
cmp byte ptr 1[ECX],0 ;
|
|
jne L1 ;
|
|
mov AX,2[ECX] ;
|
|
add 8*4[ESP],3 ;
|
|
add ECX,3 ;
|
|
L1: inc EAX ;
|
|
inc ECX ;
|
|
add 8*4[ESP],EAX ;
|
|
dec EAX ;
|
|
push ECX ;
|
|
push EAX ;
|
|
call trace_pro ;
|
|
add ESP,8 ;
|
|
popad ;
|
|
ret ;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
// Function called by trace code in function epilog.
|
|
|
|
|
|
void _trace_epi_n()
|
|
{
|
|
asm
|
|
{ naked ;
|
|
pushad ;
|
|
}
|
|
trace_epi();
|
|
asm
|
|
{
|
|
popad ;
|
|
ret ;
|
|
}
|
|
}
|
|
|
|
|
|
version (Win32)
|
|
{
|
|
extern (Windows)
|
|
{
|
|
export int QueryPerformanceCounter(timer_t *);
|
|
export int QueryPerformanceFrequency(timer_t *);
|
|
}
|
|
}
|
|
else version (X86)
|
|
{
|
|
extern (D)
|
|
{
|
|
void QueryPerformanceCounter(timer_t* ctr)
|
|
{
|
|
asm
|
|
{ naked ;
|
|
mov ECX,EAX ;
|
|
rdtsc ;
|
|
mov [ECX],EAX ;
|
|
mov 4[ECX],EDX ;
|
|
ret ;
|
|
}
|
|
}
|
|
|
|
void QueryPerformanceFrequency(timer_t* freq)
|
|
{
|
|
*freq = 3579545;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static assert(0);
|
|
}
|