[PATCH] glretrace: Add feature to loop over a frame or call range
Jon Ashburn
jon at lunarg.com
Tue Apr 22 11:53:10 PDT 2014
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
More information about the apitrace
mailing list