/**************************************************************************** ** TAU Portable Profiling Package ** ** http://www.cs.uoregon.edu/research/paracomp/tau ** ***************************************************************************** ** Copyright 2007 ** ** Department of Computer and Information Science, University of Oregon ** ** Advanced Computing Laboratory, Los Alamos National Laboratory ** ****************************************************************************/ /*************************************************************************** ** File : tau_wrap.cpp ** ** Description : Generates a wrapper library for external pkgs ** ** for instrumentation with TAU. ** ** Author : Sameer Shende ** ** Contact : sameer@cs.uoregon.edu sameer@paratools.com ** ** Documentation : ** ***************************************************************************/ /* Headers */ #include #include #include #include #if (!defined(TAU_WINDOWS)) #include #endif //TAU_WINDOWS #ifdef _OLD_HEADER_ # include # include # include # include # include #else # include # include # include # include # include # include # include using namespace std; #endif #include "pdbAll.h" #include "tau_datatypes.h" /* defines */ #ifdef TAU_WINDOWS #define TAU_DIR_CHARACTER '\\' #else #define TAU_DIR_CHARACTER '/' #endif /* TAU_WINDOWS */ //#define DEBUG 1 /* For selective instrumentation */ extern int processInstrumentationRequests(char *fname); extern bool instrumentEntity(const string& function_name); extern bool processFileForInstrumentation(const string& file_name); extern bool isInstrumentListEmpty(void); /* Prototypes for selective instrumentation */ extern bool addFileInstrumentationRequests(PDB& p, pdbFile *file, vector & itemvec); /* Globals */ bool memory_flag = false; /* by default, do not insert malloc.h in instrumented C/C++ files */ /////////////////////////////////////////////////////////////////////////// /* -------------------------------------------------------------------------- */ /* -- Fuzzy Match. Allows us to match files that don't quite match properly, * but infact refer to the same file. For e.g., /home/pkg/foo.cpp and ./foo.cpp * or foo.cpp and ./foo.cpp. This routine allows us to match such files! * -------------------------------------------------------------------------- */ bool fuzzyMatch(const string& a, const string& b) { /* This function allows us to match string like ./foo.cpp with /home/pkg/foo.cpp */ if (a == b) { /* the two files do match */ #ifdef DEBUG cout <<"fuzzyMatch returns true for "<& itemvec, PDB& pdb, pdbFile *file) { /* moved selective instrumentation file processing here */ if (!isInstrumentListEmpty()) { /* there are finite instrumentation requests, add requests for this file */ addFileInstrumentationRequests(pdb, file, itemvec); } } #ifdef OLD { /* we used to keep the selective instrumentation file processing at the entry. But, when a routine is specified as a phase, we need to annotate its itemRef accordingly. This needs the entry/exit records to be created prior to processing the selective instrumentation file. N/A for wrappers as there are no entry/exit records created.*/ PDB::croutinevec routines = pdb.getCRoutineVec(); for (PDB::croutinevec::const_iterator rit=routines.begin(); rit!=routines.end(); ++rit) { pdbRoutine::locvec retlocations = (*rit)->returnLocations(); if ( (*rit)->location().file() == file && !(*rit)->isCompilerGenerated() && (instrumentEntity((*rit)->fullName())) ) { itemvec.push_back(new itemRef(*rit, BODY_BEGIN, (*rit)->bodyBegin().line(), (*rit)->bodyBegin().col())); #ifdef DEBUG cout <<" Location begin: "<< (*rit)->location().line() << " col " << (*rit)->location().col() <headBegin().line() << " col " << (*rit)->headBegin().col() <headEnd().line() << " col " << (*rit)->headEnd().col() <bodyBegin().line() << " col " << (*rit)->bodyBegin().col() <bodyEnd().line() << " col " << (*rit)->bodyEnd().col() <line() << " col " << (*rlit)->col() <line(), (*rlit)->col())); } itemvec.push_back(new itemRef(*rit, BODY_END, (*rit)->bodyEnd().line(), (*rit)->bodyEnd().col())); #ifdef DEBUG cout <<" Return type: " << (*rit)->signature()->returnType()->name()<name() <<" Signature: " << (*rit)->signature()->name() <callees(); } } /* All instrumentation requests are in. Sort these now and remove duplicates */ #ifdef DEBUG for(vector::iterator iter = itemvec.begin(); iter != itemvec.end(); iter++) { cout <<"Before SORT: Items ("<<(*iter)->line<<", "<<(*iter)->col<<")" <<"snippet = "<<(*iter)->snippet<::iterator iter = itemvec.begin(); iter != itemvec.end(); iter++) { cout <<"Items ("<<(*iter)->line<<", "<<(*iter)->col<<")" <<"snippet = "<<(*iter)->snippet<signature()->returnType()->name().c_str(), "void") == 0) { #ifdef DEBUG cout <<"Return type is void for "<name()<name()); string proto(r->name()); string funchandle("_h) ("); string rcalledfunc("(*"+r->name()+"_h)"); string dltext; string returntypename; string retstring(" return;"); const pdbGroup *grp; func.append("("); rcalledfunc.append("("); proto.append("("); if ((grp = r->signature()->returnType()->isGroup()) != 0) { returntypename = grp->name(); } else { returntypename = r->signature()->returnType()->name(); } if (runtime) impl<name()<signature()->arguments(); int argcount = 1; bool isVoid = isReturnTypeVoid(r); for(pdbType::argvec::const_iterator argsit = av.begin(); argsit != av.end(); argsit++, argcount++) { char number[256]; #ifdef DEBUG cout <<"Argument "<<(*argsit).name()<<" Type "<<(*argsit).type()->name()<isGroup()) != 0) { argtypename=gr->name(); } else { argtypename=(*argsit).type()->name(); } proto.append(argtypename); funchandle.append(argtypename); proto.append(" " + string("a")+string(number)); rcalledfunc.append(" " + string("a")+string(number)); func.append(string("a")+string(number)); /* We need to handle the case int (*)[] separately generating int (*a1)[] instead of int (*)[] a1 in the impl file */ const char *found; const char *examinedarg = argtypename.c_str(); if ((found = strstr(examinedarg, "(*)")) != 0) { found += 2; /* Reach ) */ //printf("found = %s diff = found - examinedarg = %d \n", found, found - examinedarg); int i; for (i=0; i < found - examinedarg; i++) { //printf("Printing %c\n", examinedarg[i]); impl << examinedarg[i]; } impl<<"a"<signature()->hasEllipsis()) { //printf("Has ellipsis...\n"); impl<<", ..."; } } func.append(")"); proto.append(")"); rcalledfunc.append(")"); funchandle.append(") = NULL;"); impl<<") {" <name()<name()<name() + string("_h == NULL)\n\t") + r->name() + string("_h = dlsym(tau_handle,\"")+r->name() + string("\"); \n") + string(" if (") + r->name() + string ("_h == NULL) {\n") + string(" perror(\"Error obtaining symbol info from dlopen'ed lib\"); \n") + string(" ")+ retstring + string("\n }\n"); } if (!isVoid) { impl<<" "<fullName()<<"\", \"\", " < netcdf */ /* -------------------------------------------------------------------------- */ void extractLibName(const char *filename, string& libname) { char *name = strdup(filename); int len = strlen(name); /* length */ int i; for (i=0; i < len; i++) { if (name[i] == '.') name[i] = '\0'; /* truncate it if . is found */ } libname=string(name); } /* -------------------------------------------------------------------------- */ /* -- Instrumentation routine for a C program ------------------------------- */ /* -------------------------------------------------------------------------- */ bool instrumentCFile(PDB& pdb, pdbFile* f, ofstream& header, ofstream& impl, string& group_name, string& header_file, bool runtime, string& runtime_libname) { //static int firsttime=0; string file(f->name()); // open source file ifstream istr(file.c_str()); if (!istr) { cerr << "Error: Cannot open '" << file << "'" << endl; return false; } #ifdef DEBUG cout << "Processing " << file << " in instrumentCFile..." << endl; #endif // initialize reference vector vector itemvec; getCReferencesForWrapper(itemvec, pdb, f); PDB::croutinevec routines = pdb.getCRoutineVec(); for (PDB::croutinevec::const_iterator rit=routines.begin(); rit!=routines.end(); ++rit) { pdbRoutine::locvec retlocations = (*rit)->returnLocations(); if ( (*rit)->location().file() == f && !(*rit)->isCompilerGenerated() && (instrumentEntity((*rit)->fullName())) ) { printRoutineInOutputFile(*rit, header, impl, group_name, runtime, runtime_libname); } } return true; } /* -------------------------------------------------------------------------- */ /* -- Define a TAU group after ------------------------- */ /* -------------------------------------------------------------------------- */ void defineTauGroup(ofstream& ostr, string& group_name) { if (strcmp(group_name.c_str(), "TAU_USER") != 0) { /* Write the following lines only when -DTAU_GROUP=string is defined */ ostr<< "#ifndef "< [-o ] [-r runtimelibname] [-g groupname] [-i headerfile] [-c|-c++|-fortran] [-f ]"< must be specified\n"<"<"<"<"<"<name(), string(filename))) && (instrumentThisFile = processFileForInstrumentation(string(filename)))) */ if (instrumentThisFile = processFileForInstrumentation(string(filename))) { /* should we instrument this file? Yes */ instrumentCFile(p, *it, header, impl, group_name, header_file, runtime, runtime_libname); } } header <<"#ifdef __cplusplus"<