//#define DEBUG 1 #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" /* defines */ #ifdef TAU_WINDOWS #define TAU_DIR_CHARACTER '\\' #else #define TAU_DIR_CHARACTER '/' #endif /* TAU_WINDOWS */ #ifdef TAU_INSTRUMENT_PURE bool instrumentPure = true; #else bool instrumentPure = false; #endif /* The IBM xlf compiler does not support sizeof(A) to find the size of an object */ #ifdef TAU_USE_SIZE_INSTEAD_OF_SIZEOF string tau_size_tok("size"); #else /* TAU_USE_SIZE_INSTEAD_OF_SIZEOF */ string tau_size_tok("sizeof"); #endif /* TAU_USE_SIZE_INSTEAD_OF_SIZEOF */ /* 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); extern void writeAdditionalDeclarations(ostream& ostr, const pdbRoutine *routine); extern void writeAdditionalFortranInvocations(ostream& ostr, const pdbRoutine *routine); extern bool addMoreInvocations(int routine_id, string& snippet); extern bool isVoidRoutine(const pdbItem* r); #include "tau_datatypes.h" const int INBUF_SIZE = 65536; #define EXIT_KEYWORD_SIZE 256 bool noinit_flag = false; /* initialize using TAU_INIT(&argc, &argv) by default */ bool memory_flag = false; /* by default, do not insert malloc.h in instrumented C/C++ files */ bool lang_specified = false; /* implicit detection of source language using PDB file */ bool process_this_return = false; /* for C instrumentation using a different return keyword */ char exit_keyword[EXIT_KEYWORD_SIZE] = "exit"; /* You can define your own exit keyword */ bool using_exit_keyword = false; /* By default, we don't use the exit keyword */ tau_language_t tau_language; /* language of the file */ bool use_perflib = false; /* by default, do not insert calls for perflib package */ /* These variables should actually be defined here. However, tau_wrap should not depend on them (but it currently would). */ extern bool use_spec; /* For Pooma, add a -noinline flag */ extern bool noinline_flag; list current_timer; /* for Fortran loop level instrumentation. */ /* not needed anymore */ #ifdef OLD const pdbItem *item; itemKind_t kind; /* For C instrumentation */ bool isTarget; int line; int col; string snippet; #endif /* OLD */ /* Prototypes for selective instrumentation */ extern bool addFileInstrumentationRequests(PDB& p, pdbFile *file, vector& itemvec); void processExitOrAbort(vector& itemvec, const pdbItem *i, pdbRoutine::callvec & c); /* in this file below */ /* A strict weak ordering is a binary predicate that compares two objects, returning true if the first preceeds the second */ static bool locCmp(const itemRef* r1, const itemRef* r2) { if (r1 == r2) { // strict weak ordering requires false on equal elements return false; } if ( r1->line == r2->line ) { if (r1->col == r2->col) { /* they're both equal */ // we must first check if they are both BODY_BEGIN and return false in that case // otherwise it just depends on which is r1 and which is r2 // STL sort requires strict weak ordering, meaning that two elements are equal // then this routine must return (x,y) as false and (y,x) as false if (r1->kind == r2->kind) return false; if (r1->kind == BODY_BEGIN) return true; if (r2->kind == BODY_BEGIN) return false; /* body begin must always come first */ if (r1->kind == INSTRUMENTATION_POINT) return false; return true; } else { /* col numbers are different */ return r1->col < r2->col; } } else { return r1->line < r2->line; } } static bool itemEqual(const itemRef* r1, const itemRef* r2) { #ifdef DEBUG printf("Comparing <%d:%d> with <%d:%d> kind = %d vs %d, target %d vs %d, attribute %d vs %d\n", r1->line, r1->col, r2->line, r2->col, r1->kind, r2->kind, r1->isTarget, r2->isTarget, r1->attribute, r2->attribute); #endif /* DEBUG */ /* two loops on the same line shouldn't be instrumented twice -- happens with templates with different instantiations. */ if ((r1->line == r2->line) && (r1->col == r2->col) && (r1->kind == r2->kind) && (r1->isTarget == r2->isTarget) && (r1->attribute == r2->attribute) && ((r1->kind == START_LOOP_TIMER ) || (r1->kind == STOP_LOOP_TIMER))) { #ifdef DEBUG printf("Items are equal returning true!\n"); #endif /* DEBUG */ return true; /* they are equal -- don't bother checking the snippet part.*/ } else return ( (r1->line == r2->line) && (r1->col == r2->col) && (r1->kind == r2->kind) && (r1->isTarget == r2->isTarget) && (r1->attribute == r2->attribute) && (r1->snippet == r2->snippet)); } string getInstrumentedName(const pdbItem *item) { // create the instrumented routine name std::ostringstream oss; pdbRoutine *pdbr = (pdbRoutine*)item; if (!item) return string(""); pdbLoc loc = item->location(); const char *fullfile = item->location().file()->name().c_str(); while (strchr(fullfile,TAU_DIR_CHARACTER)) { // remove path fullfile = strchr(fullfile,TAU_DIR_CHARACTER)+1; } // we only have fat item data for C/C++ right now pdbFatItem *fatItem = (pdbFatItem*)item; if (fatItem->headBegin().line() == 0) { oss << item->fullName() << " [{" << fullfile << "} {" << loc.line() << "," << loc.col() << "}]"; } else { oss << item->fullName() << " [{" << fullfile << "} {" << fatItem->headBegin().line() << "," << fatItem->headBegin().col() << "}-{" << fatItem->bodyEnd().line() << "," << fatItem->bodyEnd().col() << "}]"; } string instrumentedName(oss.str()); return instrumentedName; } /* -------------------------------------------------------------------------- */ /* -- Sometimes a routine is created by a macro expansion and we shouldn't */ /* -- instrument it. identicalBeginEnd returns true if body begin/end line */ /* -- and columns match perfectly, false otherwise. */ /* -------------------------------------------------------------------------- */ bool identicalBeginEnd(const pdbCRoutine *rit) { if (rit && (rit->bodyBegin().line() == rit->bodyEnd().line()) && (rit->bodyBegin().col() == rit->bodyBegin().col())) { return true; } else { return false; } } /* -------------------------------------------------------------------------- */ /* -- getMeasurementEntity(i) returns TAU_PROFILE/TAU_PHASE based on i ----- */ /* -------------------------------------------------------------------------- */ const char * getMeasurementEntity(itemRef *i) { /* for C++ */ if (i->isPhase) { /* static or dynamic phase */ if (i->isDynamic) { return "TAU_DYNAMIC_PHASE"; } else { /* ! dynamic phase */ return "TAU_PHASE"; } } else { /* timer */ if (i->isDynamic) { return "TAU_DYNAMIC_PROFILE"; } else { /* ! dynamic timer -- plain old static timer */ return "TAU_PROFILE"; } } /* phase/timer */ } /* -------------------------------------------------------------------------- */ /* -- getCreateMeasurementEntity(i) returns TAU_PROFILE_TIMER/TAU_PHASE_TIMER */ /* -------------------------------------------------------------------------- */ const char * getCreateMeasurementEntity(itemRef *i) { /* NOTE: THIS ROUTINE IS ONLY MEANT FOR C/C++. See writeFortranTimer for F90. */ if (i && i->isPhase) { /* static or dynamic phase */ if (i->isDynamic) { return "TAU_PHASE_CREATE_DYNAMIC_AUTO"; /* NOTE: Change this! */ } else { /* ! dynamic phase */ return "TAU_PHASE_CREATE_STATIC"; } } else { /* timer. We currently do not support a dynamic timer for the full routine. Hence, we use the default static timer.*/ if (i->isDynamic) { return "TAU_PROFILE_CREATE_DYNAMIC_AUTO"; /* NOTE: Change this! */ } else { /* ! dynamic timer */ return "TAU_PROFILE_TIMER"; } } } /* -------------------------------------------------------------------------- */ /* -- getStartMeasurementEntity(i) returns TAU_PROFILE_START/TAU_PHASE_START */ /* -------------------------------------------------------------------------- */ const char * getStartMeasurementEntity(itemRef *i) { if (i && i->isPhase) return "TAU_PHASE_START"; else return "TAU_PROFILE_START"; } /* -------------------------------------------------------------------------- */ /* -- getStopMeasurementEntity(i) returns TAU_PROFILE_STOP/TAU_PHASE_STOP --- */ /* -------------------------------------------------------------------------- */ const char * getStopMeasurementEntity(itemRef *i) { #ifdef DEBUG printf("Inside getStopMeasurementEntity: isPhase = %d\n", i->isPhase); #endif /* DEBUG */ if (i && i->isPhase) return "TAU_PHASE_STOP"; else return "TAU_PROFILE_STOP"; } /* -------------------------------------------------------------------------- */ /* -- Merge instrumentation requests of same kind for same location --------- */ /* -------------------------------------------------------------------------- */ void mergeInstrumentationRequests(vector& itemvec) { /* Now merge objects of the same kind at the same location */ if (itemvec.size() > 1) { vector::iterator iter = itemvec.begin()+1; while (iter != itemvec.end()) { itemRef* item1 = *(iter - 1); itemRef* item2 = *iter; if (item1->kind == item2->kind && item1->line == item2->line && item1->col == item2->col) { if (item1->snippet.empty()) item1->snippet = item2->snippet; else if (!item2->snippet.empty()) item1->snippet += "\n\t" + item2->snippet; iter = itemvec.erase(iter); } else { ++iter; } } } } /* -------------------------------------------------------------------------- */ /* -- Remove any matching requests ------------------------------------------ */ /* -------------------------------------------------------------------------- */ void removeMatchingInstrumentationRequests(vector& itemvec, const char *name, int line) { /* Iterate through at remove any instrumentation request with the same 'name' and line number */ if (itemvec.size() > 1) { vector::iterator iter = itemvec.begin(); while (iter != itemvec.end()) { itemRef* ref = *iter; if (ref->item) { pdbFatItem *fatItem = (pdbFatItem*)ref->item; if (line == ref->line || line == fatItem->headBegin().line()) { iter = itemvec.erase(iter); } else { ++iter; } } } } } /* -------------------------------------------------------------------------- */ /* -- Merge instrumentation requests of same kind for same location --------- */ /* -------------------------------------------------------------------------- */ void postprocessInstrumentationRequests(vector& itemvec) { /* It is assumed that all instrumentation requests are in the vector at this point. Now the requests can be sorted, duplicates removed, and requests of the same type on the same location merged. */ stable_sort(itemvec.begin(), itemvec.end(), locCmp); itemvec.erase(unique(itemvec.begin(), itemvec.end(),itemEqual),itemvec.end()); mergeInstrumentationRequests(itemvec); #ifdef DEBUG for(vector::iterator iter = itemvec.begin(); iter != itemvec.end(); iter++) { cout <<"Items ("<<(*iter)->line<<", "<<(*iter)->col<<")"<& itemvec, PDB& pdb, pdbFile *file) { /* get routines, templates and member templates of classes */ bool retval; /* 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. */ PDB::croutinevec routines = pdb.getCRoutineVec(); for (PDB::croutinevec::const_iterator rit=routines.begin(); rit!=routines.end(); ++rit) { if ( (*rit)->location().file() == file && !(*rit)->isCompilerGenerated() && (((*rit)->bodyBegin().line() != 0) && (*rit)->kind() != pdbItem::RO_EXT) && (instrumentEntity((*rit)->fullName())) && !identicalBeginEnd(*rit) ) { #ifdef DEBUG cout <<"* Checking Routine: "<<(*rit)->fullName()<callees(); processExitOrAbort(itemvec, *rit, c); #ifdef DEBUG cout <<"Routine "<<(*rit)->fullName() <<" body Begin line " << (*rit)->bodyBegin().line() << " col " << (*rit)->bodyBegin().col() <isInline()) { if (noinline_flag) { #ifdef DEBUG cout <<"Dont instrument "<<(*rit)->fullName()<isStatic()) { #ifdef DEBUG cout <<" STATIC "<< (*rit)->fullName() <bodyBegin().line(), (*rit)->bodyBegin().col())); /* parameter is always true: no need to add CT(*this) for non templates */ #ifdef DEBUG cout << (*rit)->fullName() <location().file() == file) { pdbItem::templ_t tekind = (*te)->kind(); #ifdef DEBUG cout <<"* Checking Template: "<<(*te)->fullName()<bodyBegin().line() != 0) && (instrumentEntity((*te)->fullName())) ) { /* Sometimes a compiler generated routine shows up in a template. These routines (such as operator=) do not have a body position. Instrument only if it has a valid body position. */ // templates need some processing. Give it a false for isTarget arg. // target helps identify if we need to put a CT(*this) in the type // old: //if ((((*te)->parentGroup()) == 0) && (tekind != pdbItem::TE_STATMEM)) /* TEMPLATES DO NOT HAVE CALLEES ONLY ROUTINES DO */ /* See if the current template calls exit() */ /* pdbRoutine::callvec c = (*te)->callees(); processExitOrAbort(itemvec, *te, c); */ if ((tekind == pdbItem::TE_FUNC) || (tekind == pdbItem::TE_STATMEM)) { // There's no parent class. No need to add CT(*this) itemvec.push_back(new itemRef(*te, true, (*te)->bodyBegin().line(), (*te)->bodyBegin().col())); // False puts CT(*this) } else { #ifdef DEBUG cout <<"Before adding false to the member function, we must verify that it is not static"<funcProtoInst(); if (!tr || (((tekind == pdbItem::TE_FUNC) || (tekind == pdbItem::TE_MEMFUNC)) && ((tr) && (tr->isStatic())))) { /* check to see if there's a prototype instantiation entry */ /* it is indeed a static member function of a class template */ /* DO NOT add CT(*this) to the static member function */ itemvec.push_back(new itemRef(*te, true, (*te)->bodyBegin().line(), (*te)->bodyBegin().col())); } else { // it is a member function add the CT macro itemvec.push_back(new itemRef(*te, false, (*te)->bodyBegin().line(), (*te)->bodyBegin().col())); } } } else { #ifdef DEBUG cout <<"T: "<<(*te)->fullName()< class Key { public: void foobar() { int x; x = 5; } }; int main(int argc, char **argv) { Key<3> key3; key3.foobar(); Key<4> key4; key4.foobar(); } The user may specify: BEGIN_EXCLUDE_LIST Key::foobar END_EXCLUDE_LIST And that will prevent the instrumentation of the template: TAU_PROFILE("Key::foobar [{key.cc} {6,8}]", " ", TAU_USER); But then the routines implementing it, (Key<3> and Key<4>) will still be there, and after merging them, one of them will remain. Now the user could specify them all: BEGIN_EXCLUDE_LIST Key::foobar Key<3>::foobar Key<4>::foobar END_EXCLUDE_LIST Or use wildcards, but really, that's just stupid. What if there were hundreds of them? So now, below, if a template is excluded, go through the list and remove all matching entries. There definitely a better way to do this, but this is all I could come up with quickly. */ u = pdb.getTemplateVec(); for(PDB::templatevec::iterator te = u.begin(); te != u.end(); ++te) { if ( (*te)->location().file() == file) { pdbItem::templ_t tekind = (*te)->kind(); if (((tekind == pdbItem::TE_MEMFUNC) || (tekind == pdbItem::TE_STATMEM) || (tekind == pdbItem::TE_FUNC)) && ((*te)->bodyBegin().line() != 0)) { if (!instrumentEntity((*te)->fullName())) { // go back and remove any routines that may have matched #ifdef DEBUG cout <<"* Removing itemRef's for: "<<(*te)->fullName()<name().c_str(), (*te)->bodyBegin().line()); } } } } return true; /* everything is ok */ } /* -------------------------------------------------------------------------- */ /* -- Get a list of instrumentation points for a C program ------------------ */ /* -------------------------------------------------------------------------- */ /* Create a vector of items that need action: such as BODY_BEGIN, RETURN etc.*/ void getCReferences(vector& itemvec, PDB& pdb, pdbFile *file) { /* 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. */ 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() && ((*rit)->kind() != pdbItem::RO_EXT) && ((*rit)->bodyBegin().line() != 0) && ((*rit)->bodyEnd().line() != 0) && (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(); processExitOrAbort(itemvec, *rit, c); } } } /* -------------------------------------------------------------------------- */ /* -- Get a list of instrumentation points for a F90 program ---------------- */ /* -------------------------------------------------------------------------- */ void getFReferences(vector& itemvec, PDB& pdb, pdbFile *file) { /* get routines, templates and member templates of classes */ PDB::froutinevec routines = pdb.getFRoutineVec(); /* 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. */ for (PDB::froutinevec::const_iterator rit=routines.begin(); rit!=routines.end(); ++rit) { pdbRoutine::locvec retlocations = (*rit)->returnLocations(); pdbRoutine::locvec stoplocations = (*rit)->stopLocations(); if ( (*rit)->location().file() == file && ((*rit)->kind() != pdbItem::RO_FSTFN) && ((*rit)->firstExecStmtLocation().file()) && (instrumentEntity((*rit)->fullName())) ) { #ifdef DEBUG cout <<"Routine " << (*rit)->fullName() <firstExecStmtLocation().line(), (*rit)->firstExecStmtLocation().col())); #ifdef DEBUG cout <<" firstExecStatement: "<< (*rit)->firstExecStmtLocation().line() << " col " << (*rit)->firstExecStmtLocation().col() <line() << " col " << (*rlit)->col() <line(), (*rlit)->col())); } /* Next process the stop locations */ for(pdbRoutine::locvec::iterator slit = stoplocations.begin(); slit != stoplocations.end(); slit++) { #ifdef DEBUG cout <<" Stop Locations : "<< (*slit)->line() << " col " << (*slit)->col() <line(), (*slit)->col())); } } } } /* -------------------------------------------------------------------------- */ /* -- process exit or abort statement and generate a record for itemRef */ /* -------------------------------------------------------------------------- */ void processExitOrAbort(vector& itemvec, const pdbItem *rit, pdbRoutine::callvec & c) { for (pdbRoutine::callvec::iterator cit = c.begin(); cit !=c.end(); cit++) { const pdbRoutine *rr = (*cit)->call(); #ifdef DEBUG cout <<"Callee " << rr->name() << " location line " << (*cit)->line() << " col " << (*cit)->col() <exit or obj->abort. Ignore the routines that have a parent group */ if (rr->parentGroup() == (const pdbGroup *) NULL) { if (strcmp(rr->name().c_str(), exit_keyword)== 0) { /* routine name matches and it is not a member of a class */ /* routine calls exit */ #ifdef DEBUG cout <<"Exit keyword matched"<line(), (*cit)->col())); } else if (using_exit_keyword) { /* also check for "exit" where it occurs */ if (strcmp(rr->name().c_str(), "exit")== 0) { /* routine calls exit */ itemvec.push_back(new itemRef(rit, EXIT, (*cit)->line(), (*cit)->col())); } } /* using exit keyword */ if (strcmp(rr->name().c_str(), "abort") == 0) { /* routine calls abort */ itemvec.push_back(new itemRef(rit, EXIT, (*cit)->line(), (*cit)->col())); } } } } /* -------------------------------------------------------------------------- */ /* -- Returns true is return type is a reference else returns false --------- */ /* -------------------------------------------------------------------------- */ bool isReturnTypeReference(itemRef * i) { const pdbType *t = ((pdbRoutine *)(i->item))->signature()->returnType(); if ((t->kind() == pdbItem::TY_REF) || (t->isGroup())) return true; else return false; } /* -------------------------------------------------------------------------- */ /* -- When int main(int, char **) is used, the argname is -. We can't use it */ /* -- with TAU_INIT(&argname,...); So, we check to see that no arg has a - */ /* -------------------------------------------------------------------------- */ bool okToPrintTauInit(pdbType::argvec& av) { for(pdbType::argvec::const_iterator argsit = av.begin(); argsit != av.end(); argsit++) { if (strcmp((*argsit).name().c_str(), "-") == 0) return false; } return true; /* its ok. No argument is -. */ } /* -------------------------------------------------------------------------- */ /* -- Prints TAU_PROFILE_INIT ----------------------------------------------- */ /* -------------------------------------------------------------------------- */ void print_tau_profile_init(ostream& ostr, pdbCRoutine *main_routine) { if ( noinit_flag == false ) { /* Put TAU_INIT */ pdbType::argvec av = main_routine->signature()->arguments(); if (av.size() == 2) { int arg_count = 0; if (okToPrintTauInit(av)) { ostr<<" TAU_INIT("; for(pdbType::argvec::const_iterator argsit = av.begin(); argsit != av.end(); argsit++, arg_count++) { ostr<<"&"<<(*argsit).name(); if (arg_count == 0) ostr<<", "; } ostr<<"); "< ------------------------- */ /* -------------------------------------------------------------------------- */ 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 "<name()); static char inbuf[INBUF_SIZE]; // to read the line // open outfile for instrumented version of source file ofstream ostr(outfile.c_str()); if (!ostr) { cerr << "Error: Cannot open '" << outfile << "'" << endl; return false; } // open source file ifstream istr(file.c_str()); if (!istr) { cerr << "Error: Cannot open '" << file << "'" << endl; return false; } #ifdef DEBUG cout << "Processing " << file << " ..." << endl; #endif memset(inbuf, INBUF_SIZE, 0); // reset to zero // initialize reference vector vector itemvec; if (!use_spec) { /* In "spec" mode, only the file instrumentation requests are used */ retval = getCXXReferences(itemvec, pdb, f); if (!retval){ #ifdef DEBUG cout <<"instrumentCXXFile: propagating error from getCXXReferences..."< if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { /* XXX Insert code here */ } else ostr<< "#include <"<"<"<::iterator it = itemvec.begin(); it != itemvec.end(); ++it) { // Read one line each till we reach the desired line no. #ifdef DEBUG if ((*it) && (*it)->item) cout <<"S: "<< (*it)->item->fullName() << " line "<< (*it)->line << " col " << (*it)->col << endl; #endif bool instrumented = false; /* NOTE: We need to change this for line level instrumentation. It can * happen that the routine's entry line is also specified for line level * instrumentation */ if (lastInstrumentedLineNo >= (*it)->line ) { // Hey! This line has already been instrumented. Go to the next // entry in the func #ifdef DEBUG cout <<"Entry already instrumented or brace not found - reached next routine! line = "<<(*it)->line <kind == INSTRUMENTATION_POINT) { #ifdef DEBUG cout <<"Instrumentation Point: inbuf = "<snippet<line) { // write the input line in the output stream ostr << inbuf <kind) { case ROUTINE: // we're at the desired line no. search for an open brace inbufLength = strlen(inbuf); for(i=0; i< inbufLength; i++) { if ((inbuf[i] == '{') && (instrumented == false)) { #ifdef DEBUG cout <<"found the *first* { on the line inputLineNo=" <col ; space++) ostr << " " ; #endif if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { /* XXX Insert code here */ } else { ostr <<" "<item) ; if (!((*it)->isTarget)) { // it is a template member. Help it by giving an additional () // if the item is a member function or a static member func give // it a class name using CT ostr <<"\", CT(*this), "; } else // it is not a class member { ostr << "\", \" \", "; // null type arg to TAU_PROFILE } if (strcmp((*it)->item->name().c_str(), "main")==0) { /* it is main() */ ostr << "TAU_DEFAULT);" <col ; space++) ostr << " " ; #endif // leave some leading spaces for formatting... print_tau_profile_init(ostr, (pdbCRoutine *) (*it)->item); ostr <<"#ifndef TAU_MPI" <col-1] = "<col-1]<col-1; k++) ostr<col-1], "abort", strlen("abort")) == 0) ||(strncmp(&inbuf[(*it)->col-1], "exit", strlen("exit")) == 0) ||(using_exit_keyword && (strncmp(&inbuf[(*it)->col-1], exit_keyword, strlen(exit_keyword)) == 0) )) { #ifdef DEBUG cout <<"WRITING EXIT RECORD "<snippet.empty()) ostr<<(*it)->snippet<col-1; k < strlen(inbuf) ; k++) ostr<line, (*it)->col); fprintf (stderr, "If the exit call occurs in a macro (likely), make sure you place a \"TAU_PROFILE_EXIT\" before it (note: this warning will still appear)\n"); for (k = (*it)->col-1; k < strlen(inbuf); k++) ostr<col-1; k++) ostr<snippet<<"\", \" \", TAU_USER);"<col-1; k++) ostr<<" "; /* put spaces */ /* if there is another instrumentation request on the same line */ instrumented = true; if ((it+1) != itemvec.end()) { /* there are other instrumentation requests */ if (((*it)->line == (*(it+1))->line) && ((*(it+1))->kind == STOP_LOOP_TIMER)) { write_upto = (*(it+1))->col - 1 ; #ifdef DEBUG cout <<"There was a stop timer on the same line: "<<(*it)->line<col-1; k < write_upto; k++) ostr<col-1; k < strlen(inbuf) ; k++) ostr<col-1; k++) ostr<col-1; k < strlen(inbuf) ; k++) ostr<col-1; k++) ostr<col-1; k < strlen(inbuf) ; k++) ostr< line = "<< (*it)->line<attribute == AFTER) { ostr << (*it)->snippet<col-1; space++) ostr <<" "; } #ifdef DEBUG printf("it col -1 = %d, write_upto = %d\n", (*it)->col-1, write_upto); #endif /* DEBUG */ for (i = (*it)->col-1; i < write_upto; i++) { #ifdef DEBUG printf("Writing (3.1) inbuf[%d] = %c\n", i, inbuf[i]); #endif /* DEBUG */ ostr << inbuf[i]; } if (print_cr) ostr <kind< 64) { string first = suffix.substr(0,64); suffix.erase(0,64); full = full + " &"+first+"&\n"; } full = full + " &"+suffix+"')"; ostr << full << endl; } /* -------------------------------------------------------------------------- */ /* -- writeFortranTimer writes the long timer name in two or more statements */ /* -- if necessary. It invokes writeLongFortranStatement ------------------- */ /* -------------------------------------------------------------------------- */ void writeFortranTimer(ostream &ostr, string timername, itemRef *i) { string prefix; if (i->isDynamic) { ostr << " tau_iter = tau_iter + 1"<isPhase) { /* dynamic phase */ prefix = string(" call TAU_PHASE_DYNAMIC_ITER(tau_iter, profiler, '"); } else { /* dynamic timer */ prefix = string(" call TAU_PROFILE_DYNAMIC_ITER(tau_iter, profiler, '"); } /* end of dynamic */ } else { /* it is static */ if (i->isPhase) { /* static phase */ prefix = string(" call TAU_PHASE_CREATE_STATIC(profiler, '"); } else { /* static timer */ prefix = string(" call TAU_PROFILE_TIMER(profiler, '"); } /* static timer */ } /* is static? */ writeLongFortranStatement(ostr, prefix, timername); } /* -------------------------------------------------------------------------- */ /* -- BodyBegin for a routine that does return some value ------------------- */ /* -------------------------------------------------------------------------- */ void processBodyBegin(ostream& ostr, itemRef *i, string& group_name) { int space; ostr << "{\n"; writeAdditionalDeclarations(ostr, (pdbRoutine *)(i->item)); ostr << "\n\t"; if (use_spec) { ostr << i->snippet << endl; /* XXX Insert code here */ } else if (use_perflib) { ostr<<"Perf_Update(\"" <<((pdbRoutine *)(i->item))->name() << "\", 1);"<item) << "\", \" " << "\", "; // ((pdbRoutine *)(i->item))->signature()->name() << "\", "; if (strcmp(i->item->name().c_str(), "main")==0) { /* it is main() */ ostr << "TAU_DEFAULT);" <col ; space++) ostr << " " ; #endif // leave some leading spaces for formatting... print_tau_profile_init(ostr, (pdbCRoutine *) (i->item)); ostr <<"#ifndef TAU_MPI" <snippet << endl; } } /* -------------------------------------------------------------------------- */ /* -- Checks to see if string is blank ------------------------------------- */ /* -------------------------------------------------------------------------- */ bool isBlankString(string& s) { int i; const char * chr = s.c_str(); if (!chr) { /* if chr is 0 or null, it is blank. */ return true; } else { /* it is not null, we need to examine each character */ i = 0; while (chr[i] != '\0') { /* keep going to the end ... */ if (! (chr[i] == ' ' || chr[i] == '\t')) return false; /* if it is not a space, just return a false -- it is not a blank */ i++; /* see next character */ } /* reached the end, and didn't find any non-white space characters */ } return true; /* the string has only white space characters */ } /* -------------------------------------------------------------------------- */ /* -- Close the loop timer before the return ---------------- */ /* -------------------------------------------------------------------------- */ void processCloseLoopTimer(ostream& ostr) { for (list::iterator siter = current_timer.begin(); siter != current_timer.end(); siter++) { /* it is not empty -- we must shut the timer before exiting! */ #ifdef DEBUG cout <<"Shutting timer "<<(*siter)<<" before stopping the profiler "<snippet))) { ostr <<"{ "; processCloseLoopTimer(ostr); ostr << it->snippet << " "; if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { ostr<<"Perf_Update(\""<< ((pdbRoutine *)(it->item))->name()<<"\", 0);"; } else { ostr <item))->signature()->returnType(); if ( const pdbGroup* gr = t->isGroup() ) { return_type = gr->fullName(); } else { return_type = t->fullName(); } /* Replace ">>" with "> >" for compilation */ string::size_type pos=string::npos; while ((pos=return_type.find(">>"))!=string::npos) { return_type.replace(pos,2,"> >"); } /* Replace "$NA$::" with "" for unnamed namespaces */ while ((pos=return_type.find("$NA$::"))!=string::npos) { return_type.replace(pos,6,""); } /* Declare and assign the return value */ ostr <<"{ " << return_type << " tau_ret_val = " << ret_expression << "; "; processCloseLoopTimer(ostr); ostr << it->snippet << " "; if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { ostr<<"Perf_Update(\""<< ((pdbRoutine *)(it->item))->name()<<"\", 0); "; } else { ostr<snippet.empty()) { ostr<snippet<item))->name()<<"\", 0);}"; } else { ostr<<"TAU_PROFILE_EXIT("<<"\""<snippet.empty()) { ostr<snippet<item))->name()<<"\", 0);"; } else { ostr<<"TAU_PROFILE_EXIT("<<"\""<name()); static char inbuf[INBUF_SIZE]; // to read the line static char exit_type[EXIT_KEYWORD_SIZE]; // to read the line string exit_expression; bool abort_used = false; char newline; newline = '\n'; /* for C \ processing in return statements */ // open outfile for instrumented version of source file ofstream ostr(outfile.c_str()); string timercode; /* for outer-loop level timer-based instrumentation */ if (!ostr) { cerr << "Error: Cannot open '" << outfile << "'" << endl; return false; } // 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 memset(inbuf, INBUF_SIZE, 0); // reset to zero // initialize reference vector vector itemvec; if (!use_spec) { /* In "spec" mode, only the file instrumentation requests are used */ getCReferences(itemvec, pdb, f); } /* check if the given file has line/routine level instrumentation requests */ if (!isInstrumentListEmpty()) { /* there are finite instrumentation requests, add requests for this file */ addFileInstrumentationRequests(pdb, f, itemvec); } /* All instrumentation requests are in. Now do postprocessing. */ postprocessInstrumentationRequests(itemvec); // Begin Instrumentation // put in code to insert if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { ostr<< "void Perf_Update(char *name, int entry);"<"<"<::iterator lit = itemvec.begin(); while (lit != itemvec.end() && !istr.eof()) { // Read one line each till we reach the desired line no. #ifdef DEBUG if ((*lit) && (*lit)->item) { cout <<"S: "<< (*lit)->item->fullName() << " line "<< (*lit)->line << " col " << (*lit)->col << endl; } #endif bool instrumented = false; while((instrumented == false) && (istr.getline(inbuf, INBUF_SIZE))) { inputLineNo ++; if (inputLineNo < (*lit)->line) { // write the input line in the output stream ostr << inbuf <col)-1; i++) { ostr << inbuf[i]; } vector::iterator it; for (it = lit; ((it != itemvec.end()) && ((*it)->line == (*lit)->line)); ++it) { /* it/lit */ inbufLength = strlen(inbuf); /* set instrumented = true after inserting instrumentation */ int write_from, write_upto; int k; write_from = ((*it)->col)-1; /* Examine the instrumentation request */ switch ((*it)->kind) { case BODY_BEGIN: processBodyBegin(ostr, *it, group_name); instrumented = true; break; case RETURN: process_this_return = false; if (strncmp((const char *)&inbuf[((*it)->col)-1], return_void_string, strlen(return_void_string))==0) { if (!isalnum(inbuf[((*it)->col)-1 + strlen(return_void_string)])) { process_this_return = true; strcpy(use_return_void, return_void_string); } } if (strncmp((const char *)&inbuf[((*it)->col)-1], return_nonvoid_string, strlen(return_nonvoid_string))==0) { if (!isalnum(inbuf[((*it)->col)-1 + strlen(return_nonvoid_string)])) { process_this_return = true; strcpy(use_return_nonvoid, return_nonvoid_string); } } if (strncmp((const char *)&inbuf[((*it)->col)-1], "return", strlen("return")) == 0) { if (!isalnum(inbuf[((*it)->col)-1 + strlen("return")])) { process_this_return = true; strcpy(use_return_void, "return"); strcpy(use_return_nonvoid, "return"); } } if (process_this_return) { if (isVoidRoutine((*it)->item)) { /* instrumentation code here */ if (use_spec) { ostr << "{ " << (*it)->snippet << " " << use_return_void << "; }" << endl; /* XXX Insert code here */ } else if (use_perflib) { ostr<<"{ Perf_Update(\""<< ((pdbRoutine *)((*it)->item))->name()<<"\", 0);"<snippet << " " <col)-1; inbuf[k] !=';'; k++) { ; } write_from = k+1; } else { string ret_expression; char current_char; char match_char; for (k = (*it)->col+strlen(use_return_nonvoid)-1; (inbuf[k] != ';') && (ksnippet << endl; /* XXX Insert code here */ } else if (use_perflib) { ostr<<"\n}\n\tPerf_Update(\""<< ((pdbRoutine *)((*it)->item))->name()<<"\", 0);"<snippet << endl; ostr<<"\t"<col-1] = "<col-1]<col-1], "abort", strlen("abort")) == 0) { strcpy(exit_type, "abort"); abort_used = true; /* abort() takes void */ } if (strncmp(&inbuf[(*it)->col-1], "exit", strlen("exit")) == 0) { strcpy(exit_type, "exit"); } if (using_exit_keyword && (strncmp(&inbuf[(*it)->col-1], exit_keyword, strlen(exit_keyword)) == 0)) { strcpy(exit_type, exit_keyword); } #ifdef DEBUG cout <<"Return for a non void routine "<col+strlen(exit_type)-1; (inbuf[k] != ';') && (kline, (*it)->col); fprintf (stderr, "If the exit call occurs in a macro (likely), make sure you place a \"TAU_PROFILE_EXIT\" before it (note: this warning will still appear)\n"); // write the input line in the output stream } instrumented = true; break; case INSTRUMENTATION_POINT: #ifdef DEBUG cout <<"Instrumentation point in C -> line = "<< (*it)->line<attribute == AFTER) ostr<snippet<attribute == AFTER) ostr<snippet+", 1); "); } else { timercode = string(string("{ TAU_PROFILE_TIMER(lt, \"")+(*it)->snippet+"\", \" \", TAU_USER); TAU_PROFILE_START(lt); "); } #ifdef DEBUG cout <<"Inserting timercode: "<col-1; space++) ostr<<" "; instrumented = true; current_timer.push_front((*it)->snippet); /* Add this timer to the list of currently open timers */ break; case STOP_LOOP_TIMER: if ((*it)->attribute == AFTER) ostr<col-1; space++) ostr<<" "; if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { timercode = string(string(" Perf_Update(\"" )+(*it)->snippet+", 0); } "); } else { timercode = "TAU_PROFILE_STOP(lt); } "; } ostr << timercode << endl; instrumented = true; /* pop the current timer! */ if (!current_timer.empty()) current_timer.pop_front(); break; case GOTO_STOP_TIMER: ostr << "{ "; if (use_spec) { /* XXX Insert code here */ } else if (use_perflib) { /* XXX Insert code here */ } else { ostr <<"TAU_PROFILE_STOP(lt);"; } for (k = (*it)->col-1; k < strlen(inbuf); k++) ostr<kind<line == (*it)->line ? (*(it+1))->col-1 : inbufLength; #ifdef DEBUG cout <<"CHECKING write_from "<line<<", "<<(*it)->col<<") ;"; cout <<"it+1 = ("<<(*(it+1))->line<<", "<<(*(it+1))->col<<") ;"<= hay_length) { /* it's fine */ check_after = true; /* ok */ continue; } /* aha! there is something else going on -- returned for instance */ #ifdef DEBUG printf("Col after return = %d, value = %c, length=%d\n", col_found +needle_length, local_haystack[col_found+needle_length], hay_length); #endif /* DEBUG */ if (isalnum(local_haystack[col_found+needle_length])) { local_haystack[col_found] = '^'; /* check again ^eturned */ continue; /* searching again */ } else { /* character is ok */ check_after = true; continue; } } /* keep searching until before and after are ok */ int diff = 0; if (res) { diff = res - local_haystack + 1 ; /* columns start from 1, not 0 */ #ifdef DEBUG printf("needle:%s\n", needle); printf("haystack:%s\n", local_haystack); printf("diff = %d\n", diff); #endif /* DEBUG */ } free((void *)local_haystack); return diff; } /* -------------------------------------------------------------------------- */ /* -- Does the statement contain this keyword? ------------------------------ */ /* -------------------------------------------------------------------------- */ bool isKeywordPresent(char *line, const char *keyword) { bool present; if ((!((line[0] == 'c') || (line[0] == 'C') || (line[0] == '!'))) && ( CPDB_GetSubstringCol(line, keyword) > 0 )) present = true; else present = false; /* is it present? */ #ifdef DEBUG cout <<"isKeywordPresent:"<0) ) return */ #ifdef DEBUG cout <<"columnToCheckFrom = "< 0; c--) { #ifdef DEBUG cout <<"c = "<col - 1; */ checkbuf[i] = currentline[i]; } checkbuf[i] = '\0'; /* now that it is filled in, let us see if it has a "if" in it */ is_if_stmt = isKeywordPresent(checkbuf, "if"); /* Before we declare that we should insert the then clause, * we need to ensure that a then does not appear in the statement already */ if (is_if_stmt == true) { /* does a then appear? */ if (isKeywordPresent(checkbuf, "then")) is_if_stmt = false; /* here we are merely checking if we are inside a single-if * statement, one that does not have a then clause. If there * is a then clause in the same statement, then we classify * is_if_stmt as false */ } /* Check to see if return is in a continuation line */ /* such as : * if( (ii/=jj .or. kk<=0) .and. & * & (kcheck==0 .or. ii/=lsav+1 .or. kk>0) ) return */ if (is_if_stmt == false) { //removeCommentFromLine(currentline); removeCommentFromLine(previousline); if(isContinuationLine(currentline, previousline, currentcol - 1 )) { /* check from one less than the current column number: (*it)->col - 2. */ is_if_stmt = true; } } /* Here, either is_if_stmt is true or it is a plain return*/ #ifdef DEBUG cout <<"if_stmt = "<(functionname.c_str()); /* go back -- Jeff doesn't like the stripped name anymore */ return nm; /* Here is the code to strip the code */ /* traverse the string till you get rid of the :: using strstr */ while (s = strstr(nm, "::")) { nm += strlen(s)+1; } return nm; } /* -------------------------------------------------------------------------- */ /* -- does it continue onto the next line? ---------------------------------- */ /* -------------------------------------------------------------------------- */ int doesStmtContinueOntoNextLine(char * & inbuf, int openparens) { /* This checks for ( and ) -- so it works for alloc/dealloc but not IO where a statement can also continue using , instead of ( ). */ char *line = inbuf; int i, len; len = strlen(line); for (i=0 ; i < len, *line; i++, line++) { if (*line == '(') openparens ++; if (*line == ')') openparens --; if (*line == '!') { *line = '\0'; break; } } return openparens; } /* -------------------------------------------------------------------------- */ /* -- isFreeFormat returns true if it has a & in the current line ----------- */ /* -------------------------------------------------------------------------- */ bool isFreeFormat(char inbuf[]) { /* get rid of ! */ if (strstr(inbuf, "&")) { #ifdef DEBUG printf("Continuation character found -- Free format\n"); #endif /* DEBUG */ return true; } else return false; } /* -------------------------------------------------------------------------- */ /* -- getNextToken returns true if it is done, and has no more variables ---- */ /* -- to process in the same line. Extracts variable name from line. - */ /* -------------------------------------------------------------------------- */ bool getNextToken(char* &line, char* &varname) { /* if I pass it "hi ", Ary(x,y)%b(2), B(2) it should return successively "hi " then Ary(x,y)%b(2) then B(2) In contrast, getVariableName returns "hi ", Ary, B for alloc/dealloc */ /* We need to traverse the string till we reach a comma and return it. If we instead see a (, we should continue processing till the closing parens ) */ int openparens = 0; int opensinglequotes, openquotes=0; int i = 0; int len = 0; len = strlen(line); while (i < len) { if (*line == ',' && openparens == 0) { line++; break; /* print *, ... */ } varname[i] = *line; if ((*line == '"') || (*line == '\'')) { char quote = *line; i++; line++; while (*line != quote) { varname[i] = *line; i++; line++; } varname[i] = *line; } if (*line == '(' ) /* first open paren. Search for close parenthesis */ openparens++; if (*line == ')' ) { openparens --; } i++; line++; /* increment and go on */ } varname[i] = '\0'; if (line && *line == ',') line++; /* get rid of comma */ #ifdef DEBUG printf("varname retrieved = %s, line = %s\n", varname, line); #endif /* DEBUG */ len = strlen(line); // printf("length remaining = %d\n", len); if (len == 0) return true; /* done = true! no more to retrieve */ else return false; /* there are more strings to process... */ } static void removeWhitespace(char *str) { int w=0; int len = strlen(str); for (int r=0;r list; virtual void print() { //printf ("size=%d(",list.size()); printf ("( "); for (int i=0; iprint(); printf (", "); } list[list.size()-1]->print(); printf (" )"); } virtual const char *getString() { return 0; } virtual void output(char *iostmt, int id) { if (list.size() == 0) { fprintf (stderr, "Warning: list.size() == 0? (Failed to parse implied-do)\n"); } else if (list.size() == 1) { list[0]->output(iostmt,id); } else { treeElement *iterElement = list[list.size()-1]; strcat(iostmt, " DO "); strcat(iostmt, iterElement->getString()); strcat(iostmt, "\n"); for (int i=0; ioutput(iostmt,id); } strcat(iostmt, " END DO\n"); } } }; class stringTreeElement : public treeElement { public: string str; virtual void print() { printf ("'%s'", str.c_str()); } virtual const char *getString() { return str.c_str(); } virtual void output(char *iostmt, int id) { char phrase[4096]; sprintf (phrase, " tio_%d_sz = tio_%d_sz + sizeof(%s)\n", id, id, str.c_str()); strcat(iostmt, phrase); } }; void recurseCrap(char* &buf, listTreeElement *element) { char *token = new char[4096]; while (*buf) { getImpliedToken(buf,token); // printf ("token = %s\n", token); if (strlen(token) == 1 && token[0] == '(') { listTreeElement *newElement = new listTreeElement(); recurseCrap(buf,newElement); element->list.push_back(newElement); } else if (strlen(token) == 1 && token[0] == ')') { delete[] token; return; } else { stringTreeElement *newElement = new stringTreeElement(); newElement->str = token; element->list.push_back(newElement); } } delete[] token; return; } /* * Process an implied-do construct, see above for definition and examples * We insert DO loops to compute the size */ void processImpliedDo(char *iostmt, char *element, int id) { char tmp[4096]; strcpy (tmp, element); blankQuote(tmp); removeWhitespace(tmp); char *p = tmp; char key[4096]; int nest = 0; int first = 1; int count = 0; listTreeElement *elements = new listTreeElement(); recurseCrap(p, elements); strcat(iostmt,"\n"); // elements->print(); // printf ("\n"); elements->output(iostmt,id); } /* -------------------------------------------------------------------------- */ /* -- getVariableName returns true if it is done, and has no more variables - */ /* -- to process in the same line. Extracts variable name from line. - */ /* -------------------------------------------------------------------------- */ bool getVariableName(char * &line, char * & varname) { int len, i, openparens, varlen; bool done = false; bool foundcompoundstmt = false; char *lastptr; char *firstptr = line; char token = ' '; do { len = strlen(line); #ifdef DEBUG printf("AT THE BEGINNING : line=%s\n", line); #endif for (i = 0; i < len && *line != ',' && *line != ')' && *line != '('; i++, line++) { /* check for the variable name. parsing shouldn't reach a , ) or ( */ varname[i] = *line; lastptr = line; #ifdef DEBUG printf("varname[%d] = %c\n", i, varname[i]); #endif /* DEBUG */ if (varname[i] == '&') varname[i] = ' '; /* we don't want &B */ } varname[i] = '\0'; lastptr ++; /* increment to the end of the variable name */ if (*line == ',') { #ifdef DEBUG printf("HEY! Found a , when we were looking for a (, varname=%s\n", varname); #endif /* DEBUG */ /* go over the , and return from the routine. We have found what we were looking for. e.g., ALLOCATE(tmp_a(ispin)%pw, tmp_b(ispin)%pw) or ALLOCATE(pw1, b(23), stat=stat) in these cases we need to return tmp_a(ispin)% pw and pw1 respectively*/ line++; break; } while (*line && *line != '(') line++; /* go to the first ( */ #ifdef DEBUG printf("after going for ( -- *line = %c\n", *line); #endif /* DEBUG */ if (!*line) { #ifdef DEBUG printf("There were no ( in the allocate statement. Look for , as in allocate(x,y)\n"); #endif /* DEBUG */ line = lastptr; /* reset it */ } /* next count the number of ( opened before we reach a ) */ len = strlen(line); for (i = 0, openparens = 0; i < len, *line; i++, line++) { if (*line == '(') openparens ++; if (*line == ')') openparens --; if (openparens == 0) break; #ifdef DEBUG printf("line = %c, openparens = %d\n", *line, openparens); #endif /* DEBUG */ } //printf("after loop: openparens = %d\n", openparens); if (*line == ')') line ++; while (*line && *line == ' ') line++; /* skip whitespaces */ #ifdef DEBUG if (*line) printf("GETVARNAME: line = %c\n", *line); #endif /* DEBUG */ token = *line; /* assign token here! */ if (token == '%') { #ifdef DEBUG printf("FOUND a percentage symbol AFTER the variable parsing is completed!! line = %s\n", line); /* implies a compound object. A variable that is part of a user defined type is present */ #endif /* DEBUG */ line++; /* advance one token*/ foundcompoundstmt = true; /* found % */ } else { /* look for the comma */ while (*line && *line != ',') line++; /* go to the first , */ #ifdef DEBUG if (*line) printf("After looking for , line = %c, next = %c, done = %d\n", *line, *(line+1), done); #endif /* DEBUG */ if (*line) { #ifdef DEBUG printf("NOT a NULL *line = %c\n", *line); #endif /* DEBUG */ line++; /* skip , */ } else { #ifdef DEBUG printf("NULL??? *line = %c\n", *line); #endif /* DEBUG */ done = true; #ifdef DEBUG printf("And after that: looking for , line = %c, done = %d\n", *line, done); #endif /* DEBUG */ } } #ifdef DEBUG printf("After IF token=%c, foundcompoundstmt=%d\n", token, foundcompoundstmt); #endif /* DEBUG */ } while (token == '%'); #ifdef DEBUG printf("foundcompoundstmt = %d, lastptr = %c\n",foundcompoundstmt, *lastptr); #endif /* DEBUG */ if (foundcompoundstmt) { for (i=0; firstptr != lastptr; i++) { varname[i] = *firstptr; #ifdef DEBUG printf("ASSIGNING varname[%d] = %c\n", i, varname[i]); #endif /* DEBUG */ if (varname[i] == '&') varname[i] = ' '; /* we don't want &B */ firstptr++; } varname[i] = '\0'; } #ifdef DEBUG printf("Got: line = %s, varname=%s, done=%d\n", line, varname, done); #endif /* DEBUG */ return done; } /* -------------------------------------------------------------------------- */ /* -- isFreeFormat returns true if it has a & in the current line ----------- */ /* -------------------------------------------------------------------------- */ bool isRequestOnSameLineAsPreviousRequest(vector::iterator& it, vector& itemvec) { int currentLine = (*it)->line; int prevLine = it == itemvec.begin()? 0 : (*(it-1))->line; /* if it is null, prevLine = 0 */ if (currentLine == prevLine) { #ifdef DEBUG printf("isRequestOnSameLineAsPreviousRequest returns true line = %d\n", currentLine); #endif /* DEBUG */ return true; } else return false; } /* -------------------------------------------------------------------------- */ /* -- Write call TAU_ALLOC(...) statement ----------------------------------- */ /* -------------------------------------------------------------------------- */ int printTauAllocStmt(ifstream& istr, ofstream& ostr, char inbuf[], vector::iterator& it, char *& laststatement) { /* consider the string: allocate(A(100), stat=ierr) */ #ifdef DEBUG cout <<"Allocate Stmt: line ="<<(*it)->line<line<< ", " <snippet<< ", var=" <line, tau_size_tok.c_str(), p); sprintf(suffixstmt, "%s, variable=%s", (*it)->snippet.c_str(), p); string prefix=string(allocstmt); string suffix=string(suffixstmt); writeLongFortranStatement(ostr, prefix, suffix); #ifdef DEBUG printf("Putting in file: varname=%s, line = %s\n", varname, line); #endif /* DEBUG */ } else break; /* end of processing */ } delete[] allocstmt; delete[] varname; return linesread; } /* -------------------------------------------------------------------------- */ /* -- Write call TAU_DEALLOC(...) statement --------------------------------- */ /* -------------------------------------------------------------------------- */ int printTauDeallocStmt(ifstream& istr, ofstream& ostr, char inbuf[], vector::iterator& it, bool writetab, char *& laststatement) { int i, len; char suffixstmt[64*1024]; int openparens, linesread=0; /* how many additional lines (cont) did we read? */ char *deallocstmt = new char[INBUF_SIZE]; int isfree; bool done = false; char *varname = new char [INBUF_SIZE]; char *start; char *line; list statements; list::iterator sit; ostr<line); cout <<"inbuf ="<<*inbuf<line<< ", " <snippet<< ", var=" <line); sprintf(suffixstmt, "%s, variable=%s", (*it)->snippet.c_str(), p); string prefix=string(deallocstmt); string suffix=string(suffixstmt); writeLongFortranStatement(ostr, prefix, suffix); #ifdef DEBUG printf("Putting in file: varname=%s, line = %s\n", varname, line); #endif /* DEBUG */ } else break; /* end of processing */ } // ostr<<"\t call TAU_DEALLOC(A, "<<(*it)->line<< ", '"<< (*it)->snippet<< ", var=A')"<::iterator& it, bool writetab, char *& laststatement) { int i, len, origlen, sizeoflen; char string_containing_sizeof[64*1024]; int openparens, linesread=0; /* how many additional lines (cont) did we read? */ char *iostmt = new char[INBUF_SIZE]; int isfree; bool done = false; char *varname = new char [INBUF_SIZE]; char *start; char *line; int lineno, numlines; list statements; list::iterator sit; ostr<line; numlines = (*it)->end.line() - (*it)->begin.line(); /* Now there are two points -- begin and end that are available for this IO statement. By checking if the line numbers differ, we can tell if it has a continuation line */ #ifdef DEBUG printf("INSIDE printTauIOStmt: inbuf=%s --> line= %d, spanning %d lines \n", inbuf, lineno, numlines); cout <<"IO Stmt: line ="<= 72) { /* exceeds 72 columns -- break it up! */ sprintf(string_containing_sizeof, "\n tio_%d_sz = tio_%d_sz+sizeof(%s)", lineno, lineno, p); } strcat(iostmt, string_containing_sizeof); } } ostr <name()); string codesnippet; /* for START_TIMER, STOP_TIMER */ static char inbuf[INBUF_SIZE]; // to read the line static char * previousline = new char [INBUF_SIZE]; // to read the line char *checkbuf=NULL; // Assign inbuf to checkbuf for return processing // open outfile for instrumented version of source file ofstream ostr(outfile.c_str()); int space, i, j, k, c, additionalLinesRead; int docol, ifcol, thencol, gotocol, alloccol, dealloccol, startcol, iocol; if (!ostr) { cerr << "Error: Cannot open '" << outfile << "'" << endl; return false; } // open source file ifstream istr(file.c_str()); if (!istr) { cerr << "Error: Cannot open '" << file << "'" << endl; return false; } #ifdef DEBUG cout << "Processing " << file << " in instrumentFFile..." << endl; #endif memset(previousline, INBUF_SIZE, 0); // reset to zero memset(inbuf, INBUF_SIZE, 0); // reset to zero // initialize reference vector vector itemvec; if (!use_spec) { /* In "spec" mode, only file instrumentation requests are used */ getFReferences(itemvec, pdb, f); } /* check if the given file has line/routine level instrumentation requests */ if (!isInstrumentListEmpty() || memory_flag) { /* there are finite instrumentation requests, add requests for this file */ addFileInstrumentationRequests(pdb, f, itemvec); } /* All instrumentation requests are in. Now do postprocessing. */ postprocessInstrumentationRequests(itemvec); int inputLineNo = 0; bool is_if_stmt; vector::iterator lit = itemvec.begin(); /* Iterate through the list of instrumentation requests */ while (lit != itemvec.end() & !istr.eof()) { // Read one line each till we reach the desired line no. #ifdef DEBUG if ((*lit) && (*lit)->item) cout <<"S: "<< (*lit)->item->fullName() << " line "<< (*lit)->line << " col " << (*lit)->col << endl; #endif bool instrumented = false; while((instrumented == false) && (istr.getline(inbuf, INBUF_SIZE)) ) { inputLineNo ++; if (inputLineNo < (*lit)->line) { // write the input line in the output stream #ifdef DEBUG cout <<"Writing (3): "<line <<" Col " <<(*lit)->col <::iterator it; int write_upto = 0; bool print_cr = true; for(it = lit; ((it != itemvec.end()) && ((*it)->line == (*lit)->line)); ++it) { /* it/lit */ if (it+1 != itemvec.end()) { if ((*(it+1))->line == (*it)->line) { write_upto = (*(it+1))->col - 1; print_cr = false; } else { write_upto = inbufLength; print_cr = true; } /* write_upto = (*(it+1))->line == (*it)->line ? (*(it+1))->col-1 : inbufLength; */ #ifdef DEBUG cout <<"CHECKING write_upto = "<col<<") ; "; cout <<"it+1 = "<<(*(it+1))->line <<", "<<(*(it+1))->col <<") ;"<item && (((pdbRoutine *)(*it)->item)->fprefix() == pdbItem::FP_PURE || ((pdbRoutine *)(*it)->item)->fprefix() == pdbItem::FP_ELEM)) { pure = 1; } #endif // get the instrumented routine name string instrumentedName = getInstrumentedName((*it)->item); /* set instrumented = true after inserting instrumentation */ switch((*it)->kind) { case BODY_BEGIN: // write out the line up to the desired column for (i=0; i< ((*it)->col)-1; i++) { ostr << inbuf[i]; } // break the line ostr << endl; if (use_spec) { writeAdditionalDeclarations(ostr, (pdbRoutine *)((*it)->item)); ostr << "\t" << (*it)->snippet << endl; writeAdditionalFortranInvocations(ostr, (pdbRoutine *)((*it)->item)); ostr << " "; // write the rest of the original statement for (k = (*it)->col-1; k < write_upto ; k++) { ostr << inbuf[k]; } if (print_cr) { ostr << endl; } instrumented = true; break; } else if (use_perflib) { if (pure && instrumentPure) { ostr << " interface\n"; ostr << " pure subroutine f_perf_update(name, flag)\n"; ostr << " character(*), intent(in) :: name\n"; ostr << " logical, intent(in) :: flag\n"; ostr << " end subroutine f_perf_update\n"; ostr << " end interface\n"; } // should we call MPI_Init? Only if it is the main program /* if (((pdbRoutine *)(*it)->item)->kind() == pdbItem::RO_FPROG) { ostr << " INTEGER tau_mpi_init_err"<item->fullName()<<"', 0, 0, 'UNKNOWN')"<item->fullName())<<"', .true.)"<col-1; k < write_upto ; k++) { ostr << inbuf[k]; } if (print_cr) { ostr << endl; } instrumented = true; break; } if (pure) { if (instrumentPure) { ostr << " interface\n"; ostr << " pure subroutine TAU_PURE_START(name)\n"; ostr << " character(*), intent(in) :: name\n"; ostr << " end subroutine TAU_PURE_START\n"; ostr << " pure subroutine TAU_PURE_STOP(name)\n"; ostr << " character(*), intent(in) :: name\n"; ostr << " end subroutine TAU_PURE_STOP\n"; ostr << " end interface\n"; } } else { #ifdef TAU_ALIGN_FORTRAN_INSTRUMENTATION // alignment issues on solaris2-64 and IRIX64 require a value that will be properly aligned ostr << " DOUBLE PRECISION profiler / 0 /"<item)); if (((pdbRoutine *)(*it)->item)->kind() == pdbItem::RO_FPROG) { // main ostr << " call TAU_PROFILE_INIT()"<"+instrumentedName; writeFortranTimer(ostr, groupInstrumentedName, (*it)); } else { /* group_name is not defined, write the default fullName of the routine */ writeFortranTimer(ostr, instrumentedName, (*it)); } } } /* spaces */ for (space = 0; space < (*it)->col-1 ; space++) WRITE_SPACE(ostr, inbuf[space]) WRITE_TAB(ostr,(*it)->col); if (pure) { if (instrumentPure) { ostr << "call TAU_PURE_START('" << instrumentedName << "')"<item)); if (!(*it)->snippet.empty()) ostr << "\n\t" << (*it)->snippet << "\n"; if (use_spec) ostr << "\t"; #ifdef DEBUG printf("Before 2.1: (*it)->col = %d, write_upto=%d\n", (*it)->col, write_upto); #endif /* DEBUG */ if ((*it)->col != 1) ostr << " "; // IMPORTANT: If the formatting of the next statement is wrong, please remove the above comment! // write the rest of the original statement for (k = (*it)->col-1; k < write_upto ; k++) { ostr << inbuf[k]; #ifdef DEBUG printf("WRITING 2.1 : inbuf[%d] = %c\n", k, inbuf[k]); #endif /* DEBUG */ } /* should we write the carriage return? */ if (print_cr) { ostr<< endl; } instrumented = true; break; case EXIT: case RETURN: #ifdef DEBUG cout <<"RETURN/EXIT statement "< 1 && (*it)->kind == EXIT) { #ifdef DEBUG cout <<"RETURN/EXIT statement was EXIT but return was found!"<line, col); */ if (col && col > (*it)->col && lit!=it) { for(i=(*it)->col-1; i < col-1; i++) { ostr<col = col; } #ifdef DEBUG cout <<"Return is found at "<< (*it)->line<<" Column: "<<(*it)->col<col > strlen(inbuf)) { fprintf(stderr, "ERROR: specified column number (%d) is beyond the end of the line (%d in length)\n",(*it)->col,strlen(inbuf)); fprintf(stderr, "line = %s (%d)\n",inbuf,(*it)->line); exit(-1); } is_if_stmt = addThenEndifClauses(inbuf, previousline, (*it)->col - 1); if (lit == it) { /* Has body begin already written the beginning of the statement? */ /* No. Write it (since it is same as lit) */ for(i=0; i< ((*it)->col)-1; i++) { #ifdef DEBUG cout << "Writing (1): "<col); /* before writing stop/exit examine the kind */ if ((*it)->kind == EXIT) { /* Turn off the timers. This is similar to abort/exit in C */ if (!(*it)->snippet.empty()) ostr << (*it)->snippet << "\n\t"; if (use_spec) { /* XXX Insert code here */ ostr << endl; } else if (use_perflib) ostr <<"call f_perf_update('"<item->fullName())<<"', .false.)"<item->fullName())<< "', .false.)"<::iterator siter = current_timer.begin(); siter != current_timer.end(); siter++) { /* it is not empty -- we must shut the timer before exiting! */ #ifdef DEBUG cout <<"Shutting timer "<<(*siter)<<" before stopping the profiler "<snippet.empty()) ostr << (*it)->snippet << "\n\t"; if (use_spec) { /* XXX Insert code here */ ostr << endl; } else if (use_perflib) ostr <<"call f_perf_update('"<item->fullName())<<"', .false.)"<col-1 ; space++) WRITE_SPACE(ostr, inbuf[space]) instrumented = true; for(j= ((*it)->col)-1; j Line = "<< (*it)->line<<" col "<<(*it)->col <<" write_upto = "<line<::iterator institer = it; while ((*institer) && (*institer)->line == (*it)->line) { if ((*institer)->item && (*institer)->kind== BODY_BEGIN) { rid = ((pdbRoutine *)(*institer)->item)->id(); #ifdef DEBUG cout <<"Found routine = "<snippet); /* assign the list of strings to the list */ } else { WRITE_SNIPPET((*it)->attribute, (*it)->col, 0, (*it)->snippet, true); } /* if there is another instrumentation point on the same line, it will take care of the write_upto part */ } else { WRITE_SNIPPET((*it)->attribute, (*it)->col, write_upto, (*it)->snippet, false); } instrumented = true; break; case START_DO_TIMER: case START_TIMER: docol = (*it)->col; /* I've commented this section out because it produces incorrect results for named loops, e.g. loopone: do i=1,6 ... enddo loopone I believe it was intented to fix incorrect pdb files where the start of the do loop for a labeled do was pointing to the label instead of the D in DO. This has been fixed in flint now though. */ // if ((*it)->kind == START_DO_TIMER) // { // docol = CPDB_GetSubstringCol(inbuf,"do"); // #ifdef DEBUG // cout <<"START_DO_TIMER point Fortran -> line = "<< (*it)->line // <<" col = "<< (*it)->col <<" write_upto = "<< write_upto // <<" timer = "<<(*it)->snippet<< " docol = "<snippet+")"; WRITE_SNIPPET((*it)->attribute, docol, write_upto, codesnippet, true); instrumented = true; /* Push the current timer name on the stack */ current_timer.push_front((*it)->snippet); break; case GOTO_STOP_TIMER: #ifdef DEBUG cout <<"GOTO_STOP_TIMER point Fortran -> line = "<< (*it)->line <<" timer = "<<(*it)->snippet<" instead of "goto