]> git.cworth.org Git - apitrace/commitdiff
Merge remote-tracking branch 'origin/master' into on-demand-loading
authorZack Rusin <zack@kde.org>
Tue, 6 Sep 2011 21:45:34 +0000 (17:45 -0400)
committerZack Rusin <zack@kde.org>
Tue, 6 Sep 2011 21:45:34 +0000 (17:45 -0400)
20 files changed:
CMakeLists.txt
gui/CMakeLists.txt
gui/apitrace.cpp
gui/apitrace.h
gui/apitracecall.cpp
gui/apitracecall.h
gui/apitracemodel.cpp
gui/mainwindow.cpp
gui/mainwindow.h
gui/traceloader.cpp [new file with mode: 0644]
gui/traceloader.h [new file with mode: 0644]
loadertest.cpp [new file with mode: 0644]
trace_file.cpp
trace_file.hpp
trace_loader.cpp [new file with mode: 0644]
trace_loader.hpp [new file with mode: 0644]
trace_parser.cpp
trace_parser.hpp
trace_snappyfile.cpp
trace_snappyfile.hpp

index e840f21d193608b386d33edf84f72ea3511e1ea9..2ee433a51dd1814eb0f518f22139c0fba416b351 100755 (executable)
@@ -187,6 +187,7 @@ add_library (common
     trace_writer.cpp
     trace_local_writer.cpp
     trace_model_writer.cpp
+    trace_loader.cpp
     image.cpp
     image_bmp.cpp
     image_pnm.cpp
@@ -204,6 +205,8 @@ link_libraries (common)
 add_executable (tracedump tracedump.cpp)
 install (TARGETS tracedump RUNTIME DESTINATION bin) 
 
+add_executable (loadertest loadertest.cpp)
+install (TARGETS loadertest RUNTIME DESTINATION bin)
 
 ##############################################################################
 # API tracers
index 6973450a9e5c16a1688ae24c233f8623d319af00..777bc9255c7c1d4c83207ec7ac12e826657e1700 100644 (file)
@@ -12,7 +12,6 @@ set(qapitrace_SRCS
    glsledit.cpp
    imageviewer.cpp
    jumpwidget.cpp
-   loaderthread.cpp
    mainwindow.cpp
    main.cpp
    retracer.cpp
@@ -21,6 +20,7 @@ set(qapitrace_SRCS
    settingsdialog.cpp
    shaderssourcewidget.cpp
    tracedialog.cpp
+   traceloader.cpp
    traceprocess.cpp
    vertexdatainterpreter.cpp
  )
index 51c4755b28194a70b635ac16d3230ef5c03623b1..d6a9e41375c2cda6ef5f39eb43084e21d2b35cc0 100644 (file)
@@ -1,31 +1,46 @@
 #include "apitrace.h"
 
-#include "loaderthread.h"
+#include "traceloader.h"
 #include "saverthread.h"
 
 #include <QDir>
+#include <QThread>
 
 ApiTrace::ApiTrace()
     : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
       m_needsSaving(false)
 {
-    m_loader = new LoaderThread(this);
-    connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
+    m_loader = new TraceLoader();
+    connect(this, SIGNAL(loadTrace(QString)),
+            m_loader, SLOT(loadTrace(QString)));
+    connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
             this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
-    connect(m_loader, SIGNAL(started()),
+    connect(m_loader, SIGNAL(frameLoaded(int,QVector<ApiTraceCall*>,quint64)),
+            this, SLOT(fillFrame(int,QVector<ApiTraceCall*>,quint64)));
+
+    connect(m_loader, SIGNAL(startedParsing()),
             this, SIGNAL(startedLoadingTrace()));
-    connect(m_loader, SIGNAL(finished()),
+    connect(m_loader, SIGNAL(parsed(int)),
+            this, SIGNAL(loaded(int)));
+    connect(m_loader, SIGNAL(finishedParsing()),
             this, SIGNAL(finishedLoadingTrace()));
 
+
     m_saver = new SaverThread(this);
     connect(m_saver, SIGNAL(traceSaved()),
             this, SLOT(slotSaved()));
     connect(m_saver, SIGNAL(traceSaved()),
             this, SIGNAL(saved()));
+
+    m_loaderThread = new QThread();
+    m_loader->moveToThread(m_loaderThread);
+    m_loaderThread->start();
 }
 
 ApiTrace::~ApiTrace()
 {
+    m_loaderThread->quit();
+    m_loaderThread->deleteLater();
     qDeleteAll(m_calls);
     qDeleteAll(m_frames);
     delete m_loader;
@@ -118,10 +133,6 @@ void ApiTrace::setFileName(const QString &name)
     if (m_fileName != name) {
         m_fileName = name;
 
-        if (m_loader->isRunning()) {
-            m_loader->terminate();
-            m_loader->wait();
-        }
         m_frames.clear();
         m_calls.clear();
         m_errors.clear();
@@ -129,7 +140,8 @@ void ApiTrace::setFileName(const QString &name)
         m_needsSaving = false;
         emit invalidated();
 
-        m_loader->loadFile(m_fileName);
+//        m_loader->loadTrace(m_fileName);
+        emit loadTrace(m_fileName);
     }
 }
 
@@ -157,7 +169,7 @@ void ApiTrace::addFrames(const QList<ApiTraceFrame*> &frames)
     int currentCalls = m_calls.count();
     int numNewCalls = 0;
     foreach(ApiTraceFrame *frame, frames) {
-        Q_ASSERT(this == frame->parentTrace());
+        frame->setParentTrace(this);
         numNewCalls += frame->numChildren();
         calls += frame->calls();
     }
@@ -180,6 +192,7 @@ void ApiTrace::detectFrames()
         if (!currentFrame) {
             currentFrame = new ApiTraceFrame(this);
             currentFrame->number = m_frames.count();
+            currentFrame->setLoaded(true);
         }
         apiCall->setParentFrame(currentFrame);
         currentFrame->addCall(apiCall);
@@ -289,34 +302,9 @@ bool ApiTrace::hasErrors() const
     return !m_errors.isEmpty();
 }
 
-ApiTraceCallSignature * ApiTrace::signature(unsigned id)
-{
-    if (id >= m_signatures.count()) {
-        m_signatures.resize(id + 1);
-        return NULL;
-    } else {
-        return m_signatures[id];
-    }
-}
-
-void ApiTrace::addSignature(unsigned id, ApiTraceCallSignature *signature)
-{
-    m_signatures[id] = signature;
-}
-
-ApiTraceEnumSignature * ApiTrace::enumSignature(unsigned id)
-{
-    if (id >= m_enumSignatures.count()) {
-        m_enumSignatures.resize(id + 1);
-        return NULL;
-    } else {
-        return m_enumSignatures[id];
-    }
-}
-
-void ApiTrace::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
+void ApiTrace::fillFrame(int frameIdx, const QVector<ApiTraceCall *> &calls,
+                         quint64 binaryDataSize)
 {
-    m_enumSignatures[id] = signature;
 }
 
 #include "apitrace.moc"
index 036a84cdd0b14f150560570c6104b8c543772169..3b737e0bbe81c3281d5e54e463b8029d6163aeb9 100644 (file)
@@ -6,8 +6,9 @@
 #include <QObject>
 #include <QSet>
 
-class LoaderThread;
+class TraceLoader;
 class SaverThread;
+class QThread;
 
 class ApiTrace : public QObject
 {
@@ -33,13 +34,6 @@ public:
 
     ApiTraceState defaultState() const;
 
-    ApiTraceCallSignature *signature(unsigned id);
-    void addSignature(unsigned id, ApiTraceCallSignature *signature);
-
-    ApiTraceEnumSignature *enumSignature(unsigned id);
-    void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature);
-
-
     QVector<ApiTraceCall*> calls() const;
     ApiTraceCall *callAt(int idx) const;
     ApiTraceCall *callWithIndex(int idx) const;
@@ -67,7 +61,9 @@ public slots:
     void save();
 
 signals:
+    void loadTrace(const QString &name);
     void startedLoadingTrace();
+    void loaded(int percent);
     void finishedLoadingTrace();
     void invalidated();
     void framesInvalidated();
@@ -81,6 +77,8 @@ signals:
 
 private slots:
     void addFrames(const QList<ApiTraceFrame*> &frames);
+    void fillFrame(int frameIdx, const QVector<ApiTraceCall*> &calls,
+                   quint64 binaryDataSize);
     void slotSaved();
 private:
     void detectFrames();
@@ -93,7 +91,8 @@ private:
 
     FrameMarker m_frameMarker;
 
-    LoaderThread *m_loader;
+    TraceLoader *m_loader;
+    QThread     *m_loaderThread;
     SaverThread  *m_saver;
 
     QSet<ApiTraceCall*> m_editedCalls;
@@ -101,8 +100,6 @@ private:
     bool m_needsSaving;
 
     QSet<ApiTraceCall*> m_errors;
-    QVector<ApiTraceCallSignature*> m_signatures;
-    QVector<ApiTraceEnumSignature*> m_enumSignatures;
 };
 
 #endif
index bd30aaaa89aff9a333ea84f13dc534e2b62d4a42..d1de5a85f5c29700f2e01da4790abe21abf2b21d 100644 (file)
@@ -1,6 +1,7 @@
 #include "apitracecall.h"
 
 #include "apitrace.h"
+#include "traceloader.h"
 #include "trace_model.hpp"
 
 #include <QDebug>
@@ -175,15 +176,15 @@ void VariantVisitor::visit(Trace::Enum *e)
 {
     ApiTraceEnumSignature *sig = 0;
 
-    if (m_trace) {
-        sig = m_trace->enumSignature(e->sig->id);
+    if (m_loader) {
+        sig = m_loader->enumSignature(e->sig->id);
     }
     if (!sig) {
         sig = new ApiTraceEnumSignature(
             QString::fromStdString(e->sig->name),
             QVariant(e->sig->value));
-        if (m_trace) {
-            m_trace->addEnumSignature(e->sig->id, sig);
+        if (m_loader) {
+            m_loader->addEnumSignature(e->sig->id, sig);
         }
     }
 
@@ -600,17 +601,15 @@ void ApiTraceEvent::setState(ApiTraceState *state)
     m_state = state;
 }
 
-ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call)
+ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame,
+                           TraceLoader *loader,
+                           const Trace::Call *call)
     : ApiTraceEvent(ApiTraceEvent::Call),
       m_parentFrame(parentFrame)
 {
-    ApiTrace *trace = parentTrace();
-
-    Q_ASSERT(trace);
-
     m_index = call->no;
 
-    m_signature = trace->signature(call->sig->id);
+    m_signature = loader->signature(call->sig->id);
 
     if (!m_signature) {
         QString name = QString::fromStdString(call->sig->name);
@@ -620,16 +619,16 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call)
             argNames += QString::fromStdString(call->sig->arg_names[i]);
         }
         m_signature = new ApiTraceCallSignature(name, argNames);
-        trace->addSignature(call->sig->id, m_signature);
+        loader->addSignature(call->sig->id, m_signature);
     }
     if (call->ret) {
-        VariantVisitor retVisitor(trace);
+        VariantVisitor retVisitor(loader);
         call->ret->visit(retVisitor);
         m_returnValue = retVisitor.variant();
     }
     m_argValues.reserve(call->args.size());
     for (int i = 0; i < call->args.size(); ++i) {
-        VariantVisitor argVisitor(trace);
+        VariantVisitor argVisitor(loader);
         call->args[i]->visit(argVisitor);
         m_argValues.append(argVisitor.variant());
         if (m_argValues[i].type() == QVariant::ByteArray) {
@@ -923,7 +922,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 +965,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 +1017,25 @@ 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;
+}
+
+void ApiTraceFrame::setParentTrace(ApiTrace *parent)
+{
+    m_parentTrace = parent;
 }
index 33648f2f28b054803d15e8f38b0ab1cd2b05e011..865f60c2ff7d406df6f3a52846794ce44b5122d5 100644 (file)
 
 
 class ApiTrace;
+class TraceLoader;
 
 class VariantVisitor : public Trace::Visitor
 {
 public:
-    VariantVisitor(ApiTrace *trace)
-        : m_trace(trace)
+    VariantVisitor(TraceLoader *loader)
+        : m_loader(loader)
     {}
     virtual void visit(Trace::Null *);
     virtual void visit(Trace::Bool *node);
@@ -37,7 +38,7 @@ public:
         return m_variant;
     }
 private:
-    ApiTrace *m_trace;
+    TraceLoader *m_loader;
     QVariant m_variant;
 };
 
@@ -233,7 +234,8 @@ Q_DECLARE_METATYPE(ApiTraceEvent*);
 class ApiTraceCall : public ApiTraceEvent
 {
 public:
-    ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *tcall);
+    ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader,
+                 const Trace::Call *tcall);
     ~ApiTraceCall();
 
     int index() const;
@@ -284,13 +286,15 @@ Q_DECLARE_METATYPE(ApiTraceCall*);
 class ApiTraceFrame : public ApiTraceEvent
 {
 public:
-    ApiTraceFrame(ApiTrace *parent);
+    ApiTraceFrame(ApiTrace *parent=0);
     int number;
 
     bool isEmpty() const;
 
+    void setParentTrace(ApiTrace *parent);
     ApiTrace *parentTrace() const;
 
+    void setNumChildren(int num);
     int numChildren() const;
     QStaticText staticText() const;
 
@@ -302,10 +306,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*);
 
index 5860cf9530e4d66310d6497db52454b7f9f085fc..800b5c7457d03781e1f9d25726335922c0dbf9fd 100644 (file)
@@ -1,7 +1,7 @@
 #include "apitracemodel.h"
 
 #include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
 #include "trace_parser.hpp"
 
 #include <QDebug>
index 591c557e55567eda81a93c1341eadf7cc727aa7a..e5f6d9b2a4b7852a71d375fac33055940e6cbf8c 100644 (file)
@@ -647,7 +647,7 @@ void MainWindow::initObjects()
     m_ui.callView->setContextMenuPolicy(Qt::CustomContextMenu);
 
     m_progressBar = new QProgressBar();
-    m_progressBar->setRange(0, 0);
+    m_progressBar->setRange(0, 100);
     statusBar()->addPermanentWidget(m_progressBar);
     m_progressBar->hide();
 
@@ -682,6 +682,8 @@ void MainWindow::initConnections()
 {
     connect(m_trace, SIGNAL(startedLoadingTrace()),
             this, SLOT(startedLoadingTrace()));
+    connect(m_trace, SIGNAL(loaded(int)),
+            this, SLOT(loadProgess(int)));
     connect(m_trace, SIGNAL(finishedLoadingTrace()),
             this, SLOT(finishedLoadingTrace()));
     connect(m_trace, SIGNAL(startedSaving()),
@@ -1159,4 +1161,9 @@ void MainWindow::saveSelectedSurface()
     statusBar()->showMessage( tr("Saved '%1'").arg(fileName), 5000);
 }
 
+void MainWindow::loadProgess(int percent)
+{
+    m_progressBar->setValue(percent);
+}
+
 #include "mainwindow.moc"
index f3e31811717f4a218f60860df2f5e203534125cd..00fe04b25ce698322e9294eee5e427e2f8f0ed1e 100644 (file)
@@ -46,6 +46,7 @@ private slots:
     void replayStateFound(ApiTraceState *state);
     void replayError(const QString &msg);
     void startedLoadingTrace();
+    void loadProgess(int percent);
     void finishedLoadingTrace();
     void lookupState();
     void showSettings();
diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp
new file mode 100644 (file)
index 0000000..0303ee7
--- /dev/null
@@ -0,0 +1,305 @@
+#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,
+                     TraceLoader *loader)
+{
+    ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
+
+    apiCall->setHelpUrl(helpHash.value(apiCall->name()));
+
+    return apiCall;
+}
+
+TraceLoader::TraceLoader(QObject *parent)
+    : QObject(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;
+    }
+    qDebug()<<"load trace with "<<filename;
+    emit startedParsing();
+
+    qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
+    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();
+           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();
+      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();
+         currentFrame->number = frameCount;
+         ++frameCount;
+      }
+      ApiTraceCall *apiCall =
+            apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
+      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) {
+            qDebug()<<"emitting = " << m_parser.percentRead();
+            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);
+   }
+}
+
+
+ApiTraceCallSignature * TraceLoader::signature(unsigned id)
+{
+    if (id >= m_signatures.count()) {
+        m_signatures.resize(id + 1);
+        return NULL;
+    } else {
+        return m_signatures[id];
+    }
+}
+
+void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
+{
+    m_signatures[id] = signature;
+}
+
+ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
+{
+    if (id >= m_enumSignatures.count()) {
+        m_enumSignatures.resize(id + 1);
+        return NULL;
+    } else {
+        return m_enumSignatures[id];
+    }
+}
+
+void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
+{
+    m_enumSignatures[id] = signature;
+}
+
+#include "traceloader.moc"
diff --git a/gui/traceloader.h b/gui/traceloader.h
new file mode 100644 (file)
index 0000000..32c7f16
--- /dev/null
@@ -0,0 +1,78 @@
+#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(QObject *parent=0);
+    ~TraceLoader();
+
+
+    ApiTraceCallSignature *signature(unsigned id);
+    void addSignature(unsigned id, ApiTraceCallSignature *signature);
+
+    ApiTraceEnumSignature *enumSignature(unsigned id);
+    void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature);
+
+public slots:
+    void loadTrace(const QString &filename);
+    void loadFrame(int frameIdx);
+    void setFrameMarker(ApiTrace::FrameMarker marker);
+
+signals:
+    void startedParsing();
+    void parsed(int 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:
+    Trace::Parser m_parser;
+    QString m_fileName;
+    ApiTrace::FrameMarker m_frameMarker;
+
+    typedef QMap<int, FrameOffset> FrameOffsets;
+    FrameOffsets m_frameOffsets;
+
+    QHash<QString, QUrl> m_helpHash;
+
+    QVector<ApiTraceCallSignature*> m_signatures;
+    QVector<ApiTraceEnumSignature*> m_enumSignatures;
+};
+
+#endif
diff --git a/loadertest.cpp b/loadertest.cpp
new file mode 100644 (file)
index 0000000..397187a
--- /dev/null
@@ -0,0 +1,72 @@
+#include "trace_loader.hpp"
+#include "os.hpp"
+
+#include <iostream>
+
+
+static const double msecsInSec = 1000000;
+
+static void timeFrameFetch(Trace::Loader &loader, unsigned frameIdx)
+{
+    long long t1, t2;
+    std::vector<Trace::Call*> frame;
+
+    t1 = OS::GetTime();
+    frame = loader.frame(frameIdx);
+    t2 = OS::GetTime();
+    std::cout << "Time to fetch the frame["
+              << frameIdx
+              << "] size "
+              << frame.size()
+              << " is = "
+              << (t2 - t1)/msecsInSec
+              << " secs "<<std::endl;
+}
+
+
+int main(int argc, char **argv)
+{
+    int i;
+
+    for (i = 1; i < argc; ++i) {
+        Trace::Loader loader;
+
+        long long t1 = OS::GetTime();
+        if (!loader.open(argv[i])) {
+            std::cerr << "error: failed to open " << argv[i] << "\n";
+            return 1;
+        }
+        long long t2 = OS::GetTime();
+        std::cout << "Time to scan file = "<< (t2 - t1)/msecsInSec
+                  << " secs "<<std::endl;
+
+        std::cout << "Number of frames = "
+                  << loader.numberOfFrames()
+                  << std::endl;
+        std::cout << "Number of calls in frame 0 = "
+                  << loader.numberOfCallsInFrame(0)
+                  << std::endl;
+        int lastFrame = loader.numberOfFrames() - 1;
+        std::cout << "Number of calls in frame "
+                  << lastFrame << " = "
+                  << loader.numberOfCallsInFrame(lastFrame)
+                  << std::endl;
+
+        unsigned biggestFrameIdx = 0;
+        unsigned maxFrameSize = 0;
+        for (unsigned i = 0; i < loader.numberOfFrames(); ++i) {
+            if (loader.numberOfCallsInFrame(i) > maxFrameSize) {
+                maxFrameSize = loader.numberOfCallsInFrame(i);
+                biggestFrameIdx = i;
+            }
+        }
+
+        timeFrameFetch(loader, loader.numberOfFrames()/2);
+        timeFrameFetch(loader, 0);
+        timeFrameFetch(loader, loader.numberOfFrames() - 1);
+        timeFrameFetch(loader, biggestFrameIdx);
+    }
+
+    return 0;
+}
+
index 81b5d03c1f3f273f972f7b8b3d9db8be22f53336..45473b345ffa3a3cae447ccab1fe101e93f91514 100644 (file)
@@ -56,6 +56,16 @@ File::~File()
     close();
 }
 
+
+File::Offset File::currentOffset()
+{
+    return File::Offset();
+}
+
+void File::setCurrentOffset(const File::Offset &offset)
+{
+}
+
 bool File::isZLibCompressed(const std::string &filename)
 {
     std::fstream stream(filename.c_str(),
@@ -87,6 +97,12 @@ bool File::isSnappyCompressed(const std::string &filename)
     return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
 }
 
+typedef struct gz_stream {
+    z_stream stream;
+    int      z_err;   /* error code for last stream operation */
+    int      z_eof;   /* set if end of input file */
+    FILE     *file;   /* .gz file */
+} gz_dummy_stream;
 
 ZLibFile::ZLibFile(const std::string &filename,
                    File::Mode mode)
@@ -103,6 +119,19 @@ bool ZLibFile::rawOpen(const std::string &filename, File::Mode mode)
 {
     m_gzFile = gzopen(filename.c_str(),
                       (mode == File::Write) ? "wb" : "rb");
+
+    if (mode == File::Read && m_gzFile) {
+        //XXX: unfortunately zlib doesn't support
+        //     SEEK_END or we could've done:
+        //m_endOffset = gzseek(m_gzFile, 0, SEEK_END);
+        //gzrewind(m_gzFile);
+        gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+        long loc = ftell(stream->file);
+        fseek(stream->file,0,SEEK_END);
+        m_endOffset = ftell(stream->file);
+        fseek(stream->file, loc, SEEK_SET);
+    }
+
     return m_gzFile != NULL;
 }
 
@@ -133,3 +162,20 @@ void ZLibFile::rawFlush()
 {
     gzflush(m_gzFile, Z_SYNC_FLUSH);
 }
+
+
+bool ZLibFile::supportsOffsets() const
+{
+    return false;
+}
+
+bool ZLibFile::rawSkip(size_t)
+{
+    return false;
+}
+
+int ZLibFile::rawPercentRead()
+{
+    gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+    return 100 * (ftell(stream->file) / m_endOffset);
+}
index 60a8459d93c9436283deceae508b7708071ace0b..f6e77ae8b69802c88f96b8b31b48d6f3cd2c013c 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <string>
 #include <fstream>
+#include <stdint.h>
 
 namespace Trace {
 
@@ -38,6 +39,15 @@ public:
         Read,
         Write
     };
+    struct Offset {
+        Offset()
+            : chunk(0),
+              offsetInChunk(0)
+        {}
+        uint64_t chunk;
+        uint32_t offsetInChunk;
+    };
+
 public:
     static bool isZLibCompressed(const std::string &filename);
     static bool isSnappyCompressed(const std::string &filename);
@@ -57,7 +67,12 @@ public:
     void close();
     void flush(void);
     int getc();
+    bool skip(size_t length);
+    int percentRead();
 
+    virtual bool supportsOffsets() const = 0;
+    virtual File::Offset currentOffset();
+    virtual void setCurrentOffset(const File::Offset &offset);
 protected:
     virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0;
     virtual bool rawWrite(const void *buffer, size_t length) = 0;
@@ -65,6 +80,8 @@ protected:
     virtual int rawGetc() = 0;
     virtual void rawClose() = 0;
     virtual void rawFlush() = 0;
+    virtual bool rawSkip(size_t length) = 0;
+    virtual int rawPercentRead() = 0;
 
 protected:
     std::string m_filename;
@@ -114,6 +131,14 @@ inline bool File::read(void *buffer, size_t length)
     return rawRead(buffer, length);
 }
 
+inline int File::percentRead()
+{
+    if (!m_isOpened || m_mode != File::Read) {
+        return 0;
+    }
+    return rawPercentRead();
+}
+
 inline void File::close()
 {
     if (m_isOpened) {
@@ -137,12 +162,22 @@ inline int File::getc()
     return rawGetc();
 }
 
+inline bool File::skip(size_t length)
+{
+    if (!m_isOpened || m_mode != File::Read) {
+        return false;
+    }
+    return rawSkip(length);
+}
+
 class ZLibFile : public File {
 public:
     ZLibFile(const std::string &filename = std::string(),
              File::Mode mode = File::Read);
     virtual ~ZLibFile();
 
+
+    virtual bool supportsOffsets() const;
 protected:
     virtual bool rawOpen(const std::string &filename, File::Mode mode);
     virtual bool rawWrite(const void *buffer, size_t length);
@@ -150,10 +185,47 @@ protected:
     virtual int rawGetc();
     virtual void rawClose();
     virtual void rawFlush();
+    virtual bool rawSkip(size_t length);
+    virtual int  rawPercentRead();
 private:
     void *m_gzFile;
+    double m_endOffset;
 };
 
+inline bool
+operator<(const File::Offset &one, const File::Offset &two)
+{
+    return one.chunk < two.chunk ||
+            (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk);
+}
+
+inline bool
+operator==(const File::Offset &one, const File::Offset &two)
+{
+    return one.chunk == two.chunk &&
+            one.offsetInChunk == two.offsetInChunk;
+}
+
+inline bool
+operator>=(const File::Offset &one, const File::Offset &two)
+{
+    return one.chunk > two.chunk ||
+            (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk);
+}
+
+inline bool
+operator>(const File::Offset &one, const File::Offset &two)
+{
+    return two < one;
+}
+
+inline bool
+operator<=(const File::Offset &one, const File::Offset &two)
+{
+    return two >= one;
+}
+
+
 }
 
 #endif
diff --git a/trace_loader.cpp b/trace_loader.cpp
new file mode 100644 (file)
index 0000000..f91e09b
--- /dev/null
@@ -0,0 +1,145 @@
+#include "trace_loader.hpp"
+
+#include "trace_snappyfile.hpp"
+
+using namespace Trace;
+
+Loader::Loader()
+    : m_frameMarker(FrameMarker_SwapBuffers)
+{
+}
+
+Loader::~Loader()
+{
+    close();
+}
+
+Loader::FrameMarker Loader::frameMarker() const
+{
+    return m_frameMarker;
+}
+
+void Loader::setFrameMarker(Loader::FrameMarker marker)
+{
+    m_frameMarker = marker;
+}
+
+int Loader::numberOfFrames() const
+{
+    return m_frameOffsets.size();
+}
+
+int Loader::numberOfCallsInFrame(int frameIdx) const
+{
+    if (frameIdx > m_frameOffsets.size()) {
+        return 0;
+    }
+    FrameOffsets::const_iterator itr =
+        m_frameOffsets.find(frameIdx);
+    return itr->second.numberOfCalls;
+}
+
+bool Loader::open(const char *filename)
+{
+    if (!m_parser.open(filename)) {
+        std::cerr << "error: failed to open " << filename << "\n";
+        return false;
+    }
+    if (!m_parser.supportsOffsets()) {
+        std::cerr << "error: " <<filename<< " doesn't support seeking "
+                  << "\n";
+        return false;
+    }
+
+    Trace::Call *call;
+    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)) {
+            File::Offset endOffset = m_parser.currentOffset();
+            FrameOffset frameOffset(startOffset);
+            frameOffset.numberOfCalls = numOfCalls;
+            frameOffset.callNumber = callNum;
+
+            m_frameOffsets[numOfFrames] = frameOffset;
+            ++numOfFrames;
+
+            if (m_parser.percentRead() - lastPercentReport >= 5) {
+                std::cerr << "\tPercent scanned = "
+                          << m_parser.percentRead()
+                          << "..."<<std::endl;
+                lastPercentReport = m_parser.percentRead();
+            }
+            startOffset = endOffset;
+            callNum = m_parser.currentCallNumber();
+            numOfCalls = 0;
+        }
+        //call->dump(std::cout, color);
+        delete call;
+    }
+    return true;
+}
+
+void Loader::close()
+{
+    m_parser.close();
+}
+
+bool Loader::isCallAFrameMarker(const Trace::Call *call) const
+{
+    std::string name = call->name();
+
+    switch (m_frameMarker) {
+    case FrameMarker_SwapBuffers:
+        return  name.find("SwapBuffers") != std::string::npos ||
+                name == "CGLFlushDrawable" ||
+                name == "glFrameTerminatorGREMEDY";
+        break;
+    case FrameMarker_Flush:
+        return name == "glFlush";
+        break;
+    case FrameMarker_Finish:
+        return name == "glFinish";
+        break;
+    case FrameMarker_Clear:
+        return name == "glClear";
+        break;
+    }
+    return false;
+}
+
+std::vector<Trace::Call *> Loader::frame(int idx)
+{
+    int numOfCalls = numberOfCallsInFrame(idx);
+    if (numOfCalls) {
+        const FrameOffset &frameOffset = m_frameOffsets[idx];
+        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);
+        return calls;
+    }
+    return std::vector<Trace::Call*>();
+}
diff --git a/trace_loader.hpp b/trace_loader.hpp
new file mode 100644 (file)
index 0000000..86a56bd
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef TRACE_LOADER_HPP
+#define TRACE_LOADER_HPP
+
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <string>
+#include <map>
+#include <queue>
+#include <vector>
+
+namespace Trace  {
+
+class Frame;
+
+class Loader
+{
+public:
+    enum FrameMarker {
+        FrameMarker_SwapBuffers,
+        FrameMarker_Flush,
+        FrameMarker_Finish,
+        FrameMarker_Clear
+    };
+public:
+    Loader();
+    ~Loader();
+
+    Loader::FrameMarker frameMarker() const;
+    void setFrameMarker(Loader::FrameMarker marker);
+
+    int numberOfFrames() const;
+    int numberOfCallsInFrame(int frameIdx) const;
+
+    bool open(const char *filename);
+    void close();
+
+    std::vector<Trace::Call*> frame(int idx);
+
+private:
+    struct FrameOffset {
+        FrameOffset()
+            : numberOfCalls(0)
+        {}
+        FrameOffset(const File::Offset &s)
+            : start(s),
+              numberOfCalls(0)
+        {}
+
+        File::Offset start;
+        int numberOfCalls;
+        unsigned callNumber;
+    };
+    bool isCallAFrameMarker(const Trace::Call *call) const;
+
+private:
+    Trace::Parser m_parser;
+    FrameMarker m_frameMarker;
+
+    typedef std::map<int, FrameOffset> FrameOffsets;
+    FrameOffsets m_frameOffsets;
+};
+
+}
+
+#endif // TRACE_LOADER_HPP
index 44d1786ac207fe2fa576a88c9cfae90339013fdc..2ef77b6d79daf856636414358fd2c232afd414c6 100644 (file)
@@ -43,6 +43,7 @@ Parser::Parser() {
     file = NULL;
     next_call_no = 0;
     version = 0;
+    m_supportsSeeking = false;
 }
 
 
@@ -62,6 +63,7 @@ bool Parser::open(const char *filename) {
     if (!file->open(filename, File::Read)) {
         return false;
     }
+    m_supportsSeeking = file->supportsOffsets();
 
     version = read_uint();
     if (version > TRACE_VERSION) {
@@ -146,21 +148,44 @@ void Parser::parse_enter(void) {
     size_t id = read_uint();
 
     FunctionSig *sig = lookup(functions, id);
-    if (!sig) {
-        sig = new FunctionSig;
-        sig->id = id;
-        sig->name = read_string();
-        sig->num_args = read_uint();
-        const char **arg_names = new const char *[sig->num_args];
-        for (unsigned i = 0; i < sig->num_args; ++i) {
-            arg_names[i] = read_string();
+
+
+    File::Offset offset;
+    bool callWithSig = false;
+    if (m_supportsSeeking) {
+        offset = file->currentOffset();
+        callWithSig = callWithSignature(offset);
+    }
+
+    if (!sig || callWithSig) {
+        if (!sig) {
+            sig = new FunctionSig;
+            sig->id = id;
+            sig->name = read_string();
+            sig->num_args = read_uint();
+            const char **arg_names = new const char *[sig->num_args];
+            for (unsigned i = 0; i < sig->num_args; ++i) {
+                arg_names[i] = read_string();
+            }
+            sig->arg_names = arg_names;
+            functions[id] = sig;
+            if (m_supportsSeeking) {
+                m_callSigOffsets.insert(offset);
+            }
+        } else {
+            /* skip over the signature */
+            skip_string(); /* name */
+            int num_args = read_uint();
+            for (unsigned i = 0; i < num_args; ++i) {
+                 skip_string(); /*arg_name*/
+            }
         }
-        sig->arg_names = arg_names;
-        functions[id] = sig;
     }
     assert(sig);
 
     Call *call = new Call(sig);
+
+
     call->no = next_call_no++;
 
     if (parse_call_details(call)) {
@@ -322,14 +347,30 @@ Value *Parser::parse_string() {
 Value *Parser::parse_enum() {
     size_t id = read_uint();
     EnumSig *sig = lookup(enums, id);
-    if (!sig) {
-        sig = new EnumSig;
-        sig->id = id;
-        sig->name = read_string();
-        Value *value = parse_value();
-        sig->value = value->toSInt();
-        delete value;
-        enums[id] = sig;
+    File::Offset offset;
+    bool enumWithSig = false;
+
+    if (m_supportsSeeking) {
+        offset = file->currentOffset();
+        enumWithSig = enumWithSignature(offset);
+    }
+
+    if (!sig || enumWithSig) {
+        if (!sig) {
+            sig = new EnumSig;
+            sig->id = id;
+            sig->name = read_string();
+            Value *value = parse_value();
+            sig->value = value->toSInt();
+            delete value;
+            enums[id] = sig;
+            if (m_supportsSeeking) {
+                m_enumSigOffsets.insert(offset);
+            }
+        } else {
+            skip_string(); /*name*/
+            scan_value();
+        }
     }
     assert(sig);
     return new Enum(sig);
@@ -339,20 +380,39 @@ Value *Parser::parse_enum() {
 Value *Parser::parse_bitmask() {
     size_t id = read_uint();
     BitmaskSig *sig = lookup(bitmasks, id);
-    if (!sig) {
-        sig = new BitmaskSig;
-        sig->id = id;
-        sig->num_flags = read_uint();
-        BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
-        for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
-            it->name = read_string();
-            it->value = read_uint();
-            if (it->value == 0 && it != flags) {
-                std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
+    File::Offset offset;
+    bool bitmaskWithSig = false;
+
+    if (m_supportsSeeking) {
+        offset = file->currentOffset();
+        bitmaskWithSig = bitmaskWithSignature(offset);
+    }
+
+    if (!sig || bitmaskWithSig) {
+        if (!sig) {
+            sig = new BitmaskSig;
+            sig->id = id;
+            sig->num_flags = read_uint();
+            BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
+            for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
+                it->name = read_string();
+                it->value = read_uint();
+                if (it->value == 0 && it != flags) {
+                    std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
+                }
+            }
+            sig->flags = flags;
+            bitmasks[id] = sig;
+            if (m_supportsSeeking) {
+                m_bitmaskSigOffsets.insert(offset);
+            }
+        } else {
+            int num_flags = read_uint();
+            for (int i = 0; i < num_flags; ++i) {
+                skip_string(); /*name */
+                skip_uint(); /* value */
             }
         }
-        sig->flags = flags;
-        bitmasks[id] = sig;
     }
     assert(sig);
 
@@ -386,17 +446,36 @@ Value *Parser::parse_struct() {
     size_t id = read_uint();
 
     StructSig *sig = lookup(structs, id);
-    if (!sig) {
-        sig = new StructSig;
-        sig->id = id;
-        sig->name = read_string();
-        sig->num_members = read_uint();
-        const char **member_names = new const char *[sig->num_members];
-        for (unsigned i = 0; i < sig->num_members; ++i) {
-            member_names[i] = read_string();
+    File::Offset offset;
+    bool structWithSig = false;
+
+    if (m_supportsSeeking) {
+        offset = file->currentOffset();
+        structWithSig = structWithSignature(offset);
+    }
+
+    if (!sig || structWithSig) {
+        if (!sig) {
+            sig = new StructSig;
+            sig->id = id;
+            sig->name = read_string();
+            sig->num_members = read_uint();
+            const char **member_names = new const char *[sig->num_members];
+            for (unsigned i = 0; i < sig->num_members; ++i) {
+                member_names[i] = read_string();
+            }
+            sig->member_names = member_names;
+            structs[id] = sig;
+            if (m_supportsSeeking) {
+                m_structSigOffsets.insert(offset);
+            }
+        } else {
+            skip_string(); /* name */
+            unsigned num_members = read_uint();
+            for (unsigned i = 0; i < num_members; ++i) {
+                skip_string(); /* member_name */
+            }
         }
-        sig->member_names = member_names;
-        structs[id] = sig;
     }
     assert(sig);
 
@@ -462,4 +541,315 @@ inline int Parser::read_byte(void) {
 }
 
 
+inline bool Parser::callWithSignature(const File::Offset &offset) const
+{
+    return m_callSigOffsets.find(offset) != m_callSigOffsets.end();
+}
+
+inline bool Parser::structWithSignature(const File::Offset &offset) const
+{
+    return m_structSigOffsets.find(offset) != m_structSigOffsets.end();
+}
+
+inline bool Parser::enumWithSignature(const File::Offset &offset) const
+{
+    return m_enumSigOffsets.find(offset) != m_enumSigOffsets.end();
+}
+
+inline bool Parser::bitmaskWithSignature(const File::Offset &offset) const
+{
+    return m_bitmaskSigOffsets.find(offset) != m_bitmaskSigOffsets.end();
+}
+
+Call * Parser::scan_call()
+{
+    assert(m_supportsSeeking);
+    do {
+        int c = read_byte();
+        switch(c) {
+        case Trace::EVENT_ENTER:
+            scan_enter();
+            break;
+        case Trace::EVENT_LEAVE:
+            return scan_leave();
+        default:
+            std::cerr << "error: unknown event " << c << "\n";
+            exit(1);
+        case -1:
+            for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+                std::cerr << "warning: incomplete call " << (*it)->name() << "\n";
+                std::cerr << **it << "\n";
+            }
+            return NULL;
+        }
+    } while (true);
+}
+
+void Parser::scan_enter(void) {
+    size_t id = read_uint();
+
+    FunctionSig *sig = lookup(functions, id);
+    const File::Offset offset = file->currentOffset();
+    if (!sig) {
+        sig = new FunctionSig;
+        sig->id = id;
+        sig->name = read_string();
+        sig->num_args = read_uint();
+        const char **arg_names = new const char *[sig->num_args];
+        for (unsigned i = 0; i < sig->num_args; ++i) {
+            arg_names[i] = read_string();
+        }
+        sig->arg_names = arg_names;
+        functions[id] = sig;
+        m_callSigOffsets.insert(offset);
+    }
+    assert(sig);
+
+    Call *call = new Call(sig);
+    call->no = next_call_no++;
+
+    if (scan_call_details(call)) {
+        calls.push_back(call);
+    } else {
+        delete call;
+    }
+}
+
+Call *Parser::scan_leave(void) {
+    unsigned call_no = read_uint();
+    Call *call = NULL;
+    for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) {
+        if ((*it)->no == call_no) {
+            call = *it;
+            calls.erase(it);
+            break;
+        }
+    }
+    if (!call) {
+        return NULL;
+    }
+
+    if (scan_call_details(call)) {
+        return call;
+    } else {
+        delete call;
+        return NULL;
+    }
+}
+
+bool Parser::scan_call_details(Call *call) {
+    do {
+        int c = read_byte();
+        switch(c) {
+        case Trace::CALL_END:
+            return true;
+        case Trace::CALL_ARG:
+            scan_arg(call);
+            break;
+        case Trace::CALL_RET:
+            scan_value();
+            break;
+        default:
+            std::cerr << "error: ("<<call->name()<< ") unknown call detail "
+                      << c << "\n";
+            exit(1);
+        case -1:
+            return false;
+        }
+    } while(true);
+}
+
+void Parser::scan_arg(Call *call) {
+    skip_uint(); /* index */
+    scan_value(); /* value */
+}
+
+
+void Parser::scan_value(void) {
+    int c = read_byte();
+    switch(c) {
+    case Trace::TYPE_NULL:
+    case Trace::TYPE_FALSE:
+    case Trace::TYPE_TRUE:
+        break;
+    case Trace::TYPE_SINT:
+        scan_sint();
+        break;
+    case Trace::TYPE_UINT:
+        scan_uint();
+        break;
+    case Trace::TYPE_FLOAT:
+        scan_float();
+        break;
+    case Trace::TYPE_DOUBLE:
+        scan_double();
+        break;
+    case Trace::TYPE_STRING:
+        scan_string();
+        break;
+    case Trace::TYPE_ENUM:
+        scan_enum();
+        break;
+    case Trace::TYPE_BITMASK:
+        scan_bitmask();
+        break;
+    case Trace::TYPE_ARRAY:
+        scan_array();
+        break;
+    case Trace::TYPE_STRUCT:
+        scan_struct();
+        break;
+    case Trace::TYPE_BLOB:
+        scan_blob();
+        break;
+    case Trace::TYPE_OPAQUE:
+        scan_opaque();
+        break;
+    default:
+        std::cerr << "error: unknown type " << c << "\n";
+        exit(1);
+    case -1:
+        break;
+    }
+}
+
+
+void Parser::scan_sint() {
+    skip_uint();
+}
+
+
+void Parser::scan_uint() {
+    skip_uint();
+}
+
+
+void Parser::scan_float() {
+    file->skip(sizeof(float));
+}
+
+
+void Parser::scan_double() {
+    file->skip(sizeof(double));
+}
+
+
+void Parser::scan_string() {
+    skip_string();
+}
+
+
+void Parser::scan_enum() {
+    size_t id = read_uint();
+    EnumSig *sig = lookup(enums, id);
+    const File::Offset offset = file->currentOffset();
+    if (!sig) {
+        sig = new EnumSig;
+        sig->id = id;
+        sig->name = read_string();
+        Value *value = parse_value();
+        sig->value = value->toSInt();
+        delete value;
+        enums[id] = sig;
+        m_enumSigOffsets.insert(offset);
+    }
+    assert(sig);
+}
+
+
+void Parser::scan_bitmask() {
+    size_t id = read_uint();
+    BitmaskSig *sig = lookup(bitmasks, id);
+    const File::Offset offset = file->currentOffset();
+    if (!sig) {
+        sig = new BitmaskSig;
+        sig->id = id;
+        sig->num_flags = read_uint();
+        BitmaskFlag *flags = new BitmaskFlag[sig->num_flags];
+        for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) {
+            it->name = read_string();
+            it->value = read_uint();
+            if (it->value == 0 && it != flags) {
+                std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n";
+            }
+        }
+        sig->flags = flags;
+        bitmasks[id] = sig;
+        m_bitmaskSigOffsets.insert(offset);
+    }
+    assert(sig);
+
+    skip_uint(); /* value */
+}
+
+
+void Parser::scan_array(void) {
+    size_t len = read_uint();
+    for (size_t i = 0; i < len; ++i) {
+        scan_value();
+    }
+}
+
+
+void Parser::scan_blob(void) {
+    size_t size = read_uint();
+    if (size) {
+        file->skip((unsigned)size);
+    }
+}
+
+
+void Parser::scan_struct() {
+    size_t id = read_uint();
+
+    StructSig *sig = lookup(structs, id);
+    const File::Offset offset = file->currentOffset();
+    if (!sig) {
+        sig = new StructSig;
+        sig->id = id;
+        sig->name = read_string();
+        sig->num_members = read_uint();
+        const char **member_names = new const char *[sig->num_members];
+        for (unsigned i = 0; i < sig->num_members; ++i) {
+            member_names[i] = read_string();
+        }
+        sig->member_names = member_names;
+        structs[id] = sig;
+        m_structSigOffsets.insert(offset);
+    }
+    assert(sig);
+
+    for (size_t i = 0; i < sig->num_members; ++i) {
+        scan_value();
+    }
+}
+
+
+void Parser::scan_opaque() {
+    skip_uint();
+}
+
+
+void Parser::skip_string(void) {
+    size_t len = read_uint();
+    file->skip((unsigned)len);
+}
+
+
+void Parser::skip_uint(void) {
+    int c;
+    do {
+        c = file->getc();
+        if (c == -1) {
+            break;
+        }
+    } while(c & 0x80);
+}
+
+
+inline void Parser::skip_byte(void) {
+    file->skip(1);
+}
+
+
 } /* namespace Trace */
index 4fff9ad1157129e0da8458f8cca87e68687197ec..15b0ccb9b03f0964b5ce1c5418488e23bfb5afe7 100644 (file)
 
 #include <iostream>
 #include <list>
+#include <set>
 
+#include "trace_file.hpp"
 #include "trace_format.hpp"
 #include "trace_model.hpp"
 
 
 namespace Trace {
 
-class File;
-
 class Parser
 {
 protected:
@@ -58,6 +58,17 @@ protected:
     typedef std::vector<BitmaskSig *> BitmaskMap;
     BitmaskMap bitmasks;
 
+    typedef std::set<File::Offset> TraceOffsets;
+    TraceOffsets m_callSigOffsets;
+    TraceOffsets m_structSigOffsets;
+    TraceOffsets m_enumSigOffsets;
+    TraceOffsets m_bitmaskSigOffsets;
+
+    typedef std::map<File::Offset, unsigned> CallNumOffsets;
+    CallNumOffsets m_callNumOffsets;
+
+    bool m_supportsSeeking;
+
     unsigned next_call_no;
 
 public:
@@ -73,6 +84,43 @@ public:
 
     Call *parse_call(void);
 
+    bool supportsOffsets() const
+    {
+        return file->supportsOffsets();
+    }
+
+    File::Offset currentOffset()
+    {
+        return file->currentOffset();
+    }
+
+    void setCurrentOffset(const File::Offset &offset)
+    {
+        file->setCurrentOffset(offset);
+    }
+
+    bool callWithSignature(const File::Offset &offset) const;
+    bool structWithSignature(const File::Offset &offset) const;
+    bool enumWithSignature(const File::Offset &offset) const;
+    bool bitmaskWithSignature(const File::Offset &offset) const;
+
+    unsigned currentCallNumber() const
+    {
+        return next_call_no;
+    }
+
+    void setCurrentCallNumber(unsigned num)
+    {
+        next_call_no = num;
+    }
+
+    int percentRead()
+    {
+        return file->percentRead();
+    }
+
+    Call *scan_call();
+
 protected:
     void parse_enter(void);
 
@@ -111,6 +159,45 @@ protected:
     unsigned long long read_uint(void);
 
     inline int read_byte(void);
+
+protected:
+    void scan_enter(void);
+
+    Call *scan_leave(void);
+
+    bool scan_call_details(Call *call);
+
+    void scan_arg(Call *call);
+
+    void scan_value(void);
+
+    void scan_sint();
+
+    void scan_uint();
+
+    void scan_float();
+
+    void scan_double();
+
+    void scan_string();
+
+    void scan_enum();
+
+    void scan_bitmask();
+
+    void scan_array(void);
+
+    void scan_blob(void);
+
+    void scan_struct();
+
+    void scan_opaque();
+
+    void skip_string(void);
+
+    void skip_uint(void);
+
+    inline void skip_byte(void);
 };
 
 
index 6a60441aaada5015c8a41a8c35eb92fa50f4a9d3..4dbe42dc364264a8db0e717a1af17681b9af271e 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <snappy.h>
 
+#include <iostream>
+
 #include <assert.h>
 #include <string.h>
 
@@ -91,6 +93,10 @@ bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
 
     //read in the initial buffer if we're reading
     if (m_stream.is_open() && mode == File::Read) {
+        m_stream.seekg(0, std::ios::end);
+        m_endPos = m_stream.tellg();
+        m_stream.seekg(0, std::ios::beg);
+
         // read the snappy file identifier
         unsigned char byte1, byte2;
         m_stream >> byte1;
@@ -209,9 +215,10 @@ void SnappyFile::flushWriteCache()
     assert(m_cachePtr == m_cache);
 }
 
-void SnappyFile::flushReadCache()
+void SnappyFile::flushReadCache(size_t skipLength)
 {
     //assert(m_cachePtr == m_cache + m_cacheSize);
+    m_currentOffset.chunk = m_stream.tellg();
     size_t compressedLength;
     compressedLength = readCompressedLength();
 
@@ -220,8 +227,10 @@ void SnappyFile::flushReadCache()
         ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
                                         &m_cacheSize);
         createCache(m_cacheSize);
-        ::snappy::RawUncompress(m_compressedCache, compressedLength,
-                                m_cache);
+        if (skipLength < m_cacheSize) {
+            ::snappy::RawUncompress(m_compressedCache, compressedLength,
+                                    m_cache);
+        }
     } else {
         createCache(0);
     }
@@ -271,3 +280,59 @@ size_t SnappyFile::readCompressedLength()
     }
     return length;
 }
+
+bool SnappyFile::supportsOffsets() const
+{
+    return true;
+}
+
+File::Offset SnappyFile::currentOffset()
+{
+    m_currentOffset.offsetInChunk = m_cachePtr - m_cache;
+    return m_currentOffset;
+}
+
+void SnappyFile::setCurrentOffset(const File::Offset &offset)
+{
+    // to remove eof bit
+    m_stream.clear();
+    // seek to the start of a chunk
+    m_stream.seekg(offset.chunk, std::ios::beg);
+    // load the chunk
+    flushReadCache();
+    assert(m_cacheSize >= offset.offsetInChunk);
+    // seek within our cache to the correct location within the chunk
+    m_cachePtr = m_cache + offset.offsetInChunk;
+
+}
+
+bool SnappyFile::rawSkip(size_t length)
+{
+    if (endOfData()) {
+        return false;
+    }
+
+    if (freeCacheSize() >= length) {
+        m_cachePtr += length;
+    } else {
+        size_t sizeToRead = length;
+        while (sizeToRead) {
+            size_t chunkSize = std::min(freeCacheSize(), sizeToRead);
+            m_cachePtr += chunkSize;
+            sizeToRead -= chunkSize;
+            if (sizeToRead > 0) {
+                flushReadCache(sizeToRead);
+            }
+            if (!m_cacheSize) {
+                break;
+            }
+        }
+    }
+
+    return true;
+}
+
+int SnappyFile::rawPercentRead()
+{
+    return 100 * (double(m_stream.tellg()) / double(m_endPos));
+}
index b807bfbdee51e693171830535e1a6efdb2fa6ea4..33159ec73cc81eb4413158de707940a2c64c5211 100644 (file)
@@ -52,6 +52,9 @@ public:
                File::Mode mode = File::Read);
     virtual ~SnappyFile();
 
+    virtual bool supportsOffsets() const;
+    virtual File::Offset currentOffset();
+    virtual void setCurrentOffset(const File::Offset &offset);
 protected:
     virtual bool rawOpen(const std::string &filename, File::Mode mode);
     virtual bool rawWrite(const void *buffer, size_t length);
@@ -59,6 +62,8 @@ protected:
     virtual int rawGetc();
     virtual void rawClose();
     virtual void rawFlush();
+    virtual bool rawSkip(size_t length);
+    virtual int rawPercentRead();
 
 private:
     inline size_t usedCacheSize() const
@@ -80,7 +85,7 @@ private:
         return m_stream.eof() && freeCacheSize() == 0;
     }
     void flushWriteCache();
-    void flushReadCache();
+    void flushReadCache(size_t skipLength = 0);
     void createCache(size_t size);
     void writeCompressedLength(size_t length);
     size_t readCompressedLength();
@@ -91,6 +96,9 @@ private:
     size_t m_cacheSize;
 
     char *m_compressedCache;
+
+    File::Offset m_currentOffset;
+    std::streampos m_endPos;
 };
 
 }