Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtGui>
43#include <QtDebug>
44
45#include <private/qpaintengineex_p.h>
46#include <private/qpaintbuffer_p.h>
47
48class ReplayWidget : public QWidget
49{
50 Q_OBJECT
51public:
52 ReplayWidget(const QString &filename, int from, int to, bool single, int frame);
53
54 void paintEvent(QPaintEvent *event);
55 void resizeEvent(QResizeEvent *event);
56
57public slots:
58 void updateRect();
59
60public:
61 QList<QRegion> updates;
62 QPaintBuffer buffer;
63
64 int currentFrame;
65 int currentIteration;
66 QTime timer;
67
68 QList<uint> visibleUpdates;
69
70 QVector<uint> iterationTimes;
71 QString filename;
72
73 int from;
74 int to;
75
76 bool single;
77
78 int frame;
79 int currentCommand;
80};
81
82void ReplayWidget::updateRect()
83{
84 if (frame >= 0 && !updates.isEmpty())
85 update(updates.at(frame));
86 else if (!visibleUpdates.isEmpty())
87 update(updates.at(visibleUpdates.at(currentFrame)));
88}
89
90const int singleFrameRepeatsPerCommand = 100;
91const int singleFrameIterations = 4;
92
93void ReplayWidget::paintEvent(QPaintEvent *)
94{
95 QPainter p(this);
96
97 QTimer::singleShot(0, this, SLOT(updateRect()));
98
99// p.setClipRegion(frames.at(currentFrame).updateRegion);
100
101 if (frame >= 0) {
102 int start = buffer.frameStartIndex(frame);
103 int end = buffer.frameEndIndex(frame);
104
105 iterationTimes.resize(end - start);
106
107 int saveRestoreStackDepth = buffer.processCommands(&p, start, start + currentCommand);
108
109 for (int i = 0; i < saveRestoreStackDepth; ++i)
110 p.restore();
111
112 const int repeats = currentIteration >= 3 ? singleFrameRepeatsPerCommand : 1;
113
114 ++currentFrame;
115 if (currentFrame == repeats) {
116 currentFrame = 0;
117 if (currentIteration >= 3) {
118 iterationTimes[currentCommand - 1] = qMin(iterationTimes[currentCommand - 1], uint(timer.elapsed()));
119 timer.restart();
120 }
121
122 if (currentIteration >= singleFrameIterations + 3) {
123 printf(" # | ms | description\n");
124 printf("------+---------+------------------------------------------------------------\n");
125
126 qSort(iterationTimes);
127
128 int sum = 0;
129 for (int i = 0; i < iterationTimes.size(); ++i) {
130 int delta = iterationTimes.at(i);
131 if (i > 0)
132 delta -= iterationTimes.at(i-1);
133 sum += delta;
134 qreal deltaF = delta / qreal(repeats);
135 printf("%.5d | %.5f | %s\n", i, deltaF, qPrintable(buffer.commandDescription(start + i)));
136 }
137 printf("Total | %.5f | Total frame time\n", sum / qreal(repeats));
138 deleteLater();
139 return;
140 }
141
142 if (start + currentCommand >= end) {
143 currentCommand = 1;
144 ++currentIteration;
145 if (currentIteration == 3) {
146 timer.start();
147 iterationTimes.fill(uint(-1));
148 }
149 if (currentIteration >= 3 && currentIteration < singleFrameIterations + 3)
150 printf("Profiling iteration %d of %d\n", currentIteration - 2, singleFrameIterations);
151 } else {
152 ++currentCommand;
153 }
154 }
155
156 return;
157 }
158
159 buffer.draw(&p, visibleUpdates.at(currentFrame));
160
161 ++currentFrame;
162 if (currentFrame >= visibleUpdates.size()) {
163 currentFrame = 0;
164 ++currentIteration;
165
166 if (single) {
167 deleteLater();
168 return;
169 }
170
171 if (currentIteration == 3)
172 timer.start();
173 else if (currentIteration > 3) {
174 iterationTimes << timer.elapsed();
175 timer.restart();
176
177 if (iterationTimes.size() >= 3) {
178 qreal mean = 0;
179 qreal stddev = 0;
180 uint min = INT_MAX;
181
182 for (int i = 0; i < iterationTimes.size(); ++i) {
183 mean += iterationTimes.at(i);
184 min = qMin(min, iterationTimes.at(i));
185 }
186
187 mean /= qreal(iterationTimes.size());
188
189 for (int i = 0; i < iterationTimes.size(); ++i) {
190 qreal delta = iterationTimes.at(i) - mean;
191 stddev += delta * delta;
192 }
193
194 stddev = qSqrt(stddev / iterationTimes.size());
195
196 qSort(iterationTimes.begin(), iterationTimes.end());
197 uint median = iterationTimes.at(iterationTimes.size() / 2);
198
199 stddev = 100 * stddev / mean;
200
201 if (iterationTimes.size() >= 10 || stddev < 4) {
202 printf("%s, iterations: %d, frames: %d, min(ms): %d, median(ms): %d, stddev: %f %%, max(fps): %f\n", qPrintable(filename),
203 iterationTimes.size(), visibleUpdates.size(), min, median, stddev, 1000. * visibleUpdates.size() / min);
204 deleteLater();
205 return;
206 }
207 }
208 }
209 }
210}
211
212void ReplayWidget::resizeEvent(QResizeEvent *)
213{
214 visibleUpdates.clear();
215
216 QRect bounds = rect();
217
218 int first = qMax(0, from);
219 int last = qMin(unsigned(to), unsigned(updates.size()));
220 for (int i = first; i < last; ++i) {
221 if (updates.at(i).intersects(bounds))
222 visibleUpdates << i;
223 }
224
225 int range = last - first;
226
227 if (visibleUpdates.size() != range)
228 printf("Warning: skipped %d frames due to limited resolution\n", range - visibleUpdates.size());
229
230}
231
232ReplayWidget::ReplayWidget(const QString &filename_, int from_, int to_, bool single_, int frame_)
233 : currentFrame(0)
234 , currentIteration(0)
235 , filename(filename_)
236 , from(from_)
237 , to(to_)
238 , single(single_)
239 , frame(frame_)
240 , currentCommand(1)
241{
242 setWindowTitle(filename);
243 QFile file(filename);
244
245 if (!file.open(QIODevice::ReadOnly)) {
246 printf("Failed to load input file '%s'\n", qPrintable(filename_));
247 return;
248 }
249
250 QDataStream in(&file);
251
252 char *data;
253 uint size;
254 in.readBytes(data, size);
255 bool isTraceFile = size >= 7 && qstrncmp(data, "qttrace", 7) == 0;
256
257 uint version = 0;
258 if (size == 9 && qstrncmp(data, "qttraceV2", 9) == 0) {
259 in.setFloatingPointPrecision(QDataStream::SinglePrecision);
260 in >> version;
261 }
262
263 if (!isTraceFile) {
264 printf("File '%s' is not a trace file\n", qPrintable(filename_));
265 return;
266 }
267
268 in >> buffer >> updates;
269 printf("Read paint buffer version %d with %d frames\n", version, buffer.numFrames());
270
271 resize(buffer.boundingRect().size().toSize());
272
273 setAutoFillBackground(false);
274 setAttribute(Qt::WA_NoSystemBackground);
275
276 QTimer::singleShot(10, this, SLOT(updateRect()));
277}
278
279int main(int argc, char **argv)
280{
281 QApplication app(argc, argv);
282
283 if (argc <= 1 || qstrcmp(argv[1], "-h") == 0 || qstrcmp(argv[1], "--help") == 0) {
284 printf("Replays a tracefile generated with '-graphicssystem trace'\n");
285 printf("Usage:\n > %s [OPTIONS] [traceFile]\n", argv[0]);
286 printf("OPTIONS\n"
287 " --range=from-to to specify a frame range.\n"
288 " --singlerun to do only one run (without statistics)\n"
289 " --instrumentframe=frame to instrument a single frame\n");
290 return 1;
291 }
292
293 QFile file(app.arguments().last());
294 if (!file.exists()) {
295 printf("%s does not exist\n", qPrintable(app.arguments().last()));
296 return 1;
297 }
298
299 bool single = false;
300
301 int frame = -1;
302
303 int from = 0;
304 int to = -1;
305 for (int i = 1; i < app.arguments().size() - 1; ++i) {
306 QString arg = app.arguments().at(i);
307 if (arg.startsWith(QLatin1String("--range="))) {
308 QString rest = arg.mid(8);
309 QStringList components = rest.split(QLatin1Char('-'));
310
311 bool ok1 = false;
312 bool ok2 = false;
313 int fromCandidate = 0;
314 int toCandidate = 0;
315 if (components.size() == 2) {
316 fromCandidate = components.first().toInt(&ok1);
317 toCandidate = components.last().toInt(&ok2);
318 }
319
320 if (ok1 && ok2) {
321 from = fromCandidate;
322 to = toCandidate;
323 } else {
324 printf("ERROR: malformed syntax in argument %s\n", qPrintable(arg));
325 }
326 } else if (arg == QLatin1String("--singlerun")) {
327 single = true;
328 } else if (arg.startsWith(QLatin1String("--instrumentframe="))) {
329 QString rest = arg.mid(18);
330 bool ok = false;
331 int frameCandidate = rest.toInt(&ok);
332 if (ok) {
333 frame = frameCandidate;
334 } else {
335 printf("ERROR: malformed syntax in argument %s\n", qPrintable(arg));
336 }
337 } else {
338 printf("Unrecognized argument: %s\n", qPrintable(arg));
339 return 1;
340 }
341 }
342
343 ReplayWidget *widget = new ReplayWidget(app.arguments().last(), from, to, single, frame);
344
345 if (!widget->updates.isEmpty()) {
346 widget->show();
347 return app.exec();
348 }
349
350}
351#include "main.moc"
352

Warning: That file was not part of the compilation database. It may have many parsing errors.