📄 nios_gprof.c
字号:
asm(".global nios_mcount
nios_mcount:
mov %o1,%i7
mov %o0,%o7
save %sp,-23
mov %o0,%i0
mov %o1,%i1
pfx %hi(internal_mcount@h)
movi %o2, %lo(internal_mcount@h)
"
#ifdef __nios32__
"pfx %xhi(internal_mcount@h)
movhi %o2, %xlo(internal_mcount@h)
"
#endif
"call %o2
nop
restore
jmp %o7
nop
");
/*
* Parameters are the return address for mcount,
* and the return address for mcount's caller.
*/
static void internal_mcount(selfpc, frompcindex)
register char *selfpc;
register unsigned short *frompcindex;
{
register struct tostruct *top;
register struct tostruct *prevtop;
register long toindex;
static char already_setup;
/* A little error checking first: if the stack pointer is below the
data, then we corrupted data and all bets are off:
*/
long a, b;
int x;
a = PTR2LONG (sbrk (0));
b = PTR2LONG (&x);
if ( a > b) {
printf("Error - stack underflow - memory corruption\n !!");
printf("End of data = 0x%08lx , Stack = 0x%08lx \n", (long) a, (long) b);
}
/* CBV - the frompcindex and selfpc addresses are currently divided
by 2. So, in order to bring them back in sync with the rest
of the code, I must make them from jump adddresses to absolute
addresses.
*/
frompcindex = (unsigned short *) (2 * ((unsigned int) frompcindex));
selfpc = (unsigned char *) (2 * ((unsigned int) selfpc));
if(!already_setup) {
extern char etext[];
already_setup = 1;
monstartup((char *)(unsigned int) nasys_program_mem,
(char *)((unsigned int) etext));
/* CBV - We don't have the operating system on_exit */
/* call, so force it to use at_exit. */
/*#ifdef USE_ONEXIT */
/* on_exit(_mcleanup, 0); */
/*#else */
atexit(_mcleanup);
/*#endif */
}
/*
* check that we are profiling
* and that we aren't recursively invoked.
*/
if (profiling) {
goto out;
}
profiling++;
/*
* check that frompcindex is a reasonable pc value.
* for example: signal catchers get called from the stack,
* not from text space. too bad.
*/
frompcindex = (unsigned short *)(((unsigned int) frompcindex) -
((unsigned int) s_lowpc));
if ((unsigned int)frompcindex > s_textsize) {
goto done;
}
frompcindex = (unsigned short *) ((unsigned int) &froms[
((unsigned int) frompcindex) /
(unsigned int) (HASHFRACTION * sizeof(*froms))]);
toindex = PTR2LONG (*frompcindex);
if (((unsigned int) toindex) == 0) {
/*
* first time traversing this arc
*/
toindex = ++tos[0].link;
if (toindex >= tolimit) {
goto overflow;
}
*frompcindex = (unsigned short) toindex;
top = &tos[toindex];
top->selfpc = selfpc;
top->count = 1;
top->link = 0;
goto done;
}
top = &tos[toindex];
if (top->selfpc == selfpc) {
/*
* arc at front of chain; usual case.
*/
top->count++;
goto done;
}
/*
* have to go looking down chain for it.
* top points to what we are looking at,
* prevtop points to previous top.
* we know it is not at the head of the chain.
*/
for (; /* goto done */; ) {
if (top->link == 0) {
/*
* top is end of the chain and none of the chain
* had top->selfpc == selfpc.
* so we allocate a new tostruct
* and link it to the head of the chain.
*/
toindex = ++tos[0].link;
if (toindex >= tolimit) {
goto overflow;
}
top = &tos[toindex];
top->selfpc = selfpc;
top->count = 1;
top->link = *frompcindex;
*frompcindex = (unsigned short) toindex;
goto done;
}
/*
* otherwise, check the next arc on the chain.
*/
prevtop = top;
top = &tos[top->link];
if (top->selfpc == selfpc) {
/*
* there it is.
* increment its count
* move it to the head of the chain.
*/
top->count++;
toindex = prevtop->link;
prevtop->link = top->link;
top->link = *frompcindex;
*frompcindex = (unsigned short) toindex;
goto done;
}
}
done:
profiling--;
/* and fall through */
out:
return; /* normal return restores saved registers */
overflow:
profiling++; /* halt further profiling */
# define TOLIMIT "mcount: tos overflow\n"
nios_write(2, TOLIMIT, sizeof(TOLIMIT));
goto out;
}
/*
* Control profiling
* profiling is what mcount checks to see if
* all the data structures are ready.
*/
static void moncontrol(mode)
int mode;
{
if (mode) {
/* start */
nios_profil((unsigned short *)(sbuf + sizeof(struct phdr)),
(unsigned long)(ssiz - sizeof(struct phdr)),
(unsigned long)((unsigned int)s_lowpc), s_scale);
profiling = 0;
} else {
/* stop */
nios_profil((unsigned short *)0, 0L, 0L, 0L);
profiling = 3;
}
}
void nios_write (int stream, char *msg, int size_of_message)
{
int i;
for(i = 0; i < size_of_message; i++) {
if((i & 0x000f) == 0) {
printf("\n### "); /* 3 #'s for convert program */
}
printf("%02x ",msg[i] & 0x000000ff);
}
printf("*\n");
}
/*
* start or stop profiling
*
* profiling goes into the SAMPLES buffer of size SIZE (which is treated
* as an array of unsigned shorts of size size/2)
*
* each bin represents a range of pc addresses from OFFSET. The number
* of pc addresses in a bin depends on SCALE. (A scale of 65536 maps
* each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
* a scale of 1 maps each bin to 128k addreses). Scale may be 1 - 65536,
* or zero to turn off profiling
*/
void
nios_profile_ctl (struct profinfo * p, char *samples, unsigned long size,
unsigned long offset, long scale)
{
unsigned long maxbin;
if (scale > 65536) {
printf ("Error - scale factor overflow!!! \n");
}
profile_off (p);
if (scale) {
memset (samples, 0, size);
memset (p, 0, sizeof *p);
maxbin = size >> 1;
prof.counter = (unsigned short *) samples;
prof.lowpc = offset;
prof.highpc = PROFADDR (maxbin, offset, scale);
prof.scale = scale;
profile_on (p);
}
}
/* Equivalent to unix profil()
Every SLEEPTIME interval, the user's program counter (PC) is examined:
offset is subtracted and the result is multiplied by scale.
The word pointed to by this address is incremented. Buf is unused. */
void
nios_profil (unsigned short *bigbuffer, unsigned long buff_size,
unsigned long base, long buf_scale)
{
nios_profile_ctl (&prof, (char *) bigbuffer, buff_size, base, buf_scale);
}
void profile_off (struct profinfo *p)
{
/* Disable the timer */
DoDisableTimerInterrupt();
}
#ifndef na_timer1 /* If the timer is not defined, stubb out timer funcs */
void profile_on (struct profinfo *p)
{
printf("\n\n---->> WARNING!!! na_timer1 NOT defined. The");
printf(" output generated by nios_gprof will NOT contain");
printf(" any usefull information!!!");
}
void nios_prof_hdr_timer_ISR(int context, int irq_number, int interruptee)
{}
static void DoEnableTimerInterrupt(void)
{}
static void DoDisableTimerInterrupt(void)
{}
#else
void profile_on (struct profinfo *p)
{
np_timer *timer = na_timer1;
long timerPeriod = nasys_clock_freq / TIMER_SAMPLE_RATE;
timer->np_timerperiodh = timerPeriod >> 16;
timer->np_timerperiodl = timerPeriod & 0xffff;
timer->np_timercontrol = np_timercontrol_start_mask |
np_timercontrol_cont_mask;
DoEnableTimerInterrupt();
}
typedef struct
{
long interruptCount; // increment with each interrupt
np_timer *timer;
} TimerISRContext;
static TimerISRContext gC = {0,0};
void nios_prof_hdr_timer_ISR(int context,int irq_number, int interruptee)
{
struct profinfo *p = (struct profinfo *) &prof;
unsigned int pc, idx;
TimerISRContext *c;
long a, b;
int x;
a = PTR2LONG (sbrk (0));
b = PTR2LONG (&x);
if (a > b) {
printf("Error - stack underflow - memory corruption\n !!");
printf("End of data = 0x%08lx , Stack = 0x%08lx \n",(long) a, (long) b);
}
c = (TimerISRContext *)context;
c->interruptCount++;
/* first, we must get the PC from the return address before the interrupt */
pc = 2 * interruptee; /* Convert return address into absolute address */
/* Now increment the appropriate counter slot: */
if (pc >= p->lowpc && pc < p->highpc)
{
idx = PROFIDX (pc, p->lowpc, p->scale);
p->counter[idx]++;
}
c->timer->np_timerstatus = 0; // write anything to clear the IRQ
}
// Turn on interrupts: enable interrupt bit, and
// install a user ISR
static void DoEnableTimerInterrupt(void)
{
gC.timer = na_timer1;
nr_installuserisr2(na_timer1_irq,(nios_isrhandlerproc2)nios_prof_hdr_timer_ISR, (unsigned int)&gC);
gC.timer->np_timercontrol = gC.timer->np_timercontrol |
np_timercontrol_ito_mask;
}
static void DoDisableTimerInterrupt(void)
{
gC.timer = na_timer1;
nr_installuserisr2(na_timer1_irq,0,0);
gC.timer->np_timercontrol = gC.timer->np_timercontrol &
~np_timercontrol_ito_mask;
}
#endif /* na_timer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -