[PATCH] glretrace: Various improvements to looping retrace
Jon Ashburn
jon at lunarg.com
Tue Apr 22 11:53:09 PDT 2014
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
More information about the apitrace
mailing list