blob: 17ac14d7d8d13a97da4f2e1a61455770e9b1104d [file] [log] [blame]
Zack Rusin3acde362011-04-06 01:11:55 -04001#include "retracer.h"
2
Zack Rusinf389ae82011-04-10 19:27:28 -04003#include "apitracecall.h"
4
Zack Rusin3acde362011-04-06 01:11:55 -04005#include <QDebug>
Zack Rusinf389ae82011-04-10 19:27:28 -04006#include <QVariant>
7
8#include <qjson/parser.h>
Zack Rusin3acde362011-04-06 01:11:55 -04009
10Retracer::Retracer(QObject *parent)
Zack Rusinf389ae82011-04-10 19:27:28 -040011 : QThread(parent),
Zack Rusin404a1ef2011-04-19 23:49:56 -040012 m_benchmarking(false),
Zack Rusin3acde362011-04-06 01:11:55 -040013 m_doubleBuffered(true),
14 m_captureState(false),
Zack Rusinf389ae82011-04-10 19:27:28 -040015 m_captureCall(0)
Zack Rusin3acde362011-04-06 01:11:55 -040016{
Zack Rusinf389ae82011-04-10 19:27:28 -040017#ifdef Q_OS_WIN
18 QString format = QLatin1String("%1;");
19#else
20 QString format = QLatin1String("%1:");
21#endif
José Fonseca27440922011-11-01 08:27:12 +000022 QString buildPath = format.arg(APITRACE_BINARY_DIR);
Zack Rusinf389ae82011-04-10 19:27:28 -040023 m_processEnvironment = QProcessEnvironment::systemEnvironment();
24 m_processEnvironment.insert("PATH", buildPath +
25 m_processEnvironment.value("PATH"));
26
27 qputenv("PATH",
28 m_processEnvironment.value("PATH").toLatin1());
Zack Rusin3acde362011-04-06 01:11:55 -040029}
30
31QString Retracer::fileName() const
32{
33 return m_fileName;
34}
35
36void Retracer::setFileName(const QString &name)
37{
38 m_fileName = name;
39}
40
José Fonseca62997b42011-11-27 15:16:34 +000041void Retracer::setAPI(trace::API api)
42{
43 m_api = api;
44}
45
Zack Rusin3acde362011-04-06 01:11:55 -040046bool Retracer::isBenchmarking() const
47{
48 return m_benchmarking;
49}
50
51void Retracer::setBenchmarking(bool bench)
52{
53 m_benchmarking = bench;
54}
55
56bool Retracer::isDoubleBuffered() const
57{
58 return m_doubleBuffered;
59}
60
61void Retracer::setDoubleBuffered(bool db)
62{
63 m_doubleBuffered = db;
64}
65
Zack Rusin3acde362011-04-06 01:11:55 -040066void Retracer::setCaptureAtCallNumber(qlonglong num)
67{
68 m_captureCall = num;
69}
70
71qlonglong Retracer::captureAtCallNumber() const
72{
73 return m_captureCall;
74}
75
76bool Retracer::captureState() const
77{
78 return m_captureState;
79}
80
81void Retracer::setCaptureState(bool enable)
82{
83 m_captureState = enable;
84}
85
Zack Rusinf389ae82011-04-10 19:27:28 -040086
87void Retracer::run()
88{
89 RetraceProcess *retrace = new RetraceProcess();
90 retrace->process()->setProcessEnvironment(m_processEnvironment);
91
92 retrace->setFileName(m_fileName);
José Fonseca62997b42011-11-27 15:16:34 +000093 retrace->setAPI(m_api);
Zack Rusinf389ae82011-04-10 19:27:28 -040094 retrace->setBenchmarking(m_benchmarking);
95 retrace->setDoubleBuffered(m_doubleBuffered);
96 retrace->setCaptureState(m_captureState);
97 retrace->setCaptureAtCallNumber(m_captureCall);
98
99 connect(retrace, SIGNAL(finished(const QString&)),
100 this, SLOT(cleanup()));
101 connect(retrace, SIGNAL(error(const QString&)),
102 this, SLOT(cleanup()));
103 connect(retrace, SIGNAL(finished(const QString&)),
104 this, SIGNAL(finished(const QString&)));
105 connect(retrace, SIGNAL(error(const QString&)),
106 this, SIGNAL(error(const QString&)));
Zack Rusined40bc62011-08-28 17:11:02 -0400107 connect(retrace, SIGNAL(foundState(ApiTraceState*)),
108 this, SIGNAL(foundState(ApiTraceState*)));
Zack Rusin10fd4772011-09-14 01:45:12 -0400109 connect(retrace, SIGNAL(retraceErrors(const QList<ApiTraceError>&)),
110 this, SIGNAL(retraceErrors(const QList<ApiTraceError>&)));
Zack Rusinf389ae82011-04-10 19:27:28 -0400111
112 retrace->start();
113
114 exec();
115
116 /* means we need to kill the process */
117 if (retrace->process()->state() != QProcess::NotRunning) {
118 retrace->terminate();
119 }
120
121 delete retrace;
122}
123
124
125void RetraceProcess::start()
126{
José Fonseca62997b42011-11-27 15:16:34 +0000127 QString prog;
Zack Rusinf389ae82011-04-10 19:27:28 -0400128 QStringList arguments;
Zack Rusin16ae0362011-04-11 21:30:04 -0400129
José Fonseca62997b42011-11-27 15:16:34 +0000130 if (m_api == trace::API_GL) {
131 prog = QLatin1String("glretrace");
132 } else if (m_api == trace::API_EGL) {
133 prog = QLatin1String("eglretrace");
134 } else {
135 assert(0);
136 return;
137 }
138
Zack Rusin16ae0362011-04-11 21:30:04 -0400139 if (m_doubleBuffered) {
140 arguments << QLatin1String("-db");
José Fonseca1872d962011-06-01 19:49:13 +0100141 } else {
142 arguments << QLatin1String("-sb");
Zack Rusin16ae0362011-04-11 21:30:04 -0400143 }
144
Zack Rusinf389ae82011-04-10 19:27:28 -0400145 if (m_captureState) {
146 arguments << QLatin1String("-D");
147 arguments << QString::number(m_captureCall);
148 } else {
149 if (m_benchmarking) {
150 arguments << QLatin1String("-b");
151 }
Zack Rusinf389ae82011-04-10 19:27:28 -0400152 }
153
154 arguments << m_fileName;
155
José Fonseca62997b42011-11-27 15:16:34 +0000156 m_process->start(prog, arguments);
Zack Rusinf389ae82011-04-10 19:27:28 -0400157}
158
159
José Fonseca56cd8ac2011-11-24 16:30:49 +0000160void RetraceProcess::replayFinished(int exitCode, QProcess::ExitStatus exitStatus)
Zack Rusin3acde362011-04-06 01:11:55 -0400161{
162 QByteArray output = m_process->readAllStandardOutput();
Zack Rusinf389ae82011-04-10 19:27:28 -0400163 QString msg;
Zack Rusinb39e1c62011-04-19 23:09:26 -0400164 QString errStr = m_process->readAllStandardError();
Zack Rusin3acde362011-04-06 01:11:55 -0400165
166#if 0
167 qDebug()<<"Process finished = ";
Zack Rusinb39e1c62011-04-19 23:09:26 -0400168 qDebug()<<"\terr = "<<errStr;
Zack Rusin3acde362011-04-06 01:11:55 -0400169 qDebug()<<"\tout = "<<output;
170#endif
José Fonseca56cd8ac2011-11-24 16:30:49 +0000171
172 if (exitStatus != QProcess::NormalExit) {
173 msg = QLatin1String("Process crashed");
174 } else if (exitCode != 0) {
175 msg = QLatin1String("Process exited with non zero exit code");
Zack Rusinf389ae82011-04-10 19:27:28 -0400176 } else {
José Fonseca56cd8ac2011-11-24 16:30:49 +0000177 if (m_captureState) {
178 bool ok = false;
179 QVariantMap parsedJson = m_jsonParser->parse(output, &ok).toMap();
180 ApiTraceState *state = new ApiTraceState(parsedJson);
181 emit foundState(state);
182 msg = tr("State fetched.");
183 } else {
184 msg = QString::fromUtf8(output);
185 }
Zack Rusinf389ae82011-04-10 19:27:28 -0400186 }
187
Zack Rusinb39e1c62011-04-19 23:09:26 -0400188 QStringList errorLines = errStr.split('\n');
Zack Rusin10fd4772011-09-14 01:45:12 -0400189 QList<ApiTraceError> errors;
Zack Rusinb39e1c62011-04-19 23:09:26 -0400190 QRegExp regexp("(^\\d+): +(\\b\\w+\\b): (.+$)");
191 foreach(QString line, errorLines) {
192 if (regexp.indexIn(line) != -1) {
Zack Rusin10fd4772011-09-14 01:45:12 -0400193 ApiTraceError error;
Zack Rusinb39e1c62011-04-19 23:09:26 -0400194 error.callIndex = regexp.cap(1).toInt();
195 error.type = regexp.cap(2);
196 error.message = regexp.cap(3);
197 errors.append(error);
198 }
199 }
200 if (!errors.isEmpty()) {
201 emit retraceErrors(errors);
202 }
Zack Rusinf389ae82011-04-10 19:27:28 -0400203 emit finished(msg);
Zack Rusin3acde362011-04-06 01:11:55 -0400204}
205
Zack Rusinf389ae82011-04-10 19:27:28 -0400206void RetraceProcess::replayError(QProcess::ProcessError err)
Zack Rusin3acde362011-04-06 01:11:55 -0400207{
José Fonseca56cd8ac2011-11-24 16:30:49 +0000208 /*
209 * XXX: this function is likely unnecessary and should be eliminated given
210 * that replayFinished is always called, even on errors.
211 */
212
213#if 0
Zack Rusin3acde362011-04-06 01:11:55 -0400214 qDebug()<<"Process error = "<<err;
215 qDebug()<<"\terr = "<<m_process->readAllStandardError();
216 qDebug()<<"\tout = "<<m_process->readAllStandardOutput();
José Fonseca56cd8ac2011-11-24 16:30:49 +0000217#endif
Zack Rusin3acde362011-04-06 01:11:55 -0400218
219 emit error(
220 tr("Couldn't execute the replay file '%1'").arg(m_fileName));
221}
222
Zack Rusin10fd4772011-09-14 01:45:12 -0400223Q_DECLARE_METATYPE(QList<ApiTraceError>);
Zack Rusinf389ae82011-04-10 19:27:28 -0400224RetraceProcess::RetraceProcess(QObject *parent)
225 : QObject(parent)
226{
227 m_process = new QProcess(this);
228 m_jsonParser = new QJson::Parser();
229
Zack Rusin10fd4772011-09-14 01:45:12 -0400230 qRegisterMetaType<QList<ApiTraceError> >();
Zack Rusinb39e1c62011-04-19 23:09:26 -0400231
Zack Rusinf389ae82011-04-10 19:27:28 -0400232 connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
José Fonseca56cd8ac2011-11-24 16:30:49 +0000233 this, SLOT(replayFinished(int, QProcess::ExitStatus)));
Zack Rusinf389ae82011-04-10 19:27:28 -0400234 connect(m_process, SIGNAL(error(QProcess::ProcessError)),
235 this, SLOT(replayError(QProcess::ProcessError)));
236}
237
238QProcess * RetraceProcess::process() const
239{
240 return m_process;
241}
242
243QString RetraceProcess::fileName() const
244{
245 return m_fileName;
246}
247
248void RetraceProcess::setFileName(const QString &name)
249{
250 m_fileName = name;
251}
252
José Fonseca62997b42011-11-27 15:16:34 +0000253void RetraceProcess::setAPI(trace::API api)
254{
255 m_api = api;
256}
257
Zack Rusinf389ae82011-04-10 19:27:28 -0400258bool RetraceProcess::isBenchmarking() const
259{
260 return m_benchmarking;
261}
262
263void RetraceProcess::setBenchmarking(bool bench)
264{
265 m_benchmarking = bench;
266}
267
268bool RetraceProcess::isDoubleBuffered() const
269{
270 return m_doubleBuffered;
271}
272
273void RetraceProcess::setDoubleBuffered(bool db)
274{
275 m_doubleBuffered = db;
276}
277
278void RetraceProcess::setCaptureAtCallNumber(qlonglong num)
279{
280 m_captureCall = num;
281}
282
283qlonglong RetraceProcess::captureAtCallNumber() const
284{
285 return m_captureCall;
286}
287
288bool RetraceProcess::captureState() const
289{
290 return m_captureState;
291}
292
293void RetraceProcess::setCaptureState(bool enable)
294{
295 m_captureState = enable;
296}
297
298void RetraceProcess::terminate()
299{
300 if (m_process) {
301 m_process->terminate();
302 emit finished(tr("Process terminated."));
303 }
304}
305
306void Retracer::cleanup()
307{
308 quit();
309}
310
311RetraceProcess::~RetraceProcess()
312{
313 delete m_jsonParser;
314}
315
Zack Rusin3acde362011-04-06 01:11:55 -0400316#include "retracer.moc"