[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