--- /opt/cvs/dotgnu/pnet/image/program.h Sun Dec 8 18:42:40 2002 +++ image/program.h Sun Feb 2 23:44:22 2003 @@ -308,6 +308,7 @@ void *userData; /* User data for the runtime engine */ ILUInt32 index; /* Data added by the runtime engine */ ILUInt32 count; /* Profile count for the engine */ + void *profile; /* Profile count with call site */ }; --- /opt/cvs/dotgnu/pnet/engine/cvmc.c Fri Nov 15 12:03:44 2002 +++ engine/cvmc.c Mon Feb 3 01:51:07 2003 @@ -342,6 +342,91 @@ return haveCounts; } +#ifdef IL_PROFILE_CVM_METHODS +typedef struct _tagILMethodProfileMap +{ + int count; + ILMethod *from; + struct _tagILMethodProfileMap *next; +}ILMethodProfileMap; +/* + * Dump call graph in neato format + */ +int _ILDumpCallGraph(FILE *stream, ILExecProcess *process) +{ + ILCache *cache = ((ILCVMCoder *)(process->coder))->cache; + ILMethod **list; + ILMethod **temp; + ILMethod *method; + int haveCounts; + + /* Get the list of all translated methods from the cache */ + list = (ILMethod **)ILCacheGetMethodList(cache); + if(!list) + { + return 0; + } + + /* Sort the method list into decreasing order of count */ + if(list[0] != 0 && list[1] != 0) + { + ILMethod **outer; + ILMethod **inner; + for(outer = list; outer[1] != 0; ++outer) + { + for(inner = outer + 1; inner[0] != 0; ++inner) + { + if(outer[0]->count < inner[0]->count) + { + method = outer[0]; + outer[0] = inner[0]; + inner[0] = method; + } + } + } + } + + /* Print the method information */ + haveCounts = 0; + temp = list; + fprintf(stream,"digraph dynamic_call_graph {\n"); + while((method = *temp++) != 0) + { + ILMethodProfileMap* map=(ILMethodProfileMap*)method->profile; + ILMethodProfileMap *level; + if(!(method->count)) + { + continue; + } + level=map; + while(level) + { + fprintf(stream,"\"%s%s%s::%s\" -> \"%s%s%s::%s\" " + "[label=\"called %d times\"];\n", + ILClass_Namespace(ILMethod_Owner(level->from)) ? + ILClass_Namespace(ILMethod_Owner(level->from)) : "", + ILClass_Namespace(ILMethod_Owner(level->from)) ? "." : "", + ILClass_Name(ILMethod_Owner(level->from)), + ILMethod_Name(map->from), + ILClass_Namespace(ILMethod_Owner(method)) ? + ILClass_Namespace(ILMethod_Owner(method)) : "", + ILClass_Namespace(ILMethod_Owner(method)) ? "." : "", + ILClass_Name(ILMethod_Owner(method)), + ILMethod_Name(method), + map->count + ); + level=level->next; + } + haveCounts = 1; + } + fprintf(stream,"}"); + + /* Clean up and exit */ + ILFree(list); + return haveCounts; +} +#endif + #endif /* !IL_CONFIG_REDUCE_CODE */ /* --- /opt/cvs/dotgnu/pnet/engine/cvm_call.c Mon Sep 16 08:24:47 2002 +++ engine/cvm_call.c Mon Feb 3 00:56:11 2003 @@ -377,6 +377,74 @@ return num; } +#ifdef IL_PROFILE_CVM_METHODS +typedef struct _tagILMethodProfileMap +{ + int count; + ILMethod *from; + struct _tagILMethodProfileMap *next; +}ILMethodProfileMap; + +static void AddCallFromMethod(ILExecThread *thread, ILMethod *method, + ILMethod *methodToCall) +{ + ILMethodProfileMap *map=(ILMethodProfileMap*)((methodToCall)->profile); + ILMethod *source; + ILMethodProfileMap *temp=map; + if(temp == NULL) + { + /* newcomer :) */ + map=(ILMethodProfileMap*)ILCalloc(sizeof(ILMethodProfileMap),1); + methodToCall->profile=(void*)map; + temp=map; + temp->from=method; + temp->count=1; + return; + } + /* else */ + while(temp) + { + const char *ns1,*ns2; + source=temp->from; + ns1=ILClass_Namespace(ILMethod_Owner(method)); + ns2=ILClass_Namespace(ILMethod_Owner(source)); + if( + ( + /* either both are null or both are equal & non-null */ + (ns1==NULL && ns2==NULL) + || + (ns1 && ns2 && !strcmp(ns1,ns2)) + ) + && + !strcmp(ILClass_Name(ILMethod_Owner(method)), + ILClass_Name(ILMethod_Owner(source))) + && + !strcmp(ILMethod_Name(method), + ILMethod_Name(source)) + && + ILTypeIdentical(ILMethod_Signature(method), + ILMethod_Signature(source)) + ) + { + (temp->count)++; + return; + } + if(temp->next == NULL) + { + /* append */ + temp->next= + (ILMethodProfileMap*)ILCalloc(sizeof(ILMethodProfileMap),1); + temp=temp->next; + temp->from=method; + temp->count=1; + return; + } + /* else */ + temp=temp->next; + } +} +#endif + #elif defined(IL_CVM_LOCALS) ILMethod *methodToCall; @@ -429,6 +497,9 @@ { /* Call a method */ methodToCall = CVM_ARG_PTR(ILMethod *); +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif if(methodToCall->userData) { /* It is converted: allocate a new call frame */ @@ -513,6 +584,9 @@ /* Call a constructor that we don't know if it has been converted */ methodToCall = CVM_ARG_PTR(ILMethod *); +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif /* Determine if we have already converted the constructor */ if(methodToCall->userData) { @@ -736,6 +810,9 @@ /* Locate the method to be called */ methodToCall = ((ILClassPrivate *)(GetObjectClass(tempptr)->userData)) ->vtable[CVM_ARG_DWIDE2_SMALL]; +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif /* Has the method already been converted? */ if(methodToCall->userData) @@ -838,6 +915,9 @@ { MISSING_METHOD_EXCEPTION(); } +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif /* Has the method already been converted? */ if(methodToCall->userData) @@ -1244,6 +1324,9 @@ { /* Call a method by pointer */ methodToCall = (ILMethod *)(stacktop[-1].ptrValue); +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif --stacktop; if(methodToCall && methodToCall->userData) { @@ -1318,6 +1401,9 @@ methodToCall = ((ILClassPrivate *)(GetObjectClass(tempptr)->userData)) ->vtable[CVM_ARG_DWIDE2_LARGE]; +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif /* Copy the state back into the thread object */ COPY_STATE_TO_THREAD(); @@ -1368,6 +1454,10 @@ MISSING_METHOD_EXCEPTION(); } +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif + /* Copy the state back into the thread object */ COPY_STATE_TO_THREAD(); @@ -1443,6 +1533,10 @@ /* Retrieve the target method */ methodToCall = CVM_ARG_TAIL_METHOD; +#ifdef IL_PROFILE_CVM_METHODS + AddCallFromMethod(thread,method,methodToCall); +#endif + /* Convert the method if necessary */ if(methodToCall->userData) { --- /opt/cvs/dotgnu/pnet/engine/ilrun.c Thu Dec 26 15:37:29 2002 +++ engine/ilrun.c Mon Feb 3 00:59:51 2003 @@ -46,6 +46,7 @@ * Imports from "cvmc.c". */ int _ILDumpMethodProfile(FILE *stream, ILExecProcess *process); +int _ILDumpCallGraph(FILE *stream, ILExecProcess *process); /* * Table of command-line options. @@ -94,6 +95,8 @@ {"--var-profile", 'V', 0, 0, 0}, {"-P", 'P', 0, 0, 0}, {"--dump-params", 'P', 0, 0, 0}, + {"-C", 'C', 0, 0, 0}, + {"--call-graph", 'C', 0, 0, 0}, #endif {0, 0, 0, 0, 0} @@ -126,6 +129,7 @@ int dumpMethodProfile = 0; int dumpVarProfile = 0; int dumpParams = 0; + int dumpCallGraph = 0; #endif /* Initialize the locale routines */ @@ -205,6 +209,12 @@ dumpParams = 1; } break; + + case 'C': + { + dumpCallGraph = 1; + } + break; #endif case 'v': @@ -376,6 +386,14 @@ { fprintf(stderr, "%s: method profiles are not available\n", progname); + } + } + if(dumpCallGraph) + { + if(!_ILDumpCallGraph(stdout, process)) + { + fprintf(stderr, "%s: method profiles are not available\n", + progname); } } if(dumpVarProfile)