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 + -
显示快捷键?