xprofiler.c

来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 713 行 · 第 1/2 页

C
713
字号
/* * xprofiler.c * Interface functions to the profiling code * * Copyright (c) 2000, 2001 University of Utah and the Flux Group. * All rights reserved. * * This file is licensed under the terms of the GNU Public License. * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * Contributed by the Flux Research Group, Department of Computer Science, * University of Utah, http://www.cs.utah.edu/flux/ */#if defined(KAFFE_XPROFILER)#include <string.h>#include <stdlib.h>#include <signal.h>#include <errno.h>#include <sys/time.h>#include <sys/gmon.h>#include <sys/time.h>#include <sys/types.h>#include <sys/gmon.h>#include <sys/sysctl.h>#include "gtypes.h"#include "md.h"#include "xprofile-md.h"#include "exception.h"#include "kaffe/jmalloc.h"#include "methodCache.h"#include "memorySamples.h"#include "feedback.h"#include "debugFile.h"#include "fileSections.h"#include "gmonFile.h"#include "callGraph.h"#include "xprofiler.h"/* Variables for figuring out the start and end of the program text */extern char _start;extern char etext;int xProfFlag = 0;/* Flag used to determine whether or not we should record `hits' */static volatile int xProfRecord = 1;/* * This variable is part of a nasty hack to keep the call graph accounting * code from being credited with time.  The accounting function should set * this variable while its working so that if a profiling interrupt happens * while its executing the appropriate function will be credited. */static char * volatile profiler_sample_override_pc = 0;volatile int profiler_sample_overrides = 0;/* Structures used to hold the profiling information */struct memory_samples *kaffe_memory_samples = 0;struct call_graph *kaffe_call_graph = 0;/* The name of the output files */char *kaffe_gmon_filename = "xgmon.out";char *kaffe_syms_filename = "kaffe-jit-symbols.s";/* Debugging file for profiler symbols */struct debug_file *profiler_debug_file = 0;static int extraProfileCount = 0;/* Number of call_arc structures to preallocate */#define XPROFILE_ARCS (1024 * 64)/* * The gutter threshold is used to determine if the gap between two chunks of * observed memory is too large to put into the file.  Since the resulting gap * would just be a bunch of zeros, we split them into different files. */#define SAMPLE_GUTTER_THRESHOLD 1024 * 1024 * 5/* Structure used to track the current gmon file for our walker */struct profiler_gmon_file {	char *pgf_stage;		/* The name of the current stage */	struct gmon_file *pgf_file;	/* The active gmon file structure */	long pgf_record;		/* The index of the hist record */};/* * A walker function for walkMemorySamples.  This does a little more than * the one provided by the gmon code since it will create a new gmon file * if theres a large gap in observed memory. */static int profilerSampleWalker(void *handle, char *addr,				short *bins, int size){	struct profiler_gmon_file *pgf = handle;	struct gmon_file *gf = pgf->pgf_file;	int retval = 0;	/* Check if we need to dump these samples in another file */	if( (addr - gf->gf_addr) > SAMPLE_GUTTER_THRESHOLD )	{		char *filename, *old_high;		int len;		old_high = gf->gf_high;		/* Rewrite the old record with the new high address */		writeGmonRecord(gf,				GRA_Rewrite, pgf->pgf_record,				GRA_Type, GMON_TAG_TIME_HIST,				GRA_LowPC, gf->gf_low,				GRA_HighPC, gf->gf_addr,				GRA_DONE);		writeCallGraph(kaffe_call_graph, gf);		/* Close down the file */		deleteGmonFile(gf);		pgf->pgf_file = 0;		gf = 0;		/*		 * Make up the filename for the new file, we'll just use the		 * starting address for this range to make it unique		 */		len = strlen(kaffe_gmon_filename) +			1 + /* `.' */			2 + (sizeof(void *) * 2) + /* `0x...' */			(pgf->pgf_stage ? strlen(pgf->pgf_stage) + 1 : 0) +			1;		if( (filename = (char *)KMALLOC(len)) )		{			/* Construct the new file name */			sprintf(filename,				"%s.%p%s%s",				kaffe_gmon_filename,				addr,				pgf->pgf_stage ? "." : "",				pgf->pgf_stage ? pgf->pgf_stage : "");			if( (pgf->pgf_file = createGmonFile(filename)) )			{				gf = pgf->pgf_file;				/* Write out another hist record */				pgf->pgf_record = writeGmonRecord(					gf,					GRA_Type, GMON_TAG_TIME_HIST,					GRA_LowPC, addr,					GRA_HighPC, old_high,					GRA_DONE);			}		}	}	if( gf )	{		/* Let the gmon walker do its thing */		retval = gmonSampleWalker(gf, addr, bins, size);	}	memset(bins, 0, size * sizeof(short));	return( retval );}/* * Handles any post processing */static void profilerAtExit(void){	if( !xProfFlag )		return;	/* We don't care about profiling anymore */	disableProfileTimer();	/* This is the final stage, write out any data */	xProfileStage(0);	/* Release everything else */	disableXProfiling();}int enableXCallGraph(void){	int retval = false;	if( (kaffe_call_graph = createCallGraph(XPROFILE_ARCS)) )	{		retval = true;	}	return( retval );}#if defined(KAFFE_CPROFILER)/* * Return the minimum cycles per second for the machine */static int hertz(void){	struct itimerval value, ovalue;	int retval = 0;		timerclear(&value.it_interval);	timerclear(&value.it_value);	timerclear(&ovalue.it_interval);	timerclear(&ovalue.it_value);	value.it_interval.tv_usec = 1;	setitimer(ITIMER_REAL, &value, 0);	getitimer(ITIMER_REAL, &ovalue);	timerclear(&value.it_interval);	timerclear(&value.it_value);	setitimer(ITIMER_REAL, &value, 0);	if( ovalue.it_interval.tv_usec >= 2 )		retval = 1000000 / ovalue.it_interval.tv_usec;	return( retval );}#if defined(KAFFE_STD_PROF_RATE)KAFFE_STD_PROF_RATE#endif#endifint enableXProfiling(void){	int retval = false;	xProfilingOff();	/* Start up our profiler and set it to observe the main executable */	if( xProfFlag &&	    enableProfileTimer() &&	    (kaffe_memory_samples = createMemorySamples()) &&	    observeMemory(kaffe_memory_samples, &_start, &etext - &_start) &&	    (profiler_debug_file = createDebugFile(kaffe_syms_filename)) &&	    !atexit(profilerAtExit) )	{#if defined(KAFFE_CPROFILER)		struct gmonparam *gp = getGmonParam();		int prof_rate;#endif		#if defined(KAFFE_CPROFILER)		/* Turn off any other profiling */		profil(0, 0, 0, 0);#if defined(KAFFE_STD_PROF_RATE)		if( !(prof_rate = kaffeStdProfRate()) )#endif			prof_rate = hertz(); /* Just guess */		if( !prof_rate )			prof_rate = 100;		/* Copy the hits leading up to now into our own counters */		if( gp && gp->kcountsize > 0 )		{			int lpc, len = gp->kcountsize / sizeof(HISTCOUNTER);			HISTCOUNTER *hist = gp->kcount;			int scale;			scale = (gp->highpc - gp->lowpc) / len;			for( lpc = 0; lpc < len; lpc++ )			{				if( hist[lpc] )				{					char *pc = ((char *)gp->lowpc) +						(lpc * scale);					memoryHitCount(kaffe_memory_samples,						       pc,						       (100 * hist[lpc]) /						       prof_rate);				}			}		}#endif		retval = true;	}	else	{		xProfFlag = 0;		disableXProfiling();	}	xProfilingOn();	return( retval );}void disableXProfiling(void){	/* Shutoff the timer and delete any structures */	disableProfileTimer();	xProfilingOff();	deleteMemorySamples(kaffe_memory_samples);	kaffe_memory_samples = 0;	deleteCallGraph(kaffe_call_graph);	kaffe_call_graph = 0;	deleteDebugFile(profiler_debug_file);	profiler_debug_file = 0;}void xProfilingOn(void){	xProfRecord++;#if defined(KAFFE_CPROFILER)	{		struct gmonparam *gp = getGmonParam();				if( xProfRecord && gp )			gp->state = GMON_PROF_ON;	}#endif}void xProfilingOff(void){	xProfRecord--;#if defined(KAFFE_CPROFILER)	{		struct gmonparam *gp = getGmonParam();				if( !xProfRecord && gp )			gp->state = GMON_PROF_OFF;	}#endif}void xProfileStage(char *stage_name){	char *low, *high, *filename;	struct gmon_file *gf;	int len;	if( !xProfFlag )		return;	xProfilingOff();	low = kaffe_memory_samples->ms_low;	high = kaffe_memory_samples->ms_high +		(extraProfileCount * HISTFRACTION);	jthread_suspendall();	len = strlen(kaffe_gmon_filename) +		(stage_name ? strlen(stage_name) + 1 : 0) +		1;	if( (filename = (char *)KMALLOC(len)) )	{		sprintf(filename,			"%s%s%s",			kaffe_gmon_filename,			stage_name ? "." : "",			stage_name ? stage_name : "");		/* Create and write out the gmon file */		if( (gf = createGmonFile(filename)) )		{			struct profiler_gmon_file pgf;						/* Initialize the profiler_gmon_files state */			pgf.pgf_stage = stage_name;			pgf.pgf_file = gf;			/* Write out the samples */			pgf.pgf_record =				writeGmonRecord(gf,						GRA_Type, GMON_TAG_TIME_HIST,						GRA_LowPC, low,						GRA_HighPC, high,						GRA_DONE);			/* The low/high might be aligned by writeGmonRecord */			low = gf->gf_low;			high = gf->gf_high;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?