Add iteration option to looping: can loop N times in addition to continuously. Allow looping to work with single and multithread. Add fast looping replay function that supports a fast parse of the calls based on saving the calls. --- retrace/retrace_main.cpp | 189 ++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 165 insertions(+), 24 deletions(-)
diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp index 04dcf2d..506d151 100644 --- a/retrace/retrace_main.cpp +++ b/retrace/retrace_main.cpp @@ -55,7 +55,7 @@ static enum { } snapshotFormat = PNM_FMT; static trace::CallSet snapshotFrequency; -static trace::ParseBookmark lastFrameStart; + static unsigned dumpStateCallNo = ~0; @@ -89,7 +89,8 @@ bool singleThread = false; unsigned frameNo = 0; unsigned callNo = 0; - +unsigned loopIter = 1; +static trace::ParseBookmark lastFrameStart; void frameComplete(trace::Call &call) { @@ -153,6 +154,130 @@ takeSnapshot(unsigned call_no) { return; } +static bool +doneLoopSetup(trace::Call *call, int frameNum) +{ + static bool lastCallEndFrame=false; + if (!call) + return true; + + if (lastCallEndFrame) { + lastCallEndFrame = false; + return true; + } + + if (loopOnFinish) { + if (call->flags & trace::CALL_FLAG_END_FRAME) + lastCallEndFrame = true; + else + return false; + } + + return false; +} + +static void +loopingFrameReplay( retrace::Retracer rt) { + trace::Call *call; + + // keep track of start and end time + long long setupStartTime, setupEndTime; + long long framePerfStart, framePerfEnd; + + // holds saved call pointers and index into array + std::vector<trace::Call*> savedCalls; + + int bucketNum = frameNo; + int startBucketNum = bucketNum; + const char *bucketName = "Frame "; + + if (loopIter) + std::cout << "Looping " << loopIter << " times on " << bucketName << bucketNum << "\n"; + else + std::cout << "Looping continuously on " << bucketName << bucketNum << "\n"; + int startCallNum = 0, endCallNum = 0; + + setupStartTime = os::getTime(); + setupEndTime = setupStartTime; + + //frame setup + call = parser.parse_call(); + startCallNum = call->no; + while( !doneLoopSetup(call, bucketNum) ) { + // save the call pointer + savedCalls.push_back(call); + if (retrace::verbosity >= 1) { + std::cout << "saving call number " << call->no << "\n"; + } + + if ((call->flags & trace::CALL_FLAG_END_FRAME) ) { + bucketNum = bucketNum + 1; + } + endCallNum = call->no; + call = parser.parse_call(); + } + setupEndTime = os::getTime(); + + // do the looping on saved calls + int i, j = 0; + while (loopIter == 0) { + // loop continuously + if (retrace::verbosity >= 1) { + std::cout << "loop: " << j << "\n"; + } + for (i = 0; i < savedCalls.size(); i++) { + trace::Call *call2 = savedCalls[i]; + rt.retrace(*call2); + if (retrace::verbosity >= 1) { + std::cout << "retraced call: " << call2->no << ":" << call2->name() << "\n"; + } + } + j++; + } + framePerfStart = os::getTime(); + for (j = 0; j < loopIter; j++) { + if (retrace::verbosity >= 1) { + std::cout << "loop: " << j << "\n"; + } + for (i = 0; i < savedCalls.size(); i++) { + trace::Call *call2 = savedCalls[i]; + rt.retrace(*call2); + if (retrace::verbosity >= 1) { + std::cout << "retraced call: " << call2->no << ":" << call2->name() << "\n"; + } + } + } + framePerfEnd = os::getTime(); + + // print out the statistics + char timestr[15]; + float timeInterval = + (setupEndTime - setupStartTime) * (1.0 / os::timeFrequency); + if (timeInterval > 0.0) { + std::cout << "Setup call range (" << startCallNum << "-" << endCallNum << "):\n"; + sprintf(timestr, "%.9f", timeInterval); + std::cout << " total time was " << timestr << " secs\n"; + } + timeInterval = + (framePerfEnd - framePerfStart) * (1.0 / os::timeFrequency); + std::cout << bucketName << " (" << startBucketNum << "-" << bucketNum << ") call range (" << startCallNum << "-" << endCallNum << "):\n"; + sprintf(timestr, "%.9f", timeInterval); + std::cout << " total time was " << timestr << " secs\n"; + sprintf(timestr, "%.9f", (timeInterval / (1.0 * loopIter))); + std::cout << " average time was " << timestr << " secs\n"; + sprintf(timestr, "%.9f", (((1.0) * loopIter) / timeInterval)); + std::cout << " fps was " << timestr << " frames per sec\n"; + + // free the saved calls + for (int i = 0; i < savedCalls.size(); i++) { + trace::Call *call3 = savedCalls[i]; + delete call3; + } + savedCalls.clear(); + + flushRendering(); +} + /** * Retrace one call. @@ -318,11 +443,11 @@ public: */ void runLeg(trace::Call *call) { + trace::ParseBookmark frameStart; /* Consume successive calls for this thread. */ do { bool callEndsFrame = false; - static trace::ParseBookmark frameStart; assert(call); assert(call->thread_id == leg); @@ -336,15 +461,10 @@ public: delete call; call = parser.parse_call(); - /* Restart last frame if looping is requested. */ - if (loopOnFinish) { - if (!call) { + if (loopOnFinish && !call) parser.setBookmark(lastFrameStart); - call = parser.parse_call(); - } else if (callEndsFrame) { - lastFrameStart = frameStart; - } - } + else if (callEndsFrame) + lastFrameStart = frameStart; } while (call && call->thread_id == leg); @@ -355,6 +475,8 @@ public: race->passBaton(call); } else { /* Reached the finish line */ + if (loopOnFinish) + loopingFrameReplay(retracer); if (0) std::cerr << "finished on leg " << leg << "\n"; if (leg) { /* Notify the fore runner */ @@ -453,14 +575,6 @@ RelayRace::run(void) { return; } - /* If the user wants to loop we need to get a bookmark target. We - * usually get this after replaying a call that ends a frame, but - * for a trace that has only one frame we need to get it at the - * beginning. */ - if (loopOnFinish) { - parser.getBookmark(lastFrameStart); - } - RelayRunner *foreRunner = getForeRunner(); if (call->thread_id == 0) { /* We are the forerunner thread, so no need to pass baton */ @@ -512,22 +626,48 @@ RelayRace::stopRunners(void) { } } - static void mainLoop() { addCallbacks(retracer); long long startTime = 0; frameNo = 0; - + trace::ParseBookmark frameStart; startTime = os::getTime(); + /* If the user wants to loop we need to get a bookmark target. We + * usually get this after replaying a call that ends a frame, but + * for a trace that has only one frame we need to get it at the + * beginning. */ + if (loopOnFinish) { + parser.getBookmark(lastFrameStart); + } + if (singleThread) { + if (retrace::verbosity >= 1) { + std::cout << "single thread\n"; + } + trace::Call *call; - while ((call = parser.parse_call())) { + call = parser.parse_call(); + while (call) { + bool callEndsFrame = false; + + if (loopOnFinish && call->flags & trace::CALL_FLAG_END_FRAME) { + callEndsFrame = true; + parser.getBookmark(frameStart); + } retraceCall(call); delete call; + call = parser.parse_call(); + if (loopOnFinish && !call) + parser.setBookmark(lastFrameStart); + else if (callEndsFrame) + lastFrameStart = frameStart; }; + if (loopOnFinish) + loopingFrameReplay( retracer); + } else { RelayRace race; race.run(); @@ -578,7 +718,7 @@ usage(const char *argv0) { " -v, --verbose increase output verbosity\n" " -D, --dump-state=CALL dump state at specific call no\n" " -w, --wait waitOnFinish on final frame\n" - " --loop continuously loop, replaying final frame.\n" + " --loop=N loop N times (N=0 continuously) replaying final frame.\n" " --singlethread use a single thread to replay command stream\n"; } @@ -621,7 +761,7 @@ longOptions[] = { {"snapshot", required_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"wait", no_argument, 0, 'w'}, - {"loop", no_argument, 0, LOOP_OPT}, + {"loop", required_argument, 0, LOOP_OPT}, {"singlethread", no_argument, 0, SINGLETHREAD_OPT}, {0, 0, 0, 0} }; @@ -736,6 +876,7 @@ int main(int argc, char **argv) waitOnFinish = true; break; case LOOP_OPT: + loopIter = atoi(optarg); loopOnFinish = true; break; case PGPU_OPT: -- 1.6.0.2 _______________________________________________ apitrace mailing list apitrace@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/apitrace