(struct bb): Add flags field.
(HAVE_POPEN): Test new define. (struct __bb, struct bb_{edge,func}): New structs. (__bb_init_{prg,file},__bb_{init,exit}_trace_func,__bb_trace_ret, (__bb_trace_func{,_ret},gopen,gclose): New functions. From-SVN: r10850
This commit is contained in:
parent
47431dff3c
commit
90b4a76470
734
gcc/libgcc2.c
734
gcc/libgcc2.c
@ -1450,6 +1450,7 @@ struct bb
|
||||
const char **functions;
|
||||
const long *line_nums;
|
||||
const char **filenames;
|
||||
char *flags;
|
||||
};
|
||||
|
||||
#ifdef BLOCK_PROFILER_CODE
|
||||
@ -1513,11 +1514,11 @@ __bb_exit_func (void)
|
||||
|
||||
/* This is somewhat type incorrect, but it avoids worrying about
|
||||
exactly where time.h is included from. It should be ok unless
|
||||
a void * differs from other pointer formats, or if sizeof(long)
|
||||
a void * differs from other pointer formats, or if sizeof (long)
|
||||
is < sizeof (time_t). It would be nice if we could assume the
|
||||
use of rationale standards here. */
|
||||
|
||||
time((void *) &time_value);
|
||||
time ((void *) &time_value);
|
||||
fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
|
||||
|
||||
/* We check the length field explicitly in order to allow compatibility
|
||||
@ -1632,6 +1633,735 @@ __bb_init_func (struct bb *blocks)
|
||||
bb_head = blocks;
|
||||
}
|
||||
|
||||
#ifndef MACHINE_STATE_SAVE
|
||||
#define MACHINE_STATE_SAVE(ID)
|
||||
#endif
|
||||
#ifndef MACHINE_STATE_RESTORE
|
||||
#define MACHINE_STATE_RESTORE(ID)
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Number of buckets in hashtable of basic block addresses. */
|
||||
|
||||
#define BB_BUCKETS 311
|
||||
|
||||
/* Maximum length of string in file bb.in. */
|
||||
|
||||
#define BBINBUFSIZE 500
|
||||
|
||||
/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
|
||||
"BBINBUFSIZE" but want to avoid trouble with preprocessors. */
|
||||
|
||||
#define BBINBUFSIZESTR "499"
|
||||
|
||||
struct bb_edge
|
||||
{
|
||||
struct bb_edge *next;
|
||||
unsigned long src_addr;
|
||||
unsigned long dst_addr;
|
||||
unsigned long count;
|
||||
};
|
||||
|
||||
enum bb_func_mode
|
||||
{
|
||||
TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
|
||||
};
|
||||
|
||||
struct bb_func
|
||||
{
|
||||
struct bb_func *next;
|
||||
char *funcname;
|
||||
char *filename;
|
||||
enum bb_func_mode mode;
|
||||
};
|
||||
|
||||
/* This is the connection to the outside world.
|
||||
The BLOCK_PROFILER macro must set __bb.blocks
|
||||
and __bb.blockno. */
|
||||
|
||||
struct {
|
||||
unsigned long blockno;
|
||||
struct bb *blocks;
|
||||
} __bb;
|
||||
|
||||
/* Vars to store addrs of source and destination basic blocks
|
||||
of a jump. */
|
||||
|
||||
static unsigned long bb_src = 0;
|
||||
static unsigned long bb_dst = 0;
|
||||
|
||||
static FILE *bb_tracefile = (FILE*)0;
|
||||
static struct bb_edge **bb_hashbuckets = (struct bb_edge**)0;
|
||||
static struct bb_func *bb_func_head = (struct bb_func*)0;
|
||||
static unsigned long bb_callcount = 0;
|
||||
static int bb_mode = 0;
|
||||
|
||||
static unsigned long *bb_stack = (unsigned long *)0;
|
||||
static size_t bb_stacksize = 0;
|
||||
|
||||
static int reported = 0;
|
||||
|
||||
/* Trace modes:
|
||||
Always : Print execution frequencies of basic blocks
|
||||
to file bb.out.
|
||||
bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
|
||||
bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
|
||||
bb_mode & 4 != 0 : Cut call instructions from basic block flow.
|
||||
bb_mode & 8 != 0 : Insert return instructions in basic block flow.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_POPEN
|
||||
|
||||
/*#include <sys/types.h>*/
|
||||
#include <sys/stat.h>
|
||||
/*#include <malloc.h>*/
|
||||
|
||||
/* Commands executed by gopen. */
|
||||
|
||||
#define GOPENDECOMPRESS "gzip -cd "
|
||||
#define GOPENCOMPRESS "gzip -c >"
|
||||
|
||||
/* Like fopen but pipes through gzip. mode may only be "r" or "w".
|
||||
If it does not compile, simply replace gopen by fopen and delete
|
||||
'.gz' from any first parameter to gopen. */
|
||||
|
||||
static FILE *
|
||||
gopen (fn, mode)
|
||||
char *fn;
|
||||
char *mode;
|
||||
{
|
||||
int use_gzip;
|
||||
char *p;
|
||||
|
||||
if (mode[1])
|
||||
return (FILE*)0;
|
||||
|
||||
if (mode[0] != 'r' && mode[0] != 'w')
|
||||
return (FILE*)0;
|
||||
|
||||
p = fn + strlen (fn)-1;
|
||||
use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z')) ||
|
||||
(p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
|
||||
|
||||
if (use_gzip)
|
||||
{
|
||||
if (mode[0]=='r')
|
||||
{
|
||||
FILE *f;
|
||||
char *s = (char*) malloc (sizeof (char) * strlen (fn)
|
||||
+ sizeof (GOPENDECOMPRESS));
|
||||
strcpy (s, GOPENDECOMPRESS);
|
||||
strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
|
||||
f = popen (s, mode);
|
||||
free (s);
|
||||
return f;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FILE *f;
|
||||
char *s = (char*) malloc (sizeof (char) * strlen (fn)
|
||||
+ sizeof (GOPENCOMPRESS));
|
||||
strcpy (s, GOPENCOMPRESS);
|
||||
strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
|
||||
if (!(f = popen (s, mode)))
|
||||
f = fopen (s, mode);
|
||||
free (s);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
return fopen (fn, mode);
|
||||
}
|
||||
|
||||
static int
|
||||
gclose (f)
|
||||
FILE *f;
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (f != NULL)
|
||||
{
|
||||
if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
|
||||
return pclose (f);
|
||||
|
||||
return fclose (f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_POPEN */
|
||||
|
||||
/* Called once per program. */
|
||||
|
||||
static void
|
||||
__bb_exit_trace_func ()
|
||||
{
|
||||
FILE *file = fopen ("bb.out", "a");
|
||||
struct bb_func *f;
|
||||
struct bb_edge *e;
|
||||
struct bb *b;
|
||||
|
||||
if (!file)
|
||||
perror ("bb.out");
|
||||
|
||||
if (bb_mode & 1)
|
||||
{
|
||||
if (!bb_tracefile)
|
||||
perror ("bbtrace");
|
||||
else
|
||||
#ifdef HAVE_POPEN
|
||||
gclose (bb_tracefile);
|
||||
#else
|
||||
fclose (bb_tracefile);
|
||||
#endif /* HAVE_POPEN */
|
||||
}
|
||||
|
||||
/* Check functions in `bb.in'. */
|
||||
|
||||
if (file)
|
||||
{
|
||||
long time_value;
|
||||
const struct bb_func *p;
|
||||
int printed_something = 0;
|
||||
struct bb *ptr;
|
||||
long blk;
|
||||
|
||||
/* This is somewhat type incorrect. */
|
||||
time ((void *) &time_value);
|
||||
|
||||
for (p = bb_func_head; p != (struct bb_func *)0; p = p->next)
|
||||
{
|
||||
for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next)
|
||||
{
|
||||
if (!ptr->filename || p->filename != (char *)0 && strcmp (p->filename, ptr->filename))
|
||||
continue;
|
||||
for (blk = 0; blk < ptr->ncounts; blk++)
|
||||
{
|
||||
if (!strcmp (p->funcname, ptr->functions[blk]))
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!printed_something)
|
||||
{
|
||||
fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
|
||||
printed_something = 1;
|
||||
}
|
||||
|
||||
fprintf (file, "\tFunction %s", p->funcname);
|
||||
if (p->filename)
|
||||
fprintf (file, " of file %s", p->filename);
|
||||
fprintf (file, "\n" );
|
||||
|
||||
found: ;
|
||||
}
|
||||
|
||||
if (printed_something)
|
||||
fprintf (file, "\n");
|
||||
|
||||
}
|
||||
|
||||
if (bb_mode & 2)
|
||||
{
|
||||
if (!bb_hashbuckets)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf (stderr, "Profiler: out of memory\n");
|
||||
reported = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
else if (file)
|
||||
{
|
||||
long time_value;
|
||||
int i;
|
||||
unsigned long addr_max = 0;
|
||||
unsigned long cnt_max = 0;
|
||||
int cnt_len;
|
||||
int addr_len;
|
||||
|
||||
/* This is somewhat type incorrect, but it avoids worrying about
|
||||
exactly where time.h is included from. It should be ok unless
|
||||
a void * differs from other pointer formats, or if sizeof (long)
|
||||
is < sizeof (time_t). It would be nice if we could assume the
|
||||
use of rationale standards here. */
|
||||
|
||||
time ((void *) &time_value);
|
||||
fprintf (file, "Basic block jump tracing");
|
||||
|
||||
switch (bb_mode & 12)
|
||||
{
|
||||
case 0:
|
||||
fprintf (file, " (with call)");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
/* Print nothing. */
|
||||
break;
|
||||
|
||||
case 8:
|
||||
fprintf (file, " (with call & ret)");
|
||||
break;
|
||||
|
||||
case 12:
|
||||
fprintf (file, " (with ret)");
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
|
||||
|
||||
for (i = 0; i < BB_BUCKETS; i++)
|
||||
{
|
||||
struct bb_edge *bucket = bb_hashbuckets[i];
|
||||
for ( ; bucket; bucket = bucket->next )
|
||||
{
|
||||
if (addr_max < bucket->src_addr)
|
||||
addr_max = bucket->src_addr;
|
||||
if (addr_max < bucket->dst_addr)
|
||||
addr_max = bucket->dst_addr;
|
||||
if (cnt_max < bucket->count)
|
||||
cnt_max = bucket->count;
|
||||
}
|
||||
}
|
||||
addr_len = num_digits (addr_max, 16);
|
||||
cnt_len = num_digits (cnt_max, 10);
|
||||
|
||||
for ( i = 0; i < BB_BUCKETS; i++)
|
||||
{
|
||||
struct bb_edge *bucket = bb_hashbuckets[i];
|
||||
for ( ; bucket; bucket = bucket->next )
|
||||
{
|
||||
fprintf (file, "Jump from block 0x%.*lx to "
|
||||
"block 0x%.*lx executed %*d time(s)\n",
|
||||
addr_len, bucket->src_addr,
|
||||
addr_len, bucket->dst_addr,
|
||||
cnt_len, bucket->count);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf (file, "\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (file)
|
||||
fclose (file);
|
||||
|
||||
/* Free allocated memory. */
|
||||
|
||||
f = bb_func_head;
|
||||
while (f)
|
||||
{
|
||||
struct bb_func *old = f;
|
||||
|
||||
f = f->next;
|
||||
if (old->funcname) free (old->funcname);
|
||||
if (old->filename) free (old->filename);
|
||||
free (old);
|
||||
}
|
||||
|
||||
if (bb_stack)
|
||||
free (bb_stack);
|
||||
|
||||
if (bb_hashbuckets)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BB_BUCKETS; i++)
|
||||
{
|
||||
struct bb_edge *old, *bucket = bb_hashbuckets[i];
|
||||
|
||||
while (bucket)
|
||||
{
|
||||
old = bucket;
|
||||
bucket = bucket->next;
|
||||
free (old);
|
||||
}
|
||||
}
|
||||
free (bb_hashbuckets);
|
||||
}
|
||||
|
||||
for (b = bb_head; b; b = b->next)
|
||||
if (b->flags) free (b->flags);
|
||||
}
|
||||
|
||||
/* Called once per program. */
|
||||
|
||||
static void
|
||||
__bb_init_prg ()
|
||||
{
|
||||
|
||||
FILE *file;
|
||||
char buf[BBINBUFSIZE];
|
||||
const char *p;
|
||||
const char *pos;
|
||||
enum bb_func_mode m;
|
||||
|
||||
#ifdef ON_EXIT
|
||||
/* Initialize destructor. */
|
||||
ON_EXIT (__bb_exit_func, 0);
|
||||
#endif
|
||||
|
||||
if (!(file = fopen ("bb.in", "r")))
|
||||
return;
|
||||
|
||||
while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
|
||||
{
|
||||
p = buf;
|
||||
if (*p == '-')
|
||||
{
|
||||
m = TRACE_OFF;
|
||||
p++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = TRACE_ON;
|
||||
}
|
||||
if (!strcmp (p, "__bb_trace__"))
|
||||
bb_mode |= 1;
|
||||
else if (!strcmp (p, "__bb_jumps__"))
|
||||
bb_mode |= 2;
|
||||
else if (!strcmp (p, "__bb_hidecall__"))
|
||||
bb_mode |= 4;
|
||||
else if (!strcmp (p, "__bb_showret__"))
|
||||
bb_mode |= 8;
|
||||
else
|
||||
{
|
||||
struct bb_func *f = (struct bb_func*) malloc (sizeof (struct bb_func));
|
||||
if (f)
|
||||
{
|
||||
unsigned long l;
|
||||
f->next = bb_func_head;
|
||||
if (pos = strchr (p, ':'))
|
||||
{
|
||||
if (!(f->funcname = (char*) malloc (strlen (pos+1)+1)))
|
||||
continue;
|
||||
strcpy (f->funcname, pos+1);
|
||||
l = pos-p;
|
||||
if ((f->filename = (char*) malloc (l+1)))
|
||||
{
|
||||
strncpy (f->filename, p, l);
|
||||
f->filename[l] = '\0';
|
||||
}
|
||||
else
|
||||
f->filename = (char*)0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(f->funcname = (char*) malloc (strlen (p)+1)))
|
||||
continue;
|
||||
strcpy (f->funcname, p);
|
||||
f->filename = (char*)0;
|
||||
}
|
||||
f->mode = m;
|
||||
bb_func_head = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose (file);
|
||||
|
||||
#ifdef HAVE_POPEN
|
||||
|
||||
if (bb_mode & 1)
|
||||
bb_tracefile = gopen ("bbtrace.gz", "w");
|
||||
|
||||
#else
|
||||
|
||||
if (bb_mode & 1)
|
||||
bb_tracefile = fopen ("bbtrace", "w");
|
||||
|
||||
#endif /* HAVE_POPEN */
|
||||
|
||||
if (bb_mode & 2)
|
||||
{
|
||||
bb_hashbuckets = (struct bb_edge **)
|
||||
malloc (BB_BUCKETS * sizeof (struct bb_edge *));
|
||||
if (bb_hashbuckets)
|
||||
bzero (bb_hashbuckets, BB_BUCKETS);
|
||||
}
|
||||
|
||||
if (bb_mode & 12)
|
||||
{
|
||||
bb_stacksize = 10;
|
||||
bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
|
||||
}
|
||||
|
||||
#ifdef ON_EXIT
|
||||
/* Initialize destructor. */
|
||||
ON_EXIT (__bb_exit_trace_func, 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Called upon entering a basic block. */
|
||||
|
||||
void
|
||||
__bb_trace_func ()
|
||||
{
|
||||
struct bb_edge *bucket;
|
||||
|
||||
MACHINE_STATE_SAVE("1")
|
||||
|
||||
if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
|
||||
goto skip;
|
||||
|
||||
bb_dst = __bb.blocks->addresses[__bb.blockno];
|
||||
__bb.blocks->counts[__bb.blockno]++;
|
||||
|
||||
if (bb_tracefile)
|
||||
{
|
||||
fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
|
||||
}
|
||||
|
||||
if (bb_hashbuckets)
|
||||
{
|
||||
struct bb_edge **startbucket, **oldnext;
|
||||
|
||||
oldnext = startbucket =
|
||||
& bb_hashbuckets[ (((int)bb_src*8)^(int)bb_dst) % BB_BUCKETS ];
|
||||
bucket = *startbucket;
|
||||
|
||||
for (bucket = *startbucket; bucket;
|
||||
oldnext = &(bucket->next), bucket = *oldnext)
|
||||
{
|
||||
if ( bucket->src_addr == bb_src &&
|
||||
bucket->dst_addr == bb_dst )
|
||||
{
|
||||
bucket->count++;
|
||||
*oldnext = bucket->next;
|
||||
bucket->next = *startbucket;
|
||||
*startbucket = bucket;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
|
||||
bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
|
||||
|
||||
if (!bucket)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf (stderr, "Profiler: out of memory\n");
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
bucket->src_addr = bb_src;
|
||||
bucket->dst_addr = bb_dst;
|
||||
bucket->next = *startbucket;
|
||||
*startbucket = bucket;
|
||||
bucket->count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret:
|
||||
bb_src = bb_dst;
|
||||
|
||||
skip:
|
||||
;
|
||||
|
||||
MACHINE_STATE_RESTORE("1")
|
||||
|
||||
}
|
||||
|
||||
/* Called when returning from a function and `__bb_showret__' is set. */
|
||||
|
||||
static void
|
||||
__bb_trace_func_ret ()
|
||||
{
|
||||
struct bb_edge *bucket;
|
||||
|
||||
if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
|
||||
goto skip;
|
||||
|
||||
if (bb_hashbuckets)
|
||||
{
|
||||
struct bb_edge **startbucket, **oldnext;
|
||||
|
||||
oldnext = startbucket =
|
||||
& bb_hashbuckets[ (((int)bb_dst*8)^(int)bb_src) % BB_BUCKETS ];
|
||||
bucket = *startbucket;
|
||||
|
||||
for (bucket = *startbucket; bucket;
|
||||
oldnext = &(bucket->next), bucket = *oldnext)
|
||||
{
|
||||
if ( bucket->src_addr == bb_dst &&
|
||||
bucket->dst_addr == bb_src )
|
||||
{
|
||||
bucket->count++;
|
||||
*oldnext = bucket->next;
|
||||
bucket->next = *startbucket;
|
||||
*startbucket = bucket;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
|
||||
bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
|
||||
|
||||
if (!bucket)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf (stderr, "Profiler: out of memory\n");
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
bucket->src_addr = bb_dst;
|
||||
bucket->dst_addr = bb_src;
|
||||
bucket->next = *startbucket;
|
||||
*startbucket = bucket;
|
||||
bucket->count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret:
|
||||
bb_dst = bb_src;
|
||||
|
||||
skip:
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
/* Called upon entering the first function of a file. */
|
||||
|
||||
static void
|
||||
__bb_init_file (blocks)
|
||||
struct bb *blocks;
|
||||
{
|
||||
|
||||
const struct bb_func *p;
|
||||
long blk, ncounts = blocks->ncounts;
|
||||
const char **functions = blocks->functions;
|
||||
|
||||
/* Set up linked list. */
|
||||
blocks->zero_word = 1;
|
||||
blocks->next = bb_head;
|
||||
bb_head = blocks;
|
||||
|
||||
blocks->flags = 0;
|
||||
if (!bb_func_head ||
|
||||
!(blocks->flags = (char*) malloc (sizeof (char) * blocks->ncounts)))
|
||||
return;
|
||||
|
||||
for (blk = 0; blk < ncounts; blk++)
|
||||
blocks->flags[blk] = 0;
|
||||
|
||||
for (blk = 0; blk < ncounts; blk++)
|
||||
{
|
||||
for (p = bb_func_head; p; p = p->next)
|
||||
{
|
||||
if (!strcmp (p->funcname, functions[blk]) &&
|
||||
(!p->filename || !strcmp (p->filename, blocks->filename)))
|
||||
{
|
||||
blocks->flags[blk] |= p->mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Called when exiting from a function. */
|
||||
|
||||
void
|
||||
__bb_trace_ret ()
|
||||
{
|
||||
|
||||
MACHINE_STATE_SAVE("2")
|
||||
|
||||
if (bb_callcount)
|
||||
{
|
||||
if ((bb_mode & 12) && bb_stacksize > bb_callcount)
|
||||
{
|
||||
bb_src = bb_stack[bb_callcount];
|
||||
if (bb_mode & 8)
|
||||
__bb_trace_func_ret ();
|
||||
}
|
||||
|
||||
bb_callcount -= 1;
|
||||
}
|
||||
|
||||
MACHINE_STATE_RESTORE("2")
|
||||
|
||||
}
|
||||
|
||||
/* Called when entering a function. */
|
||||
|
||||
void
|
||||
__bb_init_trace_func (blocks, blockno)
|
||||
struct bb *blocks;
|
||||
unsigned long blockno;
|
||||
{
|
||||
static int trace_init = 0;
|
||||
|
||||
MACHINE_STATE_SAVE("3")
|
||||
|
||||
if (!blocks->zero_word)
|
||||
{
|
||||
if (!trace_init)
|
||||
{
|
||||
trace_init = 1;
|
||||
__bb_init_prg ();
|
||||
}
|
||||
__bb_init_file (blocks);
|
||||
}
|
||||
|
||||
if (bb_callcount)
|
||||
{
|
||||
|
||||
bb_callcount += 1;
|
||||
|
||||
if (bb_mode & 12)
|
||||
{
|
||||
if (bb_callcount >= bb_stacksize)
|
||||
{
|
||||
size_t newsize = bb_callcount + 100;
|
||||
|
||||
bb_stack = (unsigned long *) realloc (bb_stack, newsize);
|
||||
if (! bb_stack)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf (stderr, "Profiler: out of memory\n");
|
||||
reported = 1;
|
||||
}
|
||||
bb_stacksize = 0;
|
||||
goto stack_overflow;
|
||||
}
|
||||
bb_stacksize = newsize;
|
||||
}
|
||||
bb_stack[bb_callcount] = bb_src;
|
||||
|
||||
if (bb_mode & 4)
|
||||
bb_src = 0;
|
||||
|
||||
}
|
||||
|
||||
stack_overflow:;
|
||||
|
||||
}
|
||||
|
||||
else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
|
||||
{
|
||||
bb_callcount = 1;
|
||||
bb_src = 0;
|
||||
|
||||
if (bb_stack)
|
||||
bb_stack[bb_callcount] = bb_src;
|
||||
}
|
||||
|
||||
MACHINE_STATE_RESTORE("3")
|
||||
}
|
||||
|
||||
#endif /* not inhibit_libc */
|
||||
#endif /* not BLOCK_PROFILER_CODE */
|
||||
#endif /* L_bb */
|
||||
|
Loading…
Reference in New Issue
Block a user