From f389ae8b54b138848a099b82d6103e006dbbd9e6 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sun, 10 Apr 2011 19:27:28 -0400 Subject: [PATCH] Replay and parse json in a thread. --- gui/apitracecall.h | 1 + gui/main.cpp | 1 + gui/mainwindow.cpp | 60 +++++++------ gui/mainwindow.h | 11 +-- gui/retracer.cpp | 207 +++++++++++++++++++++++++++++++++++---------- gui/retracer.h | 62 +++++++++++++- 6 files changed, 261 insertions(+), 81 deletions(-) diff --git a/gui/apitracecall.h b/gui/apitracecall.h index 94bd234..dd69b0e 100644 --- a/gui/apitracecall.h +++ b/gui/apitracecall.h @@ -118,6 +118,7 @@ private: QStringList m_shaderSources; QList m_textures; }; +Q_DECLARE_METATYPE(ApiTraceState); class ApiTraceEvent { diff --git a/gui/main.cpp b/gui/main.cpp index bee35d3..3f8cfa6 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -13,6 +13,7 @@ int main(int argc, char **argv) QApplication app(argc, argv); qRegisterMetaType >(); + qRegisterMetaType(); MainWindow window; window.show(); diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index b19a559..4fc1362 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -12,8 +12,6 @@ #include "ui_retracerdialog.h" #include "vertexdatainterpreter.h" -#include - #include #include #include @@ -32,8 +30,7 @@ MainWindow::MainWindow() : QMainWindow(), m_selectedEvent(0), - m_stateEvent(0), - m_jsonParser(new QJson::Parser()) + m_stateEvent(0) { m_ui.setupUi(this); initObjects(); @@ -140,7 +137,7 @@ void MainWindow::replayStart() void MainWindow::replayStop() { - m_retracer->terminate(); + m_retracer->quit(); m_ui.actionStop->setEnabled(false); m_ui.actionReplay->setEnabled(true); m_ui.actionLookupState->setEnabled(true); @@ -164,20 +161,19 @@ void MainWindow::newTraceFile(const QString &fileName) } } -void MainWindow::replayFinished(const QByteArray &output) +void MainWindow::replayFinished(const QString &output) { m_ui.actionStop->setEnabled(false); m_ui.actionReplay->setEnabled(true); m_ui.actionLookupState->setEnabled(true); - if (m_retracer->captureState()) { - bool ok = false; - QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap(); - parseState(parsedJson); - } else if (output.length() < 80) { + m_progressBar->hide(); + if (output.length() < 80) { statusBar()->showMessage(output); } m_stateEvent = 0; + statusBar()->showMessage( + tr("Replaying finished!"), 2000); } void MainWindow::replayError(const QString &message) @@ -187,6 +183,9 @@ void MainWindow::replayError(const QString &message) m_ui.actionLookupState->setEnabled(true); m_stateEvent = 0; + m_progressBar->hide(); + statusBar()->showMessage( + tr("Replaying unsuccessful."), 2000); QMessageBox::warning( this, tr("Replay Failed"), message); } @@ -223,7 +222,8 @@ void MainWindow::replayTrace(bool dumpState) if (m_selectedEvent->type() == ApiTraceEvent::Call) { index = static_cast(m_selectedEvent)->index; } else if (m_selectedEvent->type() == ApiTraceEvent::Frame) { - ApiTraceFrame *frame = static_cast(m_selectedEvent); + ApiTraceFrame *frame = + static_cast(m_selectedEvent); if (frame->calls.isEmpty()) { //XXX i guess we could still get the current state qDebug()<<"tried to get a state for an empty frame"; @@ -239,6 +239,13 @@ void MainWindow::replayTrace(bool dumpState) m_retracer->start(); m_ui.actionStop->setEnabled(true); + m_progressBar->show(); + if (dumpState) + statusBar()->showMessage( + tr("Looking up the state...")); + else + statusBar()->showMessage( + tr("Replaying the trace file...")); } void MainWindow::lookupState() @@ -255,18 +262,6 @@ void MainWindow::lookupState() MainWindow::~MainWindow() { - delete m_jsonParser; -} - -void MainWindow::parseState(const QVariantMap &parsedJson) -{ - m_stateEvent->setState(ApiTraceState(parsedJson)); - m_model->stateSetOnEvent(m_stateEvent); - if (m_selectedEvent == m_stateEvent) { - fillStateForFrame(); - } else { - m_ui.stateDock->hide(); - } } static void @@ -469,10 +464,12 @@ void MainWindow::initConnections() connect(m_trace, SIGNAL(finishedLoadingTrace()), this, SLOT(finishedLoadingTrace())); - connect(m_retracer, SIGNAL(finished(const QByteArray&)), - this, SLOT(replayFinished(const QByteArray&))); + connect(m_retracer, SIGNAL(finished(const QString&)), + this, SLOT(replayFinished(const QString&))); connect(m_retracer, SIGNAL(error(const QString&)), this, SLOT(replayError(const QString&))); + connect(m_retracer, SIGNAL(foundState(const ApiTraceState&)), + this, SLOT(replayStateFound(const ApiTraceState&))); connect(m_ui.vertexInterpretButton, SIGNAL(clicked()), m_vdataInterpreter, SLOT(interpretData())); @@ -516,4 +513,15 @@ void MainWindow::initConnections() this, SLOT(openHelp(const QUrl&))); } +void MainWindow::replayStateFound(const ApiTraceState &state) +{ + m_stateEvent->setState(state); + m_model->stateSetOnEvent(m_stateEvent); + if (m_selectedEvent == m_stateEvent) { + fillStateForFrame(); + } else { + m_ui.stateDock->hide(); + } +} + #include "mainwindow.moc" diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 55326bf..313180a 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -11,6 +11,7 @@ class ApiTraceEvent; class ApiTraceFilter; class ApiTraceFrame; class ApiTraceModel; +class ApiTraceState; class ImageViewer; class QLineEdit; class QModelIndex; @@ -20,10 +21,6 @@ class Retracer; class ShadersSourceWidget; class VertexDataInterpreter; -namespace QJson { - class Parser; -} - class MainWindow : public QMainWindow { Q_OBJECT @@ -40,7 +37,8 @@ private slots: void filterTrace(); void replayStart(); void replayStop(); - void replayFinished(const QByteArray &output); + void replayFinished(const QString &output); + void replayStateFound(const ApiTraceState &state); void replayError(const QString &msg); void startedLoadingTrace(); void finishedLoadingTrace(); @@ -55,7 +53,6 @@ private: void initConnections(); void newTraceFile(const QString &fileName); void replayTrace(bool dumpState); - void parseState(const QVariantMap ¶ms); void fillStateForFrame(); private: @@ -75,8 +72,6 @@ private: ApiTraceEvent *m_stateEvent; - QJson::Parser *m_jsonParser; - Retracer *m_retracer; VertexDataInterpreter *m_vdataInterpreter; diff --git a/gui/retracer.cpp b/gui/retracer.cpp index b9d74b6..8f35087 100644 --- a/gui/retracer.cpp +++ b/gui/retracer.cpp @@ -1,15 +1,31 @@ #include "retracer.h" +#include "apitracecall.h" + #include +#include + +#include Retracer::Retracer(QObject *parent) - : QObject(parent), + : QThread(parent), m_benchmarking(true), m_doubleBuffered(true), m_captureState(false), - m_captureCall(0), - m_process(0) + m_captureCall(0) { +#ifdef Q_OS_WIN + QString format = QLatin1String("%1;"); +#else + QString format = QLatin1String("%1:"); +#endif + QString buildPath = format.arg(BUILD_DIR); + m_processEnvironment = QProcessEnvironment::systemEnvironment(); + m_processEnvironment.insert("PATH", buildPath + + m_processEnvironment.value("PATH")); + + qputenv("PATH", + m_processEnvironment.value("PATH").toLatin1()); } QString Retracer::fileName() const @@ -42,31 +58,65 @@ void Retracer::setDoubleBuffered(bool db) m_doubleBuffered = db; } -void Retracer::start() +void Retracer::setCaptureAtCallNumber(qlonglong num) { - if (!m_process) { -#ifdef Q_OS_WIN - QString format = QLatin1String("%1;"); -#else - QString format = QLatin1String("%1:"); -#endif - QString buildPath = format.arg(BUILD_DIR); - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("PATH", buildPath + env.value("PATH")); + m_captureCall = num; +} + +qlonglong Retracer::captureAtCallNumber() const +{ + return m_captureCall; +} + +bool Retracer::captureState() const +{ + return m_captureState; +} + +void Retracer::setCaptureState(bool enable) +{ + m_captureState = enable; +} + - qputenv("PATH", env.value("PATH").toLatin1()); +void Retracer::run() +{ + RetraceProcess *retrace = new RetraceProcess(); + retrace->process()->setProcessEnvironment(m_processEnvironment); + + retrace->setFileName(m_fileName); + retrace->setBenchmarking(m_benchmarking); + retrace->setDoubleBuffered(m_doubleBuffered); + retrace->setCaptureState(m_captureState); + retrace->setCaptureAtCallNumber(m_captureCall); + + connect(retrace, SIGNAL(finished(const QString&)), + this, SLOT(cleanup())); + connect(retrace, SIGNAL(error(const QString&)), + this, SLOT(cleanup())); + connect(retrace, SIGNAL(finished(const QString&)), + this, SIGNAL(finished(const QString&))); + connect(retrace, SIGNAL(error(const QString&)), + this, SIGNAL(error(const QString&))); + connect(retrace, SIGNAL(foundState(const ApiTraceState&)), + this, SIGNAL(foundState(const ApiTraceState&))); + + retrace->start(); - m_process = new QProcess(this); - m_process->setProcessEnvironment(env); + exec(); - connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(replayFinished())); - connect(m_process, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(replayError(QProcess::ProcessError))); + /* means we need to kill the process */ + if (retrace->process()->state() != QProcess::NotRunning) { + retrace->terminate(); } - QStringList arguments; + delete retrace; +} + +void RetraceProcess::start() +{ + QStringList arguments; if (m_captureState) { arguments << QLatin1String("-D"); arguments << QString::number(m_captureCall); @@ -84,53 +134,124 @@ void Retracer::start() m_process->start(QLatin1String("glretrace"), arguments); } -void Retracer::terminate() + +void RetraceProcess::replayFinished() { - if (m_process) { - m_process->terminate(); + QByteArray output = m_process->readAllStandardOutput(); + QString msg; + +#if 0 + qDebug()<<"Process finished = "; + qDebug()<<"\terr = "<readAllStandardError(); + qDebug()<<"\tout = "<parse(output, &ok).toMap(); + ApiTraceState state(parsedJson); + emit foundState(state); + msg = tr("State fetched."); + } else { + msg = QString::fromUtf8(output); } + + emit finished(msg); } -void Retracer::setCaptureAtCallNumber(qlonglong num) +void RetraceProcess::replayError(QProcess::ProcessError err) +{ + qDebug()<<"Process error = "<readAllStandardOutput(); - -#if 0 - qDebug()<<"Process finished = "; - qDebug()<<"\terr = "<readAllStandardError(); - qDebug()<<"\tout = "<terminate(); + emit finished(tr("Process terminated.")); + } } -void Retracer::replayError(QProcess::ProcessError err) +void Retracer::cleanup() { - qDebug()<<"Process error = "< +#include #include -class Retracer : public QObject +class ApiTraceState; +namespace QJson { + class Parser; +} + +/* internal class used by the retracer to run + * in the thread */ +class RetraceProcess : public QObject { Q_OBJECT public: - Retracer(QObject *parent=0); + RetraceProcess(QObject *parent=0); + ~RetraceProcess(); + + QProcess *process() const; QString fileName() const; void setFileName(const QString &name); @@ -30,12 +40,14 @@ public slots: void terminate(); signals: - void finished(const QByteArray &output); + void finished(const QString &output); void error(const QString &msg); + void foundState(const ApiTraceState &state); private slots: void replayFinished(); void replayError(QProcess::ProcessError err); + private: QString m_fileName; bool m_benchmarking; @@ -44,6 +56,48 @@ private: qlonglong m_captureCall; QProcess *m_process; + QJson::Parser *m_jsonParser; +}; + +class Retracer : public QThread +{ + Q_OBJECT +public: + Retracer(QObject *parent=0); + + QString fileName() const; + void setFileName(const QString &name); + + bool isBenchmarking() const; + void setBenchmarking(bool bench); + + bool isDoubleBuffered() const; + void setDoubleBuffered(bool db); + + void setCaptureAtCallNumber(qlonglong num); + qlonglong captureAtCallNumber() const; + + bool captureState() const; + void setCaptureState(bool enable); + +signals: + void finished(const QString &output); + void foundState(const ApiTraceState &state); + void error(const QString &msg); + +protected: + virtual void run(); + +private slots: + void cleanup(); +private: + QString m_fileName; + bool m_benchmarking; + bool m_doubleBuffered; + bool m_captureState; + qlonglong m_captureCall; + + QProcessEnvironment m_processEnvironment; }; #endif -- 2.43.0