summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose Fonseca <jfonseca@vmware.com>2016-01-19 14:16:24 +0000
committerJose Fonseca <jfonseca@vmware.com>2016-01-22 22:37:46 +0000
commita20a795cb585b75d4d03d671a9a235ca67d3418d (patch)
tree18bf67e62ee3b73b98c242badd1b825f7f98697f
parentc4343f12297177d558dc58e2a38921c2ec671f6a (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.txt1
-rw-r--r--gui/leaktracethread.cpp82
-rw-r--r--gui/leaktracethread.h35
-rw-r--r--gui/mainwindow.cpp24
-rw-r--r--gui/mainwindow.h2
-rw-r--r--gui/ui/mainwindow.ui9
-rwxr-xr-xscripts/leaks.py2
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>&amp;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()