/************************************************************************ ************************************************************************/ /************************************************************************ stack.cc Author: Ryan K. Harris Source file for stack class. ************************************************************************* Member functions: push -- push one tray onto top of the stack ************************************************************************/ #include "stack.h" #include using namespace std; /************************************************************************ stack::push Push one tray onto top of the stack. When it does this, it proceeds based on the exchange type: If it is type (1) (a call to a routine), it leaves this function at the top of the stack. It then calculates the difference between the previousTray's timeStamp and the current tray on top; this equals the exclusive time for the previousTray. If it is type (2) a return from a subroutine, it removes the new type (2) tray and the associated type (1) tray which should be the previous tray, i.e. should be on the stack directly before the current type (2). When it removes these two, it calculates the difference between them, this equals the inclusive time. After making either of these calculations, the calculated amount is added to either the exclusive or inclusive totals stored as private variables inside of the 'function' type nodes within the associated 'cpu' node. Operations marked with 'Equi' are sample manipulations equivalent to the timestamp operations being performed. Parameters: functionID, timeStamp, exchangeType, a_samples, n_samplesdim ************************************************************************/ void stack::push(int n_functionID, double n_timeStamp, unsigned long long * a_samples, int n_samplesdim, int n_exchangeType) { /* If only a part of the trace is being analyzed the startMets and endMets values must be initialized like startTime and endTime */ if(startTime != -1) { if((startset == 0) && (n_timeStamp >= startTime)) { startset = 1; startMets = a_samples; } if((endset == 0) && (n_timeStamp >= endTime)) { endset = 1; endMets = a_samples; } } if(n_exchangeType == 5) { newtray(n_functionID,n_timeStamp, a_samples, n_samplesdim); } else if(n_exchangeType == 1) { routine(n_functionID,n_timeStamp, a_samples, n_samplesdim); } else if(n_exchangeType == 2) { returnfrom(n_functionID,n_timeStamp, a_samples, n_samplesdim); } }//push void stack::newtray(int n_functionID, double n_timeStamp, unsigned long long * a_samples, int n_samplesdim) { /* Build a new tray. We have a special build process when a n_exhcangeType == 5 is received. This means that there was an 'Upfrom' event, but we want stack class to be able to handle this without major modification. I originally designed this stack class around 'Upto' and 'Downto' events since those were the original examples I was given. Therefore this forces 'Upfrom' to be a special case. Basically I just alter some variables as though an 'Upto' event was received, after making some safety checks. */ //if(n_exchangeType == 5) //{ if(topTray != 0) { int topID = topTray->getFunctionID(); int topExchange = topTray->getExchangeType(); if((topID == n_functionID) && (topExchange == 1)) { tray * topPrev = topTray->getPrevious(); if (topPrev) { /* has a parent tray */ n_functionID = topPrev->getFunctionID(); } else { /* detected termination on the given thread */ /* set n_functionID to -1 which is checked later */ n_functionID = -1; } returnfrom(n_functionID, n_timeStamp,a_samples, n_samplesdim); //n_exchangeType = 2;//??? } else { cerr << "received 'Upfrom' exchangeType(5) event, " << "but the topTray in 'stack' has diff funcID or top.exchangeType != 1.\n"; parent->stackError = 1; return; } } else { cerr << "received 'Upfrom' exchangeType(5) event, " << "but the topTray in 'stack' is a NULL pointer.\n"; parent->stackError = 1; return; } }//newtray /* If this is a call to a routine. */ //if(n_exchangeType == 1) void stack::routine(int n_functionID, double n_timeStamp, unsigned long long * a_samples, int n_samplesdim) { tray * tempTray = new tray( n_functionID, n_timeStamp, a_samples, n_samplesdim, 1); /* The following is for timeStamp error detection. */ if(parent->lastTimeOne > n_timeStamp) { parent->totalOutOrder += 1; parent->lastTimeTwo = parent->lastTimeOne; parent->lastTimeOne = n_timeStamp; }//if else { if((parent->lastTimeTwo == n_timeStamp) && (parent->lastTimeOne < n_timeStamp)) { parent->totalRepeats += 1; }//if parent->lastTimeTwo = parent->lastTimeOne; parent->lastTimeOne = n_timeStamp; }//else /* Check whether stack is empty. */ if(topTray == 0) { topTray = tempTray; int tempFuncID = topTray->getFunctionID(); node * tempNode = parent->funcTree->getFuncNode(tempFuncID); double tempTime = tempTray->getTimeStamp(); //int * tempSamps = tempTray->getSamples(); if((startTime != -1) && (endTime != -1)) { if((startTime <= tempTime) && (tempTime <= endTime)) { tempNode->incCount(); }//if }//if else { tempNode->incCount(); } topTray->setLastEntrance(n_timeStamp); topTray->setLastSamples(a_samples);//Equi! return; } else { tempTray->setLastEntrance(n_timeStamp); tempTray->setLastSamples(a_samples);//Equi! // topTray->setNext(tempTray); tempTray->setPrevious(topTray); /* Now calculate the exclusive time for previous function. */ /* New addition: we now implement the ability for the user to specify time intervals, so we first determine if this event is in their requested interval. */ double tempTime = tempTray->getTimeStamp(); unsigned long long * tempSamps = tempTray->getSamples();//Equi! double tempExclusive = -1; // Holds difference to be added. unsigned long long * tempSampExclusive = new unsigned long long[n_samplesdim];//Equi! //double lastTime = lastEntry->getTimeStamp(); double lastTime = topTray->getLastEntrance(); unsigned long long * lastSamples = topTray->getLastSamples();//Equi! /* If endTime == -1, then the interval option isn't set and we are profiling the entire tracefile. */ if(endTime != -1) { if((startTime <= tempTime) && (lastTime <= endTime)) { /* Check that lastTime is within the interval. */ if(lastTime < startTime) { lastTime = startTime; lastSamples = startMets; }//if if(endTime < tempTime) { tempTime = endTime; tempSamps = endMets; }//if tempExclusive = tempTime - lastTime; for(int i = 0; igetFuncionID(); but I'm changing it to match obsolstack, I believe it makes more sense to add this time to the last tray which was on top. */ int funcID = topTray->getFunctionID(); /* Now set to the appropriate function node. */ node * funcNode = (*parent).funcTree->getFuncNode(funcID); if(funcNode != 0) { double valueToAdd = tempExclusive; if (valueToAdd < 0) { valueToAdd = 0; } funcNode->addExclusive(valueToAdd); funcNode->addExcSamples(tempSampExclusive,n_samplesdim);//Equi! } /* Now make the topTray pointer point to the newest addition to the stack (the top tray). */ //delete topTray; topTray = tempTray; /* Now incSubrs of previous function in topTray.previous. */ tempTray = tempTray->getPrevious(); //delete lastEntry; int tempFuncID = tempTray->getFunctionID(); node * tempNode = parent->funcTree->getFuncNode(tempFuncID); if(tempNode != 0) { // tempNode->incSubrs(); #ifdef DEBUG printf ("\nstartTime == %G\n", startTime); printf ("endTime == %G\n", endTime); printf ("tempExclusive == %G\n", tempExclusive); #endif /* DEBUG */ /* I'm not yet positive whether the next conditional is required or not, I don't have the "if(startTime != -1.....endTime != -1) but I'll leave it here in stack for now. */ if ((startTime != -1) && (endTime != -1)) { if((tempExclusive >= 0) && ((startTime <= n_timeStamp) && (n_timeStamp <= endTime))) { tempNode->incSubrs(); } } else if(tempExclusive >= 0){ tempNode->incSubrs(); } } /* The following is a new method for incrementing the function call counters, based on the new interval implementation. The idea is that we only increment the call counter if we have made an addition to the time sums, i.e. only if the call was made within our chosen interval. */ tempFuncID = topTray->getFunctionID(); tempNode = parent->funcTree->getFuncNode(tempFuncID); /* However, after more thought, I don't want to call incCount based on tempExclusive alone, because this doesn't necessarily mean that the function we're looking at is within interval(I). Need to check also that 'n_timeStamp' is in (I). */ if((startTime != -1) && (endTime != -1)) { if((startTime <= n_timeStamp) && (n_timeStamp <= endTime)) { tempNode->incCount(); }//if }//if else { tempNode->incCount(); }//else return; } }//exchangetype(1) /* If this is a return from a routine. */ //if(n_exchangeType == 2) void stack::returnfrom(int n_functionID, double n_timeStamp, unsigned long long * a_samples, int n_samplesdim) { /* The following is for timeStamp error detection. */ if (parent->lastTimeOne > n_timeStamp) { parent->totalOutOrder += 1; parent->lastTimeTwo = parent->lastTimeOne; parent->lastTimeOne = n_timeStamp; } else { if((parent->lastTimeTwo == n_timeStamp) && (parent->lastTimeOne < n_timeStamp)) { parent->totalRepeats += 1; } parent->lastTimeTwo = parent->lastTimeOne; parent->lastTimeOne = n_timeStamp; } /* Check whether stack is empty. */ if (topTray == 0) { cerr << "received exchangeType(2) event when stack is " << "already empty\n"; parent->stackError = 1; return; } /* Now check that topTray is exchangeType(1). */ if(topTray->getExchangeType() != 1) { cerr << "missmatched exchangeTypes in traceStack!\n"; parent->stackError = 1; return; } //Set tempTray's 'lastEntrance' time. tray * prevTray = topTray->getPrevious(); if (prevTray != 0) { if ((prevTray->getFunctionID()) != (n_functionID)) { cerr << "missmatched functionID's in the trays\n"; } else { prevTray->setLastEntrance(n_timeStamp); prevTray->setLastSamples(a_samples);//Equi! }//else }//if if(n_functionID == -1) { //delete tempTray; lastreturn(n_functionID, n_timeStamp, a_samples, n_samplesdim); return; } /* Verify that the topTray.previousTray is an exchangeType(1) with matching functionID. */ if (prevTray == 0) { cerr << "error: prevTray == NULL in stack.\n"; parent->stackError = 1; return; } if ( (prevTray->getFunctionID()) != n_functionID ) { cerr << "topTray.previous.functionID != " << "tempTray.functionID in traceStack!\n\n"; parent->stackError = 1; return; } tray * tempTray = new tray( n_functionID, n_timeStamp, a_samples, n_samplesdim, 2); double tempTime = tempTray->getTimeStamp(); double tempExclusive = 0; // Holds difference to be added. //double lastTime = lastEntry->getTimeStamp(); double lastTime = topTray->getLastEntrance(); //unsigned long * tempSamps = tempTray->getSamples();//Equi! unsigned long long * tempSamps = new unsigned long long[n_samplesdim]; for(int i = 0; i< n_samplesdim;i++) { tempSamps[i] = tempTray->getSamples()[i]; } unsigned long long * tempSampExclusive = new unsigned long long[n_samplesdim];//Equi! unsigned long long * lastSamples = topTray->getLastSamples();//Equ /* If endTime == -1, then the interval option isn't set and we are profiling the entire tracefile. */ if (endTime != -1) { if ((tempTime < startTime) || (endTime < lastTime)) { // Do nothing, doesn't occur within interval. } else { /* cerr << "startTime: " << startTime << "\n"; cerr << "endTime: " << endTime << "\n"; cerr << "tempTime: " << tempTime << "\n"; cerr << "lastTime: " << lastTime << "\n"; */ if(endTime < tempTime) { tempTime = endTime; tempSamps = endMets; } if(lastTime < startTime) { lastTime = startTime; lastSamples = startMets; } tempExclusive = tempTime - lastTime; for(int i = 0; igetFuncNode(topTray->getFunctionID()); if (funcNode != 0) { funcNode->addExclusive(tempExclusive); funcNode->addExcSamples(tempSampExclusive,n_samplesdim);//Equi! } /* Inclusive time needs to be handled (calculated) more carefully when recursion is present in the program; so for every exchangetype 2 event which comes to our stack, we now verify whether there already exists a tray on the stack representing the function which is currently being pushed. If an instance of the function already exists, it implies either recursion or subsequent calls to identical functions: we don't want to add the same inclusive time to the same function multiple times. */ tray * searchTray = topTray->getPrevious(); int inclusiveID = topTray->getFunctionID(); int recursionPresent = 0; while(searchTray != 0){ if( (searchTray->getFunctionID()) == inclusiveID) { recursionPresent = 1; }//if searchTray = searchTray->getPrevious(); } if(!recursionPresent) { norec(funcNode, n_samplesdim, tempTray); } delete tempTray; tempTray = topTray; /* Now make topTray pointer point to topTray.previous. */ topTray = topTray->getPrevious(); delete tempTray; return; } void stack::norec(node * funcNode, int n_samplesdim, tray * tempTray) { /*****THE FOLLOWING IS FOR INTERVAL CALCULATIONS*****/ double tempTime = tempTray->getTimeStamp(); double tempInclusive = 0; // Holds difference to be added. double lastTime = topTray->getTimeStamp(); //unsigned long * tempSamps = tempTray->getSamples();//Equi unsigned long long * tempSamps = new unsigned long long[n_samplesdim]; for(int i = 0; i< n_samplesdim;i++) { tempSamps[i] = tempTray->getSamples()[i]; } unsigned long long * tempSampInclusive = new unsigned long long[n_samplesdim];//Equi unsigned long long * lastSamples = topTray->getSamples();//Equi if(endTime != -1) { if(tempTime < startTime) { /* Do nothing, doesn't occur within interval. */ }//if else { if(endTime < lastTime) { /* Do nothing, doesn't occur within interval. */ }//if else { /* At this point we know we've found something inside of the interval. */ if(endTime < tempTime) { tempTime = endTime; tempSamps = endMets; }//if if(lastTime < startTime) { lastTime = startTime; lastSamples = startMets; }//if tempInclusive = tempTime - lastTime; for(int i = 0; igetTimeStamp()) - (topTray->getTimeStamp()); */ if(funcNode != 0) { funcNode->addInclusive(tempInclusive); funcNode->addIncSamples(tempSampInclusive,n_samplesdim);//Equi! } delete[] tempSamps; // delete tempTray; tempTray = 0; } /* When we receive the last return call and remove the last tray from the stack, the functionID on that return call will == -1. We need to check for that, and if it is the case, we cannot access topTray.previous as it is a NULL pointer. */ //if(n_functionID == -1) void stack::lastreturn(int n_functionID, double n_timeStamp, unsigned long long * a_samples, int n_samplesdim) { /* The purpose of having a seperate if statement for the case when functionID == -1 is that: when we set topTray = topTray.previous, we cannot in turn (don't need to actually) set the topTray previousTray and nextTray pointers, as topTray is now a NULL pointer. */ tray * tempTray = new tray( n_functionID, n_timeStamp, a_samples, n_samplesdim, 2); double tempTime = tempTray->getTimeStamp(); unsigned long long * tempSamps = tempTray->getSamples();//Equi double tempExclusive = 0; // Holds difference to be added. unsigned long long * tempSampExclusive = new unsigned long long[n_samplesdim];//Equi //double lastTime = lastEntry->getTimeStamp(); double lastTime = topTray->getLastEntrance(); unsigned long long * lastSamples = topTray->getLastSamples();//Equi /* If endTime == -1, then the interval option isn't set and we are profiling the entire tracefile. */ if(endTime != -1) { if((tempTime < startTime) || (endTime < lastTime)) { // Do nothing, doesn't occur within interval. } else { /* cerr << "startTime: " << startTime << "\n"; cerr << "endTime: " << endTime << "\n"; cerr << "tempTime: " << tempTime << "\n"; cerr << "lastTime: " << lastTime << "\n"; */ if(endTime < tempTime) { tempTime = endTime; tempSamps = endMets; } if(lastTime < startTime) { lastTime = startTime; lastSamples = startMets; } tempExclusive = tempTime - lastTime; for(int i = 0; igetFuncNode(topTray->getFunctionID()); if(funcNode != 0) { funcNode->addExclusive(tempExclusive); funcNode->addExcSamples(tempSampExclusive,n_samplesdim);//Equi! } /* Inclusive time needs to be handled (calculated) more carefully when recursion is present in the program; so for every exchangetype 2 event which comes to our stack, we now verify whether there already exists a tray on the stack representing the function which is currently being pushed. If an instance of the function already exists, it implies either recursion or subsequent calls to identical functions: we don't want to add the same inclusive time to the same function multiple times. */ tray * searchTray = topTray->getPrevious(); int inclusiveID = topTray->getFunctionID(); int recursionPresent = 0; while(searchTray != 0) { if( (searchTray->getFunctionID()) == inclusiveID) { recursionPresent = 1; }//if searchTray = searchTray->getPrevious(); }//while if(!recursionPresent) { norec(funcNode, n_samplesdim, tempTray); }//if(!recursionPresent) /* Garbage collect tempTray. */ //delete lastEntry; //lastEntry = 0; delete tempTray; /* Assign tempTray pointer = topTray for garbage collection purposes. */ tempTray = topTray; /* Now make topTray pointer point to topTray.previous. */ topTray = topTray->getPrevious(); /* garbage collect what was topTray. */ delete tempTray; //delete[] tempSampExclusive; //tempSampExclusive = NULL; return; }//functionID == -1