Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

235 lines
6.2 KiB
C

#ifndef lint
static char sccsid[] = "@(#)gmon.c 1.1 92/07/30 SMI";
#endif
#ifdef DEBUG
#include <stdio.h>
#endif DEBUG
/*
* Environment variable PROFDIR added such that:
* If PROFDIR doesn't exist, "gmon.out" is produced as before.
* If PROFDIR = NULL, no profiling output is produced.
* If PROFDIR = string, "string/pid.progname" is produced,
* where name consists of argv[0] suitably massaged.
*/
#include <sys/param.h>
#include <sys/dir.h>
#include "gmon.h"
#define PROFDIR "PROFDIR"
extern int creat(), write(), close(), getpid();
extern void profil(), perror();
extern char *getenv(), *strcpy(), *strrchr();
void monitor(), moncontrol();
char **___Argv = NULL; /* initialized to argv array by mcrt0 (if loaded) */
/*
* froms is actually a bunch of unsigned shorts indexing tos
*/
extern char profiling;
static unsigned short *froms;
static struct tostruct *tos = 0;
static long tolimit = 0;
static int s_lowpc = 0;
static char *s_highpc = 0;
static unsigned long s_textsize = 0;
static int s_scale;
/* see profil(2) where this is described (incorrectly) */
#define SCALE_1_TO_1 0x10000L
static int ssiz;
static int *sbuf;
#define MSG "No space for monitor buffer(s)\n"
static char gmon_out[MAXPATHLEN];
static char progname[MAXNAMLEN];
monstartup(lowpc, highpc)
char *lowpc;
char *highpc;
{
int monsize, fromsize, tosize;
char *buffer;
char *_alloc_profil_buf();
/*
* round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
*/
lowpc = (char *)
ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
s_lowpc = (int) lowpc;
highpc = (char *)
ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
s_highpc = highpc;
s_textsize = highpc - lowpc;
monsize = ROUNDUP((s_textsize / HISTFRACTION) + sizeof(struct phdr), sizeof(long));
fromsize = ROUNDUP(s_textsize / HASHFRACTION, sizeof(long));
tolimit = s_textsize * ARCDENSITY / 100;
if ( tolimit < MINARCS ) {
tolimit = MINARCS;
} else if ( tolimit > 65534 ) {
tolimit = 65534;
}
tosize = ROUNDUP( tolimit * sizeof( struct tostruct ), sizeof(long) );
buffer = _alloc_profil_buf(monsize+fromsize+tosize);
if(buffer == (char*) -1) {
write( 2 , MSG , sizeof(MSG) );
froms = 0;
tos = 0;
return;
}
froms = (unsigned short*) (buffer + monsize);
tos = (struct tostruct*) (buffer + monsize + fromsize);
tos[0].link = 0;
monitor( lowpc , highpc , buffer , monsize , tolimit );
}
_mcleanup()
{
int fd;
int fromindex;
int endfrom;
int frompc;
int toindex;
struct rawarc rawarc;
char *name = gmon_out;
moncontrol(0);
if (sbuf != NULL) {
register int pid, n;
if (progname[0] != '\0') { /* finish constructing
"PROFDIR/pid.progname" */
/* set name to end of PROFDIR */
name = strrchr(gmon_out, '\0');
if ((pid = getpid()) <= 0) /* extra test just in case */
pid = 1; /* getpid returns something inappropriate */
for (n = 10000; n > pid; n /= 10)
; /* suppress leading zeros */
for ( ; ; n /= 10) {
*name++ = pid/n + '0';
if (n == 1)
break;
pid %= n;
}
*name++ = '.';
(void)strcpy(name, progname);
}
fd = creat( gmon_out , 0666 );
if ( fd < 0 ) {
perror( gmon_out );
return;
}
# ifdef DEBUG
fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
# endif DEBUG
if (write( fd , sbuf , ssiz ) == -1) {
perror( gmon_out );
return;
}
}
endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
if ( froms[fromindex] == 0 ) {
continue;
}
frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
# ifdef DEBUG
fprintf( stderr ,
"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
frompc , tos[toindex].selfpc , tos[toindex].count );
# endif DEBUG
rawarc.raw_frompc = (unsigned long) frompc;
rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
rawarc.raw_count = tos[toindex].count;
write( fd , &rawarc , sizeof rawarc );
}
}
close( fd );
}
/*VARARGS1*/
void
monitor( lowpc , highpc , buf , bufsiz , nfunc )
char *lowpc;
char *highpc;
int *buf, bufsiz;
int nfunc; /* not used, available for compatability only */
{
register o;
register char *s, *name = gmon_out;
if ( lowpc == NULL ) { /* true only at the end */
moncontrol(0);
_mcleanup();
return;
}
#if 0
if (ssiz >= bufsize || lowpc >= highpc)
return; /* buffer too small or PC range bad */
#endif
if ((s = getenv(PROFDIR)) == NULL) /* PROFDIR not in environment */
(void)strcpy(name, GMON_OUT); /* use default "gmon.out" */
else if (*s == '\0') /* value of PROFDIR is NULL */
return; /* no profiling on this run */
else { /* set up mon_out and progname to construct
"PROFDIR/pid.progname" when done profiling */
while (*s != '\0') /* copy PROFDIR value (path-prefix) */
*name++ = *s++;
*name++ = '/'; /* two slashes won't hurt */
if (___Argv != NULL) /* mcrt0.s executed */
if ((s = strrchr(___Argv[0], '/')) != NULL)
strcpy(progname, s + 1);
else
strcpy(progname, ___Argv[0]);
}
sbuf = buf; /* for writing buffer at the wrapup */
ssiz = bufsiz;
( (struct phdr *) buf ) -> lpc = lowpc; /* initialize the first */
( (struct phdr *) buf ) -> hpc = highpc; /* region of the buffer */
( (struct phdr *) buf ) -> ncnt = ssiz;
o = sizeof(struct phdr);
buf = (int *) ( ( (int) buf ) + o );
bufsiz -= o;
if ( bufsiz <= 0 )
return;
o = ( ( (char *) highpc - (char *) lowpc) );
if( bufsiz < o )
s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1;
else
s_scale = SCALE_1_TO_1;
moncontrol(1);
}
/*
* Control profiling
* profiling is what mcount checks to see if
* all the data structures are ready.
*/
void
moncontrol(mode)
int mode;
{
if (mode) {
/* start */
profil((char*) sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
s_lowpc, s_scale);
profiling = 0;
} else {
/* stop */
profil((char *)0, 0, 0, 0);
profiling = 3;
}
}