diff options
author | Jose Fonseca <jfonseca@vmware.com> | 2016-01-19 14:16:24 +0000 |
---|---|---|
committer | Jose Fonseca <jfonseca@vmware.com> | 2016-01-22 22:37:46 +0000 |
commit | a20a795cb585b75d4d03d671a9a235ca67d3418d (patch) | |
tree | 18bf67e62ee3b73b98c242badd1b825f7f98697f | |
parent | c4343f12297177d558dc58e2a38921c2ec671f6a (diff) |
gui: Show leaks.
Based on comicfans change, but adapted to invoke `apitrace leaks`.
Issue #416.
v2: Add missing file.
-rw-r--r-- | gui/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gui/leaktracethread.cpp | 82 | ||||
-rw-r--r-- | gui/leaktracethread.h | 35 | ||||
-rw-r--r-- | gui/mainwindow.cpp | 24 | ||||
-rw-r--r-- | gui/mainwindow.h | 2 | ||||
-rw-r--r-- | gui/ui/mainwindow.ui | 9 | ||||
-rwxr-xr-x | scripts/leaks.py | 2 |
7 files changed, 154 insertions, 1 deletions
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index a86336bb..b74e3ece 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -51,6 +51,7 @@ set(qapitrace_SRCS traceprocess.cpp trimprocess.cpp vertexdatainterpreter.cpp + leaktracethread.cpp graphing/frameaxiswidget.cpp graphing/graphwidget.cpp graphing/graphaxiswidget.cpp diff --git a/gui/leaktracethread.cpp b/gui/leaktracethread.cpp new file mode 100644 index 00000000..a5b1e346 --- /dev/null +++ b/gui/leaktracethread.cpp @@ -0,0 +1,82 @@ +#include "leaktracethread.h" + +#include "apitracecall.h" + +#include <QDebug> +#include <QProcess> + +void LeakTraceThread::run() +{ + QString msg = QLatin1String("Replay finished!"); + + /* + * Construct command line + */ + + QString prog = "apitrace"; + QStringList arguments; + arguments << "leaks"; + arguments << filename; + + /* + * Start the process. + */ + + { + QDebug debug(QtDebugMsg); + debug << "Running:"; + debug << prog; + foreach (const QString &argument, arguments) { + debug << argument; + } + } + + QProcess process; + + process.start(prog, arguments, QIODevice::ReadOnly); + if (!process.waitForStarted(-1)) { + return; + } + + /* + * Wait for process termination + */ + + process.waitForFinished(-1); + + if (process.exitStatus() != QProcess::NormalExit) { + msg = QLatin1String("Process crashed"); + } else if (process.exitCode() != 0) { + msg = QLatin1String("Process exited with non zero exit code"); + } + + /* + * Parse errors. + */ + + QList<ApiTraceError> errors; + process.setReadChannel(QProcess::StandardError); + QRegExp regexp("(^\\d+): +(\\b\\w+\\b): ([^\\r\\n]+)[\\r\\n]*$"); + while (!process.atEnd()) { + QString line = process.readLine(); + qDebug() << line; + if (regexp.indexIn(line) != -1) { + qDebug() << "error"; + ApiTraceError error; + error.callIndex = regexp.cap(1).toInt(); + error.type = regexp.cap(2); + error.message = regexp.cap(3); + errors.append(error); + } else { + qDebug() << line; + } + } + + /* + * Emit signals + */ + + error = !errors.empty(); + emit leakTraceErrors(errors); +} + diff --git a/gui/leaktracethread.h b/gui/leaktracethread.h new file mode 100644 index 00000000..cbc16ea0 --- /dev/null +++ b/gui/leaktracethread.h @@ -0,0 +1,35 @@ + +#pragma once + +#include <QThread> +#include <QString> +#include <QList> + +struct ApiTraceError; + +class LeakTraceThread: public QThread{ + + Q_OBJECT + + public: + + LeakTraceThread(QString _filename):filename(_filename){} + + + bool hasError()const {return error;} + signals: + + void leakTraceErrors(const QList<ApiTraceError> &errors); + + protected: + + virtual void run(); + + private: + + QString filename; + + bool error=false; +}; + + diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 8bf464a0..129e634d 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -24,6 +24,7 @@ #include "vertexdatainterpreter.h" #include "trace_profiler.hpp" #include "image/image.hpp" +#include "leaktracethread.h" #include <QAction> #include <QApplication> @@ -864,6 +865,27 @@ void MainWindow::showSettings() dialog.exec(); } +void MainWindow::leakTrace() +{ + LeakTraceThread *t=new LeakTraceThread(m_trace->fileName()); + + connect (t,SIGNAL(finished()),this,SLOT(leakTraceFinished())); + + connect (t,SIGNAL(leakTraceErrors(const QList<ApiTraceError> &)), + this,SLOT(slotRetraceErrors(const QList<ApiTraceError>&))); + + t->start(); +} + +void MainWindow::leakTraceFinished(){ + + LeakTraceThread *t = qobject_cast<LeakTraceThread*>(sender()); + + m_ui.errorsDock->setVisible(t->hasError()); + + delete t; +} + void MainWindow::openHelp(const QUrl &url) { QDesktopServices::openUrl(url); @@ -1082,6 +1104,8 @@ void MainWindow::initConnections() this, SLOT(showThumbnails())); connect(m_ui.actionOptions, SIGNAL(triggered()), this, SLOT(showSettings())); + connect(m_ui.actionLeakTrace,SIGNAL(triggered()), + this, SLOT(leakTrace())); connect(m_ui.callView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(callItemSelected(const QModelIndex &))); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 34f4113e..8740ab76 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -72,6 +72,8 @@ private slots: void showThumbnails(); void trim(); void showSettings(); + void leakTrace(); + void leakTraceFinished(); void openHelp(const QUrl &url); void showSurfacesMenu(const QPoint &pos); void showSelectedSurface(); diff --git a/gui/ui/mainwindow.ui b/gui/ui/mainwindow.ui index 41a7d214..376f70e3 100644 --- a/gui/ui/mainwindow.ui +++ b/gui/ui/mainwindow.ui @@ -92,6 +92,7 @@ <addaction name="actionLookupState"/> <addaction name="actionShowThumbnails"/> <addaction name="actionTrim"/> + <addaction name="actionLeakTrace"/> <addaction name="separator"/> <addaction name="actionOptions"/> </widget> @@ -776,6 +777,14 @@ <string>Retrace on Android</string> </property> </action> + <action name="actionLeakTrace"> + <property name="text"> + <string>&LeakTrace</string> + </property> + <property name="toolTip"> + <string>trace opengl object leaks</string> + </property> + </action> <zorder>stateDock</zorder> <zorder>vertexDataDock</zorder> <zorder>errorsDock</zorder> diff --git a/scripts/leaks.py b/scripts/leaks.py index 71c0123a..6349f84b 100755 --- a/scripts/leaks.py +++ b/scripts/leaks.py @@ -93,7 +93,7 @@ class LeakDetector(unpickle.Unpickler): def dumpLeaks(self, callNo, context): for textureName, textureCallNo in context.textures.iteritems(): - sys.stderr.write('error: call %s: texture %u created in call %u was never destroyed\n' % (callNo, textureName, textureCallNo)) + sys.stderr.write('%u: error: texture %u was not destroyed until %s\n' % (textureCallNo, textureName, callNo)) context.textures.clear() |