blob: 9480f459e015505e79266843e0f2d80ae2568ffb [file] [log] [blame]
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001#include "traceloader.h"
2
Zack Rusin3176ebe2011-09-06 21:11:36 -04003#include "apitrace.h"
Zack Rusin20b1f6d2011-09-06 11:50:07 -04004#include <QDebug>
5#include <QFile>
6
7#define FRAMES_TO_CACHE 100
8
9static ApiTraceCall *
10apiCallFromTraceCall(const Trace::Call *call,
11 const QHash<QString, QUrl> &helpHash,
Zack Rusinebf971e2011-09-06 17:44:43 -040012 ApiTraceFrame *frame,
13 TraceLoader *loader)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040014{
Zack Rusinebf971e2011-09-06 17:44:43 -040015 ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040016
17 apiCall->setHelpUrl(helpHash.value(apiCall->name()));
18
19 return apiCall;
20}
21
Zack Rusinebf971e2011-09-06 17:44:43 -040022TraceLoader::TraceLoader(QObject *parent)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040023 : QObject(parent),
Zack Rusin20b1f6d2011-09-06 11:50:07 -040024 m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
25{
26}
27
28TraceLoader::~TraceLoader()
29{
30 m_parser.close();
31}
32
33void TraceLoader::loadTrace(const QString &filename)
34{
35 if (m_helpHash.isEmpty()) {
36 loadHelpFile();
37 }
38
39 if (!m_parser.open(filename.toLatin1())) {
40 qDebug() << "error: failed to open " << filename;
41 return;
42 }
Zack Rusinebf971e2011-09-06 17:44:43 -040043 qDebug()<<"load trace with "<<filename;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040044 emit startedParsing();
45
Zack Rusinebf971e2011-09-06 17:44:43 -040046 qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040047 if (m_parser.supportsOffsets()) {
Zack Rusinac92a212011-09-06 18:25:34 -040048 scanTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040049 } else {
Zack Rusinac92a212011-09-06 18:25:34 -040050 //Load the entire file into memory
51 parseTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040052 }
53
54 emit finishedParsing();
55}
56
Zack Rusin3176ebe2011-09-06 21:11:36 -040057void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040058{
Zack Rusin8f98c3a2011-09-11 18:21:29 -040059 fetchFrameContents(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040060}
61
62void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
63{
64 m_frameMarker = marker;
65}
66
67bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
68{
69 std::string name = call->name();
70
71 switch (m_frameMarker) {
72 case ApiTrace::FrameMarker_SwapBuffers:
Zack Rusinac92a212011-09-06 18:25:34 -040073 return name.find("SwapBuffers") != std::string::npos ||
74 name == "CGLFlushDrawable" ||
75 name == "glFrameTerminatorGREMEDY";
76 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040077 case ApiTrace::FrameMarker_Flush:
Zack Rusinac92a212011-09-06 18:25:34 -040078 return name == "glFlush";
79 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040080 case ApiTrace::FrameMarker_Finish:
Zack Rusinac92a212011-09-06 18:25:34 -040081 return name == "glFinish";
82 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040083 case ApiTrace::FrameMarker_Clear:
Zack Rusinac92a212011-09-06 18:25:34 -040084 return name == "glClear";
85 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040086 }
87 return false;
88}
89
90int TraceLoader::numberOfFrames() const
91{
José Fonseca61e61f72011-09-11 16:53:34 +010092 return m_frameBookmarks.size();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040093}
94
95int TraceLoader::numberOfCallsInFrame(int frameIdx) const
96{
José Fonseca61e61f72011-09-11 16:53:34 +010097 if (frameIdx > m_frameBookmarks.size()) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -040098 return 0;
99 }
José Fonseca61e61f72011-09-11 16:53:34 +0100100 FrameBookmarks::const_iterator itr =
101 m_frameBookmarks.find(frameIdx);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400102 return itr->numberOfCalls;
103}
104
105void TraceLoader::loadHelpFile()
106{
Zack Rusinac92a212011-09-06 18:25:34 -0400107 QFile file(":/resources/glreference.tsv");
108 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
109 QString line;
110 while (!file.atEnd()) {
111 line = file.readLine();
112 QString function = line.section('\t', 0, 0).trimmed();
113 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
114 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
115 m_helpHash.insert(function, url);
116 }
117 } else {
118 qWarning() << "Couldn't open reference file "
119 << file.fileName();
120 }
121 file.close();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400122}
123
124void TraceLoader::scanTrace()
125{
Zack Rusinac92a212011-09-06 18:25:34 -0400126 QList<ApiTraceFrame*> frames;
127 ApiTraceFrame *currentFrame = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400128
Zack Rusinac92a212011-09-06 18:25:34 -0400129 Trace::Call *call;
José Fonseca61e61f72011-09-11 16:53:34 +0100130 Trace::ParseBookmark startBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400131 int numOfFrames = 0;
132 int numOfCalls = 0;
Zack Rusinac92a212011-09-06 18:25:34 -0400133 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400134
José Fonseca61e61f72011-09-11 16:53:34 +0100135 m_parser.getBookmark(startBookmark);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400136
Zack Rusinac92a212011-09-06 18:25:34 -0400137 while ((call = m_parser.scan_call())) {
138 ++numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400139
Zack Rusinac92a212011-09-06 18:25:34 -0400140 if (isCallAFrameMarker(call)) {
José Fonseca61e61f72011-09-11 16:53:34 +0100141 FrameBookmark frameBookmark(startBookmark);
142 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400143
Zack Rusinac92a212011-09-06 18:25:34 -0400144 currentFrame = new ApiTraceFrame();
145 currentFrame->number = numOfFrames;
146 currentFrame->setNumChildren(numOfCalls);
Zack Rusin851d0b02011-09-14 22:04:07 -0400147 currentFrame->setLastCallIndex(call->no);
Zack Rusinac92a212011-09-06 18:25:34 -0400148 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400149
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400150 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100151 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400152 ++numOfFrames;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400153
Zack Rusinac92a212011-09-06 18:25:34 -0400154 if (m_parser.percentRead() - lastPercentReport >= 5) {
155 emit parsed(m_parser.percentRead());
156 lastPercentReport = m_parser.percentRead();
157 }
José Fonseca61e61f72011-09-11 16:53:34 +0100158 m_parser.getBookmark(startBookmark);
Zack Rusinac92a212011-09-06 18:25:34 -0400159 numOfCalls = 0;
160 }
Zack Rusinac92a212011-09-06 18:25:34 -0400161 delete call;
162 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400163
Zack Rusinac92a212011-09-06 18:25:34 -0400164 if (numOfCalls) {
José Fonseca61e61f72011-09-11 16:53:34 +0100165 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
166 FrameBookmark frameBookmark(startBookmark);
167 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400168
Zack Rusinac92a212011-09-06 18:25:34 -0400169 currentFrame = new ApiTraceFrame();
170 currentFrame->number = numOfFrames;
171 currentFrame->setNumChildren(numOfCalls);
172 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400173
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400174 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100175 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400176 ++numOfFrames;
177 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400178
Zack Rusinac92a212011-09-06 18:25:34 -0400179 emit parsed(100);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400180
Zack Rusinac92a212011-09-06 18:25:34 -0400181 emit framesLoaded(frames);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400182}
183
184void TraceLoader::parseTrace()
185{
Zack Rusinac92a212011-09-06 18:25:34 -0400186 QList<ApiTraceFrame*> frames;
187 ApiTraceFrame *currentFrame = 0;
188 int frameCount = 0;
189 QVector<ApiTraceCall*> calls;
190 quint64 binaryDataSize = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400191
Zack Rusinac92a212011-09-06 18:25:34 -0400192 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400193
Zack Rusinac92a212011-09-06 18:25:34 -0400194 Trace::Call *call = m_parser.parse_call();
195 while (call) {
196 //std::cout << *call;
197 if (!currentFrame) {
198 currentFrame = new ApiTraceFrame();
199 currentFrame->number = frameCount;
200 ++frameCount;
201 }
202 ApiTraceCall *apiCall =
203 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
204 calls.append(apiCall);
205 if (apiCall->hasBinaryData()) {
206 QByteArray data =
207 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
208 binaryDataSize += data.size();
209 }
210 if (ApiTrace::isCallAFrameMarker(apiCall,
211 m_frameMarker)) {
212 calls.squeeze();
213 currentFrame->setCalls(calls, binaryDataSize);
214 calls.clear();
215 frames.append(currentFrame);
216 currentFrame = 0;
217 binaryDataSize = 0;
218 if (frames.count() >= FRAMES_TO_CACHE) {
219 emit framesLoaded(frames);
220 frames.clear();
221 }
222 if (m_parser.percentRead() - lastPercentReport >= 5) {
223 emit parsed(m_parser.percentRead());
224 lastPercentReport = m_parser.percentRead();
225 }
226 }
227 delete call;
228 call = m_parser.parse_call();
229 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400230
Zack Rusinac92a212011-09-06 18:25:34 -0400231 //last frames won't have markers
232 // it's just a bunch of Delete calls for every object
233 // after the last SwapBuffers
234 if (currentFrame) {
235 calls.squeeze();
236 currentFrame->setCalls(calls, binaryDataSize);
237 frames.append(currentFrame);
238 currentFrame = 0;
239 }
240 if (frames.count()) {
241 emit framesLoaded(frames);
242 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400243}
244
245
Zack Rusinebf971e2011-09-06 17:44:43 -0400246ApiTraceCallSignature * TraceLoader::signature(unsigned id)
247{
248 if (id >= m_signatures.count()) {
249 m_signatures.resize(id + 1);
250 return NULL;
251 } else {
252 return m_signatures[id];
253 }
254}
255
256void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
257{
258 m_signatures[id] = signature;
259}
260
261ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
262{
263 if (id >= m_enumSignatures.count()) {
264 m_enumSignatures.resize(id + 1);
265 return NULL;
266 } else {
267 return m_enumSignatures[id];
268 }
269}
270
271void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
272{
273 m_enumSignatures[id] = signature;
274}
275
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400276void TraceLoader::searchNext(int startFrame,
277 const QString &str,
278 Qt::CaseSensitivity sensitivity)
279{
280 Q_ASSERT(m_parser.supportsOffsets());
281 if (m_parser.supportsOffsets()) {
282 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
283 m_parser.setBookmark(frameBookmark.start);
284 Trace::Call *call = 0;
285 while ((call = m_parser.parse_call())) {
286
287 if (callContains(call, str, sensitivity)) {
288 unsigned frameIdx = callInFrame(call->no);
289 ApiTraceFrame *frame = m_createdFrames[frameIdx];
290 const QVector<ApiTraceCall*> calls =
291 fetchFrameContents(frame);
292 for (int i = 0; i < calls.count(); ++i) {
293 if (calls[i]->index() == call->no) {
294 emit searchResult(ApiTrace::SearchFound, calls[i]);
295 break;
296 }
297 }
298 delete call;
299 return;
300 }
301
302 delete call;
303 }
304 }
305 emit searchResult(ApiTrace::SearchNotFound, 0);
306}
307
308void TraceLoader::searchPrev(int startFrame,
309 const QString &str,
310 Qt::CaseSensitivity sensitivity)
311{
Zack Rusin121e3162011-09-13 01:35:12 -0400312 Q_ASSERT(m_parser.supportsOffsets());
313 if (m_parser.supportsOffsets()) {
314 Trace::Call *call = 0;
315 QList<Trace::Call*> frameCalls;
316 int frameIdx = startFrame;
317
318 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
319 int numCallsToParse = frameBookmark.numberOfCalls;
320 m_parser.setBookmark(frameBookmark.start);
321
322 while ((call = m_parser.parse_call())) {
323
324 frameCalls.append(call);
325 --numCallsToParse;
326
327 if (numCallsToParse == 0) {
328 bool foundCall = searchCallsBackwards(frameCalls,
329 frameIdx,
330 str, sensitivity);
331
332 qDeleteAll(frameCalls);
333 frameCalls.clear();
334 if (foundCall) {
335 return;
336 }
337
338 --frameIdx;
339
340 if (frameIdx >= 0) {
341 const FrameBookmark &frameBookmark =
342 m_frameBookmarks[frameIdx];
343 m_parser.setBookmark(frameBookmark.start);
344 numCallsToParse = frameBookmark.numberOfCalls;
345 }
346 }
347 }
348 }
349 emit searchResult(ApiTrace::SearchNotFound, 0);
350}
351
352bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
353 int frameIdx,
354 const QString &str,
355 Qt::CaseSensitivity sensitivity)
356{
357 for (int i = calls.count() - 1; i >= 0; --i) {
358 Trace::Call *call = calls[i];
359 if (callContains(call, str, sensitivity)) {
360 ApiTraceFrame *frame = m_createdFrames[frameIdx];
361 const QVector<ApiTraceCall*> apiCalls =
362 fetchFrameContents(frame);
363 for (int i = 0; i < apiCalls.count(); ++i) {
364 if (apiCalls[i]->index() == call->no) {
365 emit searchResult(ApiTrace::SearchFound, apiCalls[i]);
366 break;
367 }
368 }
369 return true;
370 }
371 }
372 return false;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400373}
374
375int TraceLoader::callInFrame(int callIdx) const
376{
377 unsigned numCalls = 0;
378
379 for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
380 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
381 unsigned firstCall = numCalls;
382 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
383 if (firstCall <= callIdx && endCall > callIdx) {
384 return frameIdx;
385 }
386 numCalls = endCall;
387 }
388 Q_ASSERT(!"call not in the trace");
389 return 0;
390}
391
392bool TraceLoader::callContains(Trace::Call *call,
393 const QString &str,
394 Qt::CaseSensitivity sensitivity)
395{
396 /*
397 * FIXME: do string comparison directly on Trace::Call
398 */
399 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
400 0, this);
401 bool result = apiCall->contains(str, sensitivity);
402 delete apiCall;
403 return result;
404}
405
406QVector<ApiTraceCall*>
407TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
408{
409 Q_ASSERT(currentFrame);
410 if (m_parser.supportsOffsets()) {
411 unsigned frameIdx = currentFrame->number;
412 int numOfCalls = numberOfCallsInFrame(frameIdx);
413
414 if (numOfCalls) {
415 quint64 binaryDataSize = 0;
416 QVector<ApiTraceCall*> calls(numOfCalls);
417 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
418
419 m_parser.setBookmark(frameBookmark.start);
420
421 Trace::Call *call;
422 int parsedCalls = 0;
423 while ((call = m_parser.parse_call())) {
424 ApiTraceCall *apiCall =
425 apiCallFromTraceCall(call, m_helpHash,
426 currentFrame, this);
427 calls[parsedCalls] = apiCall;
428 Q_ASSERT(calls[parsedCalls]);
429 if (apiCall->hasBinaryData()) {
430 QByteArray data =
431 apiCall->arguments()[
432 apiCall->binaryDataIndex()].toByteArray();
433 binaryDataSize += data.size();
434 }
435
436 ++parsedCalls;
437
438 delete call;
439
440 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
441 break;
442 }
443
444 }
445 assert(parsedCalls == numOfCalls);
446 Q_ASSERT(parsedCalls == calls.size());
447 calls.squeeze();
448
449 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
450 emit frameContentsLoaded(currentFrame,
451 calls, binaryDataSize);
452 return calls;
453 }
454 }
455 return QVector<ApiTraceCall*>();
456}
457
Zack Rusin93e4d152011-09-13 02:23:39 -0400458void TraceLoader::findFrameStart(ApiTraceFrame *frame)
459{
460 loadFrame(frame);
461 emit foundFrameStart(frame);
462}
463
464void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
465{
466 loadFrame(frame);
467 emit foundFrameEnd(frame);
468}
469
Zack Rusinda7579b2011-09-13 17:33:05 -0400470void TraceLoader::findCallIndex(int index)
471{
472 int frameIdx = callInFrame(index);
473 ApiTraceFrame *frame = m_createdFrames[frameIdx];
474 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
475 QVector<ApiTraceCall*>::const_iterator itr;
476 ApiTraceCall *call = 0;
477 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
478 if ((*itr)->index() == index) {
479 call = *itr;
480 }
481 }
482 Q_ASSERT(call);
483 emit foundCallIndex(call);
484}
485
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400486#include "traceloader.moc"