]> git.cworth.org Git - apitrace/commitdiff
Implement an incremental on demand loader for the gui.
authorZack Rusin <zack@kde.org>
Tue, 6 Sep 2011 15:50:07 +0000 (11:50 -0400)
committerZack Rusin <zack@kde.org>
Tue, 6 Sep 2011 15:50:07 +0000 (11:50 -0400)
gui/CMakeLists.txt
gui/apitrace.cpp
gui/apitracecall.cpp
gui/apitracecall.h
gui/traceloader.cpp [new file with mode: 0644]
gui/traceloader.h [new file with mode: 0644]

index 6973450a9e5c16a1688ae24c233f8623d319af00..e0cfe44f04206b6a0c204863dff418d46c39d7d7 100644 (file)
@@ -21,6 +21,7 @@ set(qapitrace_SRCS
    settingsdialog.cpp
    shaderssourcewidget.cpp
    tracedialog.cpp
+   traceloader.cpp
    traceprocess.cpp
    vertexdatainterpreter.cpp
  )
index 51c4755b28194a70b635ac16d3230ef5c03623b1..9a68e63d56eb0ee3db5233bf327ac481527a50bb 100644 (file)
@@ -180,6 +180,7 @@ void ApiTrace::detectFrames()
         if (!currentFrame) {
             currentFrame = new ApiTraceFrame(this);
             currentFrame->number = m_frames.count();
+            currentFrame->setLoaded(true);
         }
         apiCall->setParentFrame(currentFrame);
         currentFrame->addCall(apiCall);
index bd30aaaa89aff9a333ea84f13dc534e2b62d4a42..680d22a543ad73c9a7e03dcf80c9d6ccc64e874a 100644 (file)
@@ -923,7 +923,9 @@ int ApiTraceCall::numChildren() const
 ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
     : ApiTraceEvent(ApiTraceEvent::Frame),
       m_parentTrace(parentTrace),
-      m_binaryDataSize(0)
+      m_binaryDataSize(0),
+      m_loaded(false),
+      m_callsToLoad(0)
 {
 }
 
@@ -964,7 +966,11 @@ QStaticText ApiTraceFrame::staticText() const
 
 int ApiTraceFrame::numChildren() const
 {
-    return m_calls.count();
+    if (m_loaded) {
+        return m_calls.count();
+    } else {
+        return m_callsToLoad;
+    }
 }
 
 ApiTrace * ApiTraceFrame::parentTrace() const
@@ -1012,4 +1018,20 @@ void ApiTraceFrame::setCalls(const QVector<ApiTraceCall*> &calls,
 {
     m_calls = calls;
     m_binaryDataSize = binaryDataSize;
+    m_loaded = true;
+}
+
+bool ApiTraceFrame::loaded() const
+{
+    return m_loaded;
+}
+
+void ApiTraceFrame::setLoaded(bool l)
+{
+    m_loaded = l;
+}
+
+void ApiTraceFrame::setNumChildren(int num)
+{
+    m_callsToLoad = num;
 }
index 33648f2f28b054803d15e8f38b0ab1cd2b05e011..5a5a64b9eadd6b5c26d6ff38ecf6dd98ec5d8960 100644 (file)
@@ -291,6 +291,7 @@ public:
 
     ApiTrace *parentTrace() const;
 
+    void setNumChildren(int num);
     int numChildren() const;
     QStaticText staticText() const;
 
@@ -302,10 +303,15 @@ public:
                   quint64 binaryDataSize);
 
     int binaryDataSize() const;
+
+    bool loaded() const;
+    void setLoaded(bool l);
 private:
     ApiTrace *m_parentTrace;
     quint64 m_binaryDataSize;
     QVector<ApiTraceCall*> m_calls;
+    bool m_loaded;
+    unsigned m_callsToLoad;
 };
 Q_DECLARE_METATYPE(ApiTraceFrame*);
 
diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp
new file mode 100644 (file)
index 0000000..40609ad
--- /dev/null
@@ -0,0 +1,273 @@
+#include "traceloader.h"
+
+#include <QDebug>
+#include <QFile>
+
+#define FRAMES_TO_CACHE 100
+
+static ApiTraceCall *
+apiCallFromTraceCall(const Trace::Call *call,
+                     const QHash<QString, QUrl> &helpHash,
+                     ApiTraceFrame *frame)
+{
+    ApiTraceCall *apiCall = new ApiTraceCall(frame, call);
+
+    apiCall->setHelpUrl(helpHash.value(apiCall->name()));
+
+    return apiCall;
+}
+
+TraceLoader::TraceLoader(ApiTrace *parent)
+    : QObject(parent),
+      m_trace(parent),
+      m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
+{
+}
+
+TraceLoader::~TraceLoader()
+{
+    m_parser.close();
+}
+
+void TraceLoader::loadTrace(const QString &filename)
+{
+    if (m_helpHash.isEmpty()) {
+        loadHelpFile();
+    }
+
+    if (!m_parser.open(filename.toLatin1())) {
+        qDebug() << "error: failed to open " << filename;
+        return;
+    }
+
+    emit startedParsing();
+
+    if (m_parser.supportsOffsets()) {
+       scanTrace();
+    } else {
+       //Load the entire file into memory
+       parseTrace();
+    }
+
+    emit finishedParsing();
+}
+
+void TraceLoader::loadFrame(int frameIdx)
+{
+    if (m_parser.supportsOffsets()) {
+        int numOfCalls = numberOfCallsInFrame(frameIdx);
+        if (numOfCalls) {
+            const FrameOffset &frameOffset = m_frameOffsets[frameIdx];
+            std::vector<Trace::Call*> calls(numOfCalls);
+            m_parser.setCurrentOffset(frameOffset.start);
+            m_parser.setCurrentCallNumber(frameOffset.callNumber);
+
+            Trace::Call *call;
+            int parsedCalls = 0;
+            while ((call = m_parser.parse_call())) {
+
+                calls[parsedCalls] = call;
+                ++parsedCalls;
+
+                if (isCallAFrameMarker(call)) {
+                    break;
+                }
+
+            }
+            assert(parsedCalls == numOfCalls);
+//            emit parsedFrame();
+        }
+    }
+}
+
+void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
+{
+    m_frameMarker = marker;
+}
+
+bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
+{
+    std::string name = call->name();
+
+    switch (m_frameMarker) {
+    case ApiTrace::FrameMarker_SwapBuffers:
+       return  name.find("SwapBuffers") != std::string::npos ||
+               name == "CGLFlushDrawable" ||
+               name == "glFrameTerminatorGREMEDY";
+       break;
+    case ApiTrace::FrameMarker_Flush:
+       return name == "glFlush";
+       break;
+    case ApiTrace::FrameMarker_Finish:
+       return name == "glFinish";
+       break;
+    case ApiTrace::FrameMarker_Clear:
+       return name == "glClear";
+       break;
+    }
+    return false;
+}
+
+int TraceLoader::numberOfFrames() const
+{
+    return m_frameOffsets.size();
+}
+
+int TraceLoader::numberOfCallsInFrame(int frameIdx) const
+{
+    if (frameIdx > m_frameOffsets.size()) {
+        return 0;
+    }
+    FrameOffsets::const_iterator itr =
+          m_frameOffsets.find(frameIdx);
+    return itr->numberOfCalls;
+}
+
+void TraceLoader::loadHelpFile()
+{
+   QFile file(":/resources/glreference.tsv");
+   if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+      QString line;
+      while (!file.atEnd()) {
+         line = file.readLine();
+         QString function = line.section('\t', 0, 0).trimmed();
+         QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
+         //qDebug()<<"function = "<<function<<", url = "<<url.toString();
+         m_helpHash.insert(function, url);
+      }
+   } else {
+      qWarning() << "Couldn't open reference file "
+                 << file.fileName();
+   }
+   file.close();
+}
+
+void TraceLoader::scanTrace()
+{
+   QList<ApiTraceFrame*> frames;
+   ApiTraceFrame *currentFrame = 0;
+
+   Trace::Call *call;
+   Trace::File::Offset startOffset;
+   int numOfFrames = 0;
+   int numOfCalls = 0;
+   unsigned callNum = 0;
+   int lastPercentReport = 0;
+
+   startOffset = m_parser.currentOffset();
+   callNum = m_parser.currentCallNumber();
+
+   while ((call = m_parser.scan_call())) {
+       ++numOfCalls;
+
+       if (isCallAFrameMarker(call)) {
+           Trace::File::Offset endOffset = m_parser.currentOffset();
+           FrameOffset frameOffset(startOffset);
+           frameOffset.numberOfCalls = numOfCalls;
+           frameOffset.callNumber = callNum;
+
+           currentFrame = new ApiTraceFrame(m_trace);
+           currentFrame->number = numOfFrames;
+           currentFrame->setNumChildren(numOfCalls);
+           frames.append(currentFrame);
+
+           m_frameOffsets[numOfFrames] = frameOffset;
+           ++numOfFrames;
+
+           if (m_parser.percentRead() - lastPercentReport >= 5) {
+               emit parsed(m_parser.percentRead());
+               lastPercentReport = m_parser.percentRead();
+           }
+           startOffset = endOffset;
+           callNum = m_parser.currentCallNumber();
+           numOfCalls = 0;
+       }
+       //call->dump(std::cout, color);
+       delete call;
+   }
+
+   if (numOfCalls) {
+//      Trace::File::Offset endOffset = m_parser.currentOffset();
+      FrameOffset frameOffset(startOffset);
+      frameOffset.numberOfCalls = numOfCalls;
+      frameOffset.callNumber = callNum;
+
+      currentFrame = new ApiTraceFrame(m_trace);
+      currentFrame->number = numOfFrames;
+      currentFrame->setNumChildren(numOfCalls);
+      frames.append(currentFrame);
+
+      m_frameOffsets[numOfFrames] = frameOffset;
+      ++numOfFrames;
+   }
+
+   emit parsed(100);
+
+   emit framesLoaded(frames);
+}
+
+void TraceLoader::parseTrace()
+{
+   QList<ApiTraceFrame*> frames;
+   ApiTraceFrame *currentFrame = 0;
+   int frameCount = 0;
+   QVector<ApiTraceCall*> calls;
+   quint64 binaryDataSize = 0;
+
+   int lastPercentReport = 0;
+
+   Trace::Call *call = m_parser.parse_call();
+   while (call) {
+      //std::cout << *call;
+      if (!currentFrame) {
+         currentFrame = new ApiTraceFrame(m_trace);
+         currentFrame->number = frameCount;
+         ++frameCount;
+      }
+      ApiTraceCall *apiCall =
+            apiCallFromTraceCall(call, m_helpHash, currentFrame);
+      calls.append(apiCall);
+      if (apiCall->hasBinaryData()) {
+         QByteArray data =
+               apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+         binaryDataSize += data.size();
+      }
+      if (ApiTrace::isCallAFrameMarker(apiCall,
+                                       m_frameMarker)) {
+         calls.squeeze();
+         currentFrame->setCalls(calls, binaryDataSize);
+         calls.clear();
+         frames.append(currentFrame);
+         currentFrame = 0;
+         binaryDataSize = 0;
+         if (frames.count() >= FRAMES_TO_CACHE) {
+            emit framesLoaded(frames);
+            frames.clear();
+         }
+         if (m_parser.percentRead() - lastPercentReport >= 5) {
+            emit parsed(m_parser.percentRead());
+            lastPercentReport = m_parser.percentRead();
+         }
+      }
+      delete call;
+      call = m_parser.parse_call();
+   }
+
+   //last frames won't have markers
+   //  it's just a bunch of Delete calls for every object
+   //  after the last SwapBuffers
+   if (currentFrame) {
+      if (!frames.count()) {
+         calls.squeeze();
+         currentFrame->setCalls(calls, binaryDataSize);
+      }
+      frames.append(currentFrame);
+      currentFrame = 0;
+   }
+   if (frames.count()) {
+      emit framesLoaded(frames);
+   }
+}
+
+
+#include "traceloader.moc"
diff --git a/gui/traceloader.h b/gui/traceloader.h
new file mode 100644 (file)
index 0000000..e9c4171
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef TRACELOADER_H
+#define TRACELOADER_H
+
+
+#include "apitrace.h"
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <QObject>
+#include <QList>
+#include <QMap>
+
+class TraceLoader : public QObject
+{
+    Q_OBJECT
+public:
+    TraceLoader(ApiTrace *parent);
+    ~TraceLoader();
+
+public slots:
+    void loadTrace(const QString &filename);
+    void loadFrame(int frameIdx);
+    void setFrameMarker(ApiTrace::FrameMarker marker);
+
+signals:
+    void startedParsing();
+    void parsed(float percent);
+    void finishedParsing();
+
+    void framesLoaded(const QList<ApiTraceFrame*> &frames);
+    void frameLoaded(int frameIdx,
+                     const QVector<ApiTraceCall*> &calls,
+                     quint64 binaryDataSize);
+
+private:
+    struct FrameOffset {
+        FrameOffset()
+            : numberOfCalls(0)
+        {}
+        FrameOffset(const Trace::File::Offset &s)
+            : start(s),
+              numberOfCalls(0)
+        {}
+
+        Trace::File::Offset start;
+        int numberOfCalls;
+        unsigned callNumber;
+    };
+    bool isCallAFrameMarker(const Trace::Call *call) const;
+    int numberOfFrames() const;
+    int numberOfCallsInFrame(int frameIdx) const;
+
+    void loadHelpFile();
+    void scanTrace();
+    void parseTrace();
+private:
+    ApiTrace *m_trace;
+    Trace::Parser m_parser;
+    QString m_fileName;
+    ApiTrace::FrameMarker m_frameMarker;
+
+    typedef QMap<int, FrameOffset> FrameOffsets;
+    FrameOffsets m_frameOffsets;
+
+    QHash<QString, QUrl> m_helpHash;
+};
+
+#endif