[PATCH] glretrace: When looping on replay save parsed calls for faster execution

Jon Ashburn jon at lunarg.com
Mon Aug 11 14:35:35 PDT 2014


Since the Call class is deleted after replaying each call, the saved calls
had to copy this class and remain undeleted. This required supporting
infastructure to clone the class Call and not delete this class
for the saved calls except when done looping.
---
 cli/cli_dump.cpp         |  6 ++++--
 cli/cli_pickle.cpp       |  6 ++++--
 cli/cli_retrace.cpp      |  6 ++++--
 cli/cli_sed.cpp          |  6 ++++--
 cli/cli_trim.cpp         | 17 +++++++++++------
 common/trace_loader.cpp  |  3 ++-
 common/trace_model.cpp   | 41 ++++++++++++++++++++++++++++++++++++++++
 common/trace_model.hpp   | 49 +++++++++++++++++++++++++++++++++++++-----------
 common/trace_parser.cpp  | 36 ++++++++++++++++++++++++++++++++---
 common/trace_parser.hpp  | 46 ++++++++++++++++++++++++++++++++++++++++-----
 gui/saverthread.cpp      |  3 ++-
 gui/traceloader.cpp      | 22 ++++++++++++++--------
 retrace/retrace_main.cpp | 17 +++++++++++------
 13 files changed, 209 insertions(+), 49 deletions(-)

diff --git a/cli/cli_dump.cpp b/cli/cli_dump.cpp
index d674c83..4c64001 100644
--- a/cli/cli_dump.cpp
+++ b/cli/cli_dump.cpp
@@ -178,14 +178,16 @@ command(int argc, char *argv[])
         }
 
         trace::Call *call;
-        while ((call = p.parse_call())) {
+        bool delCall;
+        while ((call = p.parse_call(delCall))) {
             if (calls.contains(*call)) {
                 if (verbose ||
                     !(call->flags & trace::CALL_FLAG_VERBOSE)) {
                     trace::dump(*call, std::cout, dumpFlags);
                 }
             }
-            delete call;
+            if (delCall)
+                delete call;
         }
     }
 
diff --git a/cli/cli_pickle.cpp b/cli/cli_pickle.cpp
index e7f51ff..46a5f31 100644
--- a/cli/cli_pickle.cpp
+++ b/cli/cli_pickle.cpp
@@ -271,13 +271,15 @@ command(int argc, char *argv[])
         }
 
         trace::Call *call;
-        while ((call = parser.parse_call())) {
+        bool delCall;
+        while ((call = parser.parse_call(delCall))) {
             if (calls.contains(*call)) {
                 writer.begin();
                 visitor.visit(call);
                 writer.end();
             }
-            delete call;
+            if(delCall)
+                delete call;
         }
     }
 
diff --git a/cli/cli_retrace.cpp b/cli/cli_retrace.cpp
index db799b9..432ed47 100644
--- a/cli/cli_retrace.cpp
+++ b/cli/cli_retrace.cpp
@@ -50,8 +50,10 @@ guessApi(const char *filename)
         return trace::API_UNKNOWN;
     }
     trace::Call *call;
-    while ((call = p.parse_call())) {
-        delete call;
+    bool delCall;
+    while ((call = p.parse_call(delCall))) {
+        if (delCall)
+            delete call;
 
         if (p.api != trace::API_UNKNOWN) {
             return p.api;
diff --git a/cli/cli_sed.cpp b/cli/cli_sed.cpp
index afec125..b33130f 100644
--- a/cli/cli_sed.cpp
+++ b/cli/cli_sed.cpp
@@ -189,7 +189,8 @@ sed_trace(Replacements &replacements, const char *inFileName, std::string &outFi
     }
 
     trace::Call *call;
-    while ((call = p.parse_call())) {
+    bool delCall;
+    while ((call = p.parse_call(delCall))) {
 
         for (Replacements::iterator it = replacements.begin(); it != replacements.end(); ++it) {
             it->visit(call);
@@ -197,7 +198,8 @@ sed_trace(Replacements &replacements, const char *inFileName, std::string &outFi
 
         writer.writeCall(call);
 
-        delete call;
+        if (delCall)
+            delete call;
     }
 
     std::cerr << "Edited trace is available as " << outFileName << "\n";
diff --git a/cli/cli_trim.cpp b/cli/cli_trim.cpp
index ed950e5..ed8900f 100644
--- a/cli/cli_trim.cpp
+++ b/cli/cli_trim.cpp
@@ -220,14 +220,16 @@ trim_trace(const char *filename, struct trim_options *options)
     /* In pass 1, analyze which calls are needed. */
     frame = 0;
     trace::Call *call;
-    while ((call = p.parse_call())) {
+    bool delCall;
+    while ((call = p.parse_call(delCall))) {
 
         /* There's no use doing any work past the last call and frame
          * requested by the user. */
         if ((options->calls.empty() || call->no > options->calls.getLast()) &&
             (options->frames.empty() || frame > options->frames.getLast())) {
 
-            delete call;
+            if (delCall)
+                delete call;
             break;
         }
 
@@ -262,7 +264,8 @@ trim_trace(const char *filename, struct trim_options *options)
         if (call->flags & trace::CALL_FLAG_END_FRAME)
             frame++;
 
-        delete call;
+        if (delCall)
+            delete call;
     }
 
     /* Prepare output file and writer for output. */
@@ -288,14 +291,15 @@ trim_trace(const char *filename, struct trim_options *options)
     frame = 0;
     call_range_first = -1;
     call_range_last = -1;
-    while ((call = p.parse_call())) {
+    while ((call = p.parse_call(delCall))) {
 
         /* There's no use doing any work past the last call and frame
          * requested by the user. */
         if ((options->calls.empty() || call->no > options->calls.getLast()) &&
             (options->frames.empty() || frame > options->frames.getLast())) {
 
-            delete call;
+            if (delCall)
+                delete call;
             break;
         }
 
@@ -320,7 +324,8 @@ trim_trace(const char *filename, struct trim_options *options)
             frame++;
         }
 
-        delete call;
+        if (delCall)
+            delete call;
     }
 
     if (options->print_callset) {
diff --git a/common/trace_loader.cpp b/common/trace_loader.cpp
index 6a3d7de..7a35592 100644
--- a/common/trace_loader.cpp
+++ b/common/trace_loader.cpp
@@ -120,7 +120,8 @@ std::vector<trace::Call *> Loader::frame(unsigned idx)
 
         trace::Call *call;
         unsigned parsedCalls = 0;
-        while ((call = m_parser.parse_call())) {
+        bool delCall;
+        while ((call = m_parser.parse_call(delCall))) {
 
             calls[parsedCalls] = call;
             ++parsedCalls;
diff --git a/common/trace_model.cpp b/common/trace_model.cpp
index baebc18..8619d03 100644
--- a/common/trace_model.cpp
+++ b/common/trace_model.cpp
@@ -203,6 +203,47 @@ void Blob   ::visit(Visitor &visitor) { visitor.visit(this); }
 void Pointer::visit(Visitor &visitor) { visitor.visit(this); }
 void Repr   ::visit(Visitor &visitor) { visitor.visit(this); }
 
+// virtual Value::clone
+Value * Null::clone() const { return new Null(*this);}
+Value * Bool::clone() const { return new Bool(*this);}
+Value * SInt::clone() const { return new SInt(*this);}
+Value * UInt::clone() const { return new UInt(*this);}
+Value * Float::clone() const { return new Float(*this);}
+Value * Double::clone() const { return new Double(*this);}
+Value * Enum::clone() const { return new Enum(*this);}
+Value * Bitmask::clone() const { return new Bitmask(*this);}
+Value * Pointer::clone() const { return new Pointer(*this);}
+Value * Repr::clone() const { return new Repr(*this);}
+Value * String::clone() const
+{
+    String  *str = new String(*this);
+    char *val = new char [strlen(this->value) + 1];
+    strcpy(val, this->value);
+    return str;
+}
+Value * Struct::clone() const 
+{
+    Struct *temp = new Struct(*this);
+    for (std::vector<Value *>::size_type i = 0; i != members.size(); i++) {
+        temp->members[i] = members[i]->clone();
+    }
+    return temp;
+}
+Value * Array::clone() const
+{
+    Array *temp = new Array(*this);
+    for (std::vector<Value *>::size_type i = 0; i != values.size(); i++) {
+        temp->values[i] = values[i]->clone();
+    }
+    return temp;
+}
+Value * Blob::clone() const 
+{
+    Blob *temp = new Blob(*this);
+    if (bound)
+        memcpy(temp->buf,this->buf, size);
+    return temp;
+}
 
 void Visitor::visit(Null *) { assert(0); }
 void Visitor::visit(Bool *) { assert(0); }
diff --git a/common/trace_model.hpp b/common/trace_model.hpp
index 164b1ab..a8470d3 100644
--- a/common/trace_model.hpp
+++ b/common/trace_model.hpp
@@ -102,7 +102,7 @@ class Value
 public:
     virtual ~Value() {}
     virtual void visit(Visitor &visitor) = 0;
-
+    virtual Value *clone() const = 0;
     virtual bool toBool(void) const = 0;
     virtual signed long long toSInt(void) const;
     virtual unsigned long long toUInt(void) const;
@@ -140,6 +140,7 @@ public:
     unsigned long long toUIntPtr(void) const;
     const char *toString(void) const;
     void visit(Visitor &visitor);
+    Value *clone() const;
 
     const Null *toNull(void) const { return this; }
     Null *toNull(void) { return this; }
@@ -157,7 +158,8 @@ public:
     virtual float toFloat(void) const;
     virtual double toDouble(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     bool value;
 };
 
@@ -173,7 +175,8 @@ public:
     virtual float toFloat(void) const;
     virtual double toDouble(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     signed long long value;
 };
 
@@ -189,7 +192,8 @@ public:
     virtual float toFloat(void) const;
     virtual double toDouble(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     unsigned long long value;
 };
 
@@ -205,7 +209,8 @@ public:
     virtual float toFloat(void) const;
     virtual double toDouble(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     float value;
 };
 
@@ -221,7 +226,8 @@ public:
     virtual float toFloat(void) const;
     virtual double toDouble(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     double value;
 };
 
@@ -235,7 +241,8 @@ public:
     bool toBool(void) const;
     const char *toString(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     const char * value;
 };
 
@@ -246,6 +253,7 @@ public:
     Enum(const EnumSig *_sig, signed long long _value) : SInt(_value), sig(_sig) {}
 
     void visit(Visitor &visitor);
+    Value *clone() const;
 
     const EnumSig *sig;
 
@@ -268,6 +276,7 @@ public:
     Bitmask(const BitmaskSig *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}
 
     void visit(Visitor &visitor);
+    Value *clone() const;
 
     const BitmaskSig *sig;
 };
@@ -281,7 +290,8 @@ public:
 
     bool toBool(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     const Struct *toStruct(void) const { return this; }
     Struct *toStruct(void) { return this; }
 
@@ -298,7 +308,8 @@ public:
 
     bool toBool(void) const;
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     const Array *toArray(void) const { return this; }
     Array *toArray(void) { return this; }
 
@@ -326,7 +337,8 @@ public:
     void *toPointer(void) const;
     void *toPointer(bool bind);
     void visit(Visitor &visitor);
-
+    Value *clone() const;
+    
     size_t size;
     char *buf;
     bool bound;
@@ -343,6 +355,7 @@ public:
     void *toPointer(bool bind);
     unsigned long long toUIntPtr(void) const;
     void visit(Visitor &visitor);
+    Value *clone() const;
 };
 
 
@@ -372,6 +385,7 @@ public:
     virtual const char *toString(void) const;
 
     void visit(Visitor &visitor);
+    Value *clone() const;
 };
 
 struct RawStackFrame {
@@ -549,7 +563,20 @@ public:
         flags(_flags),
         backtrace(0) {
     }
-
+    Call(const Call *other) : thread_id(other->thread_id), no(other->no),
+        sig(other->sig), args(other->args), ret(0), flags(other->flags),
+        backtrace(0)
+    {
+        for (int i = 0; i < other->args.size(); i++) {
+            Value *a = other->args[i].value->clone();
+            args[i].value = a;
+        }
+ 
+        if (other->ret) {
+            ret = other->ret->clone();
+        }
+    }
+    
     ~Call();
 
     inline const char *
diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp
index f5c6f1d..45d6699 100644
--- a/common/trace_parser.cpp
+++ b/common/trace_parser.cpp
@@ -1023,10 +1023,19 @@ void LastFrameLoopParser::bookmarkFrameStart(trace::Call *call) {
     }
 }
 
-Call *LastFrameLoopParser::parse_call(void) {
+Call *LastFrameLoopParser::parse_call(bool & del) {
     trace::Call *call;
 
-    call = parser->parse_call();
+    call = parser->parse_call(del);
+    if (savingCalls) {
+        if (call) {
+            trace::Call * tempCall = new Call(call);
+            savedCalls.push_back(tempCall);
+        } else {
+            savedCalls.push_back(call);
+        }
+    }
+
 
      /* 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
@@ -1039,7 +1048,21 @@ Call *LastFrameLoopParser::parse_call(void) {
     /* Restart last frame when looping is requested. */
     if (!call  && (loopIter > 0  || loopContinuous)) {
         parser->setBookmark(lastFrameStart);
-        call = parser->parse_call();
+        call = parser->parse_call(del);
+        /* If looping multiple times save parsed calls on first loop so
+         * subsequent loops will run faster. */
+        if (savedCalls.empty() && !savingCalls && (loopIter > 1 || loopContinuous)) {
+            savingCalls = true;
+            trace::Call *tempCall = new Call(call);
+            savedCalls.push_back(tempCall);
+        } else if (savingCalls) {
+            /* any subsequent loops use fast parser */
+            parser = new FastParser(parser, &savedCalls);
+            fp = parser;
+            savingCalls = false;
+            call = parser->parse_call(del);
+ 
+        }
         if (!loopContinuous)
             loopIter--;
     } else if (callEndsFrame) {
@@ -1049,5 +1072,12 @@ Call *LastFrameLoopParser::parse_call(void) {
 
     return call;
 }
+Call * FastParser::parse_call(bool &del) {
+    Call *temp;
 
+    idx = idx % savedCalls->size();
+    temp = (*savedCalls)[idx++];
+    del = false;
+    return temp;
+}
 } /* namespace trace */
diff --git a/common/trace_parser.hpp b/common/trace_parser.hpp
index a86f35d..08b3538 100644
--- a/common/trace_parser.hpp
+++ b/common/trace_parser.hpp
@@ -3,7 +3,7 @@
  * Copyright 2010 VMware, Inc.
  * All Rights Reserved.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * Permission is hereby granted,free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
@@ -54,7 +54,7 @@ struct ParseBookmark
  {
  public:
     virtual ~AbstractParser() {}
-    virtual  Call *parse_call(void) = 0;
+    virtual  Call *parse_call(bool &del) = 0;
     virtual void bookmarkFrameStart(trace::Call *call) = 0;
     virtual void getBookmark(ParseBookmark &bookmark) = 0;
     virtual void setBookmark(const ParseBookmark &bookmark) = 0;
@@ -125,7 +125,8 @@ public:
 
     void close(void);
 
-    Call *parse_call(void) {
+    Call *parse_call(bool & del) {
+        del = true;
         return parse_call(FULL);
     }
 
@@ -238,6 +239,29 @@ protected:
     inline void skip_byte(void);
 };
 
+// Decorator to loop over a vector of saved calls
+class FastParser: public AbstractParser {
+public:
+    FastParser(AbstractParser *p, std::vector<Call *> *s) {
+        parser = p;
+        savedCalls = s;
+        idx = 0;
+    }
+    ~FastParser() {}
+    
+    Call *parse_call(bool &del);
+    void bookmarkFrameStart(trace::Call *call) {}
+    void getBookmark(ParseBookmark &bookmark) {}
+    void setBookmark(const ParseBookmark &bookmark) {}
+    bool open(const char *filename) {return false;}
+    void close(void) {}
+    unsigned long long get_version(void) {return 0;}
+private:
+    AbstractParser *parser;
+    std::vector<Call *> *savedCalls;
+    unsigned int idx;
+};
+
 // Decorator for parser which loops
 class LastFrameLoopParser : public AbstractParser  {
 public:
@@ -245,10 +269,19 @@ public:
         parser = p;
         callEndsFrame = false;
         firstCall = true;
+        savedCalls.clear();
+        savingCalls = false;
+        fp = NULL;
+    }
+    ~LastFrameLoopParser() {
+        delete fp;
+        fp = NULL;
+        for (std::vector<Call *>::iterator it = savedCalls.begin(); it != savedCalls.end();)
+            it = savedCalls.erase(it);
+        savedCalls.clear();
     }
-    ~LastFrameLoopParser() { delete parser; }
 
-    Call *parse_call(void);
+    Call *parse_call(bool & del);
     void bookmarkFrameStart(trace::Call *call);
 
     //delegate to Parser
@@ -259,9 +292,12 @@ public:
     unsigned long long get_version(void) {return parser->get_version();}
 private:
     AbstractParser *parser;
+    AbstractParser *fp;
     bool callEndsFrame, firstCall;
     ParseBookmark frameStart;
     ParseBookmark lastFrameStart;
+    std::vector<Call *> savedCalls;
+    bool savingCalls;
 };
 
 } /* namespace trace */
diff --git a/gui/saverthread.cpp b/gui/saverthread.cpp
index 4ad83c5..a7a4278 100644
--- a/gui/saverthread.cpp
+++ b/gui/saverthread.cpp
@@ -353,7 +353,8 @@ void SaverThread::run()
     parser.open(m_readFileName.toLocal8Bit());
 
     trace::Call *call;
-    while ((call = parser.parse_call())) {
+    bool delCall;
+    while ((call = parser.parse_call(delCall))) {
         if (callIndexMap.contains(call->no)) {
             QVector<QVariant> values = callIndexMap[call->no]->editedValues();
             for (int i = 0; i < values.count(); ++i) {
diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp
index 59f8803..10139e6 100644
--- a/gui/traceloader.cpp
+++ b/gui/traceloader.cpp
@@ -265,7 +265,8 @@ void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
         const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
         m_parser.setBookmark(frameBookmark.start);
         trace::Call *call = 0;
-        while ((call = m_parser.parse_call())) {
+        bool delCall;
+        while ((call = m_parser.parse_call(delCall))) {
 
             if (callContains(call, request.text, request.cs)) {
                 unsigned frameIdx = callInFrame(call->no);
@@ -279,11 +280,13 @@ void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
                         break;
                     }
                 }
-                delete call;
+                if (delCall)
+                    delete call;
                 return;
             }
 
-            delete call;
+            if (delCall)
+                delete call;
         }
     }
     emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
@@ -301,8 +304,9 @@ void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
         const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
         int numCallsToParse = frameBookmark.numberOfCalls;
         m_parser.setBookmark(frameBookmark.start);
-
-        while ((call = m_parser.parse_call())) {
+        
+        bool delCall;
+        while ((call = m_parser.parse_call(delCall))) {
 
             frameCalls.append(call);
             --numCallsToParse;
@@ -528,8 +532,9 @@ TraceLoader::FrameContents::load(TraceLoader   *loader,
     int initNumOfCalls = m_allCalls.count();
     trace::Call  *call;
     ApiTraceCall *apiCall = NULL;
-
-    while ((call = parser.parse_call())) {
+    bool delCall;
+    
+    while ((call = parser.parse_call(delCall))) {
 
         apiCall = apiCallFromTraceCall(call, helpHash, currentFrame,
                                        m_groups.isEmpty() ? 0 : m_groups.top(),
@@ -561,7 +566,8 @@ TraceLoader::FrameContents::load(TraceLoader   *loader,
             m_binaryDataSize += data.size();
         }
 
-        delete call;
+        if (delCall)
+            delete call;
 
         if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
             bEndFrameReached = true;
diff --git a/retrace/retrace_main.cpp b/retrace/retrace_main.cpp
index 0db1b16..8ced20e 100644
--- a/retrace/retrace_main.cpp
+++ b/retrace/retrace_main.cpp
@@ -318,6 +318,7 @@ public:
     void
     runLeg(trace::Call *call) {
 
+        bool delCall = true;
         /* Consume successive calls for this thread. */
         do {
 
@@ -327,8 +328,9 @@ public:
             parser->bookmarkFrameStart(call);
 
             retraceCall(call);
-            delete call;
-            call = parser->parse_call();
+            if (delCall)
+                delete call;
+            call = parser->parse_call(delCall);
 
         } while (call && call->thread_id == leg);
 
@@ -431,7 +433,8 @@ RelayRace::getRunner(unsigned leg) {
 void
 RelayRace::run(void) {
     trace::Call *call;
-    call = parser->parse_call();
+    bool delCall;
+    call = parser->parse_call(delCall);
     if (!call) {
         /* Nothing to do */
         return;
@@ -500,12 +503,14 @@ mainLoop() {
 
     if (singleThread) {
         trace::Call *call;
-        call = parser->parse_call();
+        bool delCall;
+        call = parser->parse_call(delCall);
         do {
             parser->bookmarkFrameStart(call);
             retraceCall(call);
-            delete call;
-            call = parser->parse_call();
+            if (delCall)
+                delete call;
+            call = parser->parse_call(delCall);
         } while (call);
     } else {
         RelayRace race;
-- 
1.8.1.2



More information about the apitrace mailing list