Existing looping is over the last frame (or partial frame) in a trace. This adds the ability to specify --framerange and --callrange options to loop over any frame or call range within the trace. --- retrace/retrace_main.cpp | 337 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 233 insertions(+), 104 deletions(-)
diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp index 6327f1b..3dbf3b7 100644 --- a/retrace/retrace_main.cpp +++ b/retrace/retrace_main.cpp @@ -92,6 +92,14 @@ unsigned callNo = 0; unsigned loopIter = 1; static trace::ParseBookmark lastFrameStart; +// call and frame range for looping +bool callrange = false; +unsigned rangeStartCallNum = 0; +unsigned rangeEndCallNum = 0; +bool framerange = false; +unsigned rangeStartFrameNum = 0; +unsigned rangeEndFrameNum = 0; + void frameComplete(trace::Call &call) { ++frameNo; @@ -158,6 +166,10 @@ static bool doneLoopSetup(trace::Call *call, int frameNum) { static bool lastCallEndFrame=false; + /* + * If looping last frame then done when no more calls or end of frame. + * Otherwise done based on framerange or callrange */ + if (!call) return true; @@ -172,100 +184,187 @@ doneLoopSetup(trace::Call *call, int frameNum) else return false; } + if (framerange && frameNum == rangeEndFrameNum && (call->flags & trace::CALL_FLAG_END_FRAME)) + lastCallEndFrame = true; + + if (callrange && call->no == rangeEndCallNum) + lastCallEndFrame = true; return false; } + +/** + * Retrace one call. + * + * Take snapshots before/after retracing (as appropriate) and dispatch it to + * the respective handler. + */ static void -loopingFrameReplay( retrace::Retracer rt) { - trace::Call *call; +retraceCall(trace::Call *call) { + bool swapRenderTarget = call->flags & + trace::CALL_FLAG_SWAP_RENDERTARGET; + bool doSnapshot = snapshotFrequency.contains(*call); + + // For calls which cause rendertargets to be swaped, we take the + // snapshot _before_ swapping the rendertargets. + if (doSnapshot && swapRenderTarget) { + if (call->flags & trace::CALL_FLAG_END_FRAME) { + // For swapbuffers/presents we still use this + // call number, spite not have been executed yet. + takeSnapshot(call->no); + } else { + // Whereas for ordinate fbo/rendertarget changes we + // use the previous call's number. + takeSnapshot(call->no - 1); + } + } + + callNo = call->no; + retracer.retrace(*call); - // keep track of start and end time + if (doSnapshot && !swapRenderTarget) + takeSnapshot(call->no); + + if (call->no >= dumpStateCallNo && + dumper->dumpState(std::cout)) { + exit(0); + } +} + +static void +doLooping(std::vector<trace::Call*> & savedCalls, retrace::Retracer rt, int loopNum) +{ + int i; + if (retrace::verbosity >= 1) { + std::cout << "loop: " << loopNum << "\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"; + } + } +} + +static void +loopingFrameReplay( trace::Call *call, retrace::Retracer rt) +{ + + // keep track of start and end time for setup and actual looping long long setupStartTime, setupEndTime; long long framePerfStart, framePerfEnd; + float timeInterval; + char timestr[15]; - // holds saved call pointers and index into array + /* + * Holds saved call pointers and index into array. + * If only looping one time this array is not used + */ 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 bucketNum = (framerange) ? rangeStartFrameNum : frameNo; + int startBucketNum; int startCallNum = 0, endCallNum = 0; + if (loopOnFinish) { + call = parser.parse_call(); + if (bucketNum != 0) + bucketNum -= 1; + } + startBucketNum = bucketNum; + + if (!call) { + std::cerr << "Skipping Looping invalid call from parse_call()\n"; + return; + } + if (framerange && (frameNo < rangeStartFrameNum || frameNo > rangeEndFrameNum)) { + std::cerr << "Skipping Looping invalid frame range given\n"; + return; + } + + if (loopIter > 1) + std::cout << "Looping " << loopIter << " times on starting frame " << bucketNum << "\n"; + else if (loopIter == 0) + std::cout << "Looping continuously on frame " << bucketNum << "\n"; + 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 (callrange && (startCallNum != rangeStartCallNum)) { + std::cerr << "Skipping Looping invalid call range given\n"; + return; + } + + /* + * frame setup saving the API calls, or if loop iterations == 1 + * then the one loop is executed in this while loop + */ + while ( !doneLoopSetup(call, bucketNum) ) { + endCallNum = call->no; + if (loopIter != 1) { + // save the call pointer + savedCalls.push_back(call); + if (retrace::verbosity >= 1) { + std::cout << "saving call number " << call->no << "\n"; + } + } else { + // execute the call + retraceCall(call); + delete call; } 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"; + if (loopIter != 1) { + // do the looping on saved calls + int j = 0; + while (loopIter == 0) { + // loop continuously + doLooping(savedCalls, rt, j); + j++; } - 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"; - } + framePerfStart = os::getTime(); + for (j = 0; j < loopIter; j++) { + doLooping(savedCalls, rt, j); } - } - framePerfEnd = os::getTime(); + framePerfEnd = os::getTime(); - // print out the statistics - char timestr[15]; - float timeInterval = + // print out the setup statistics + 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"; + if (timeInterval > 0.0) { + std::cout << "Setup call range (" << startCallNum << "-" << + endCallNum << "):\n"; + sprintf(timestr, "%.9f", timeInterval); + std::cout << " total time was " << timestr << " secs\n"; + } + } else { + framePerfStart = setupStartTime; + framePerfEnd = setupEndTime; } + + // print out the looping statistics timeInterval = (framePerfEnd - framePerfStart) * (1.0 / os::timeFrequency); - std::cout << bucketName << " (" << startBucketNum << "-" << bucketNum << ") call range (" << startCallNum << "-" << endCallNum << "):\n"; + if (framerange && bucketNum > rangeEndFrameNum) + bucketNum = rangeEndFrameNum; + if (loopOnFinish) + bucketNum = startBucketNum; + float numFrames = (float) (1 + bucketNum - startBucketNum); + std::cout << "Frame (" << 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)); + sprintf(timestr, "%.9f", (timeInterval / (numFrames * (float) loopIter))); + std::cout << " average time per frame was " << timestr << " secs\n"; + sprintf(timestr, "%.9f", ((numFrames * (float) loopIter) / timeInterval)); std::cout << " fps was " << timestr << " frames per sec\n"; // free the saved calls @@ -278,45 +377,41 @@ loopingFrameReplay( retrace::Retracer rt) { flushRendering(); } +static bool +beforeLooping(trace::Call *call) +{ + static bool lastCallEndFrame=false; + + if (loopOnFinish) + return (call != NULL); + /* + * If looping and NO callrange or framerange defined then replay till + * the end of trace, looping code keeps a bookmark of the start of last + * frame for looping. + */ -/** - * Retrace one call. - * - * Take snapshots before/after retracing (as appropriate) and dispatch it to - * the respective handler. - */ -static void -retraceCall(trace::Call *call) { - bool swapRenderTarget = call->flags & - trace::CALL_FLAG_SWAP_RENDERTARGET; - bool doSnapshot = snapshotFrequency.contains(*call); + if (!framerange && !callrange) + return (call != NULL); - // For calls which cause rendertargets to be swaped, we take the - // snapshot _before_ swapping the rendertargets. - if (doSnapshot && swapRenderTarget) { - if (call->flags & trace::CALL_FLAG_END_FRAME) { - // For swapbuffers/presents we still use this - // call number, spite not have been executed yet. - takeSnapshot(call->no); - } else { - // Whereas for ordinate fbo/rendertarget changes we - // use the previous call's number. - takeSnapshot(call->no - 1); - } + if (!call) + return false; + /* + * If callrange or framerange defined then transition to looping replay + * when get start of call or frame range + */ + if (callrange && call->no >= rangeStartCallNum) { + return false; } - - callNo = call->no; - retracer.retrace(*call); - - if (doSnapshot && !swapRenderTarget) - takeSnapshot(call->no); - - if (call->no >= dumpStateCallNo && - dumper->dumpState(std::cout)) { - exit(0); + if (framerange) { + if (rangeStartFrameNum == 0 || lastCallEndFrame) + return false; + if (frameNo+1 == rangeStartFrameNum && + (call->flags & trace::CALL_FLAG_END_FRAME)) + lastCallEndFrame = true; } -} + return true; +} class RelayRunner; @@ -446,7 +541,7 @@ public: trace::ParseBookmark frameStart; /* Consume successive calls for this thread. */ - do { + while (beforeLooping(call) && call->thread_id == leg) { bool callEndsFrame = false; assert(call); @@ -466,17 +561,16 @@ public: else if (callEndsFrame) lastFrameStart = frameStart; - } while (call && call->thread_id == leg); + } - if (call) { + if (call && call->thread_id != leg) { /* Pass the baton */ - assert(call->thread_id != leg); flushRendering(); race->passBaton(call); } else { /* Reached the finish line */ - if (loopOnFinish) - loopingFrameReplay(retracer); + if (loopOnFinish || callrange || framerange) + loopingFrameReplay(call, retracer); if (0) std::cerr << "finished on leg " << leg << "\n"; if (leg) { /* Notify the fore runner */ @@ -650,7 +744,7 @@ mainLoop() { trace::Call *call; call = parser.parse_call(); - while (call) { + while (beforeLooping(call)) { bool callEndsFrame = false; if (loopOnFinish && call->flags & trace::CALL_FLAG_END_FRAME) { @@ -665,8 +759,8 @@ mainLoop() { else if (callEndsFrame) lastFrameStart = frameStart; }; - if (loopOnFinish) - loopingFrameReplay( retracer); + if (loopOnFinish || callrange || framerange) + loopingFrameReplay( call, retracer); } else { RelayRace race; @@ -719,7 +813,9 @@ 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=N loop N times (N=0 continuously) replaying final frame.\n" + " --loop=N loop N times (N=0 continuously) replaying (call/frame range or final) frame.\n" + " --callrange=CALLSET loop on CALLSET (contiguous)\n" + " --framerange=RANGESET loop on RANGESET of frames (contiguous)\n" " --singlethread use a single thread to replay command stream\n"; } @@ -736,6 +832,8 @@ enum { SB_OPT, SNAPSHOT_FORMAT_OPT, LOOP_OPT, + CALLRANGE_OPT, + FRAMERANGE_OPT, SINGLETHREAD_OPT }; @@ -764,6 +862,8 @@ longOptions[] = { {"verbose", no_argument, 0, 'v'}, {"wait", no_argument, 0, 'w'}, {"loop", required_argument, 0, LOOP_OPT}, + {"callrange", required_argument, 0, CALLRANGE_OPT}, + {"framerange", required_argument, 0, FRAMERANGE_OPT}, {"singlethread", no_argument, 0, SINGLETHREAD_OPT}, {0, 0, 0, 0} }; @@ -880,9 +980,38 @@ int main(int argc, char **argv) case 'w': waitOnFinish = true; break; + case CALLRANGE_OPT: + callrange = true; + framerange = false; + loopOnFinish = false; + retrace::debug = false; + static trace::CallSet callSet = trace::CallSet(); + callSet.merge(optarg); + rangeStartCallNum = callSet.getFirst(); + rangeEndCallNum = callSet.getLast(); + if (rangeStartCallNum > rangeEndCallNum) { + callrange = false; + std::cerr << "error bad call range values\n"; + } + break; + case FRAMERANGE_OPT: + framerange = true; + callrange = false; + loopOnFinish = false; + retrace::debug = false; + static trace::CallSet frameSet = trace::CallSet(); + frameSet.merge(optarg); + rangeStartFrameNum = frameSet.getFirst(); + rangeEndFrameNum = frameSet.getLast(); + if (rangeStartFrameNum > rangeEndFrameNum) { + framerange = false; + std::cerr << "error bad frame range values\n"; + } + break; case LOOP_OPT: loopIter = atoi(optarg); - loopOnFinish = true; + if (!callrange && !framerange) + loopOnFinish = true; break; case PGPU_OPT: retrace::debug = 0; -- 1.8.1.2 _______________________________________________ apitrace mailing list apitrace@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/apitrace