blob: d970c16fe311d99511875a52f452a7064497da00 [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();
Zack Rusin081e59d2011-09-21 00:25:03 -040031 qDeleteAll(m_signatures);
32 qDeleteAll(m_enumSignatures);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040033}
34
35void TraceLoader::loadTrace(const QString &filename)
36{
37 if (m_helpHash.isEmpty()) {
38 loadHelpFile();
39 }
40
41 if (!m_parser.open(filename.toLatin1())) {
42 qDebug() << "error: failed to open " << filename;
43 return;
44 }
Zack Rusinebf971e2011-09-06 17:44:43 -040045 qDebug()<<"load trace with "<<filename;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040046 emit startedParsing();
47
Zack Rusinebf971e2011-09-06 17:44:43 -040048 qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040049 if (m_parser.supportsOffsets()) {
Zack Rusinac92a212011-09-06 18:25:34 -040050 scanTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040051 } else {
Zack Rusinac92a212011-09-06 18:25:34 -040052 //Load the entire file into memory
53 parseTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040054 }
55
56 emit finishedParsing();
57}
58
Zack Rusin3176ebe2011-09-06 21:11:36 -040059void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040060{
Zack Rusin8f98c3a2011-09-11 18:21:29 -040061 fetchFrameContents(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040062}
63
64void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
65{
66 m_frameMarker = marker;
67}
68
69bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
70{
71 std::string name = call->name();
72
73 switch (m_frameMarker) {
74 case ApiTrace::FrameMarker_SwapBuffers:
Zack Rusinac92a212011-09-06 18:25:34 -040075 return name.find("SwapBuffers") != std::string::npos ||
76 name == "CGLFlushDrawable" ||
77 name == "glFrameTerminatorGREMEDY";
78 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040079 case ApiTrace::FrameMarker_Flush:
Zack Rusinac92a212011-09-06 18:25:34 -040080 return name == "glFlush";
81 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040082 case ApiTrace::FrameMarker_Finish:
Zack Rusinac92a212011-09-06 18:25:34 -040083 return name == "glFinish";
84 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040085 case ApiTrace::FrameMarker_Clear:
Zack Rusinac92a212011-09-06 18:25:34 -040086 return name == "glClear";
87 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040088 }
89 return false;
90}
91
92int TraceLoader::numberOfFrames() const
93{
José Fonseca61e61f72011-09-11 16:53:34 +010094 return m_frameBookmarks.size();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040095}
96
97int TraceLoader::numberOfCallsInFrame(int frameIdx) const
98{
José Fonseca61e61f72011-09-11 16:53:34 +010099 if (frameIdx > m_frameBookmarks.size()) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400100 return 0;
101 }
José Fonseca61e61f72011-09-11 16:53:34 +0100102 FrameBookmarks::const_iterator itr =
103 m_frameBookmarks.find(frameIdx);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400104 return itr->numberOfCalls;
105}
106
107void TraceLoader::loadHelpFile()
108{
Zack Rusinac92a212011-09-06 18:25:34 -0400109 QFile file(":/resources/glreference.tsv");
110 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
111 QString line;
112 while (!file.atEnd()) {
113 line = file.readLine();
114 QString function = line.section('\t', 0, 0).trimmed();
115 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
116 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
117 m_helpHash.insert(function, url);
118 }
119 } else {
120 qWarning() << "Couldn't open reference file "
121 << file.fileName();
122 }
123 file.close();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400124}
125
126void TraceLoader::scanTrace()
127{
Zack Rusinac92a212011-09-06 18:25:34 -0400128 QList<ApiTraceFrame*> frames;
129 ApiTraceFrame *currentFrame = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400130
Zack Rusinac92a212011-09-06 18:25:34 -0400131 Trace::Call *call;
José Fonseca61e61f72011-09-11 16:53:34 +0100132 Trace::ParseBookmark startBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400133 int numOfFrames = 0;
134 int numOfCalls = 0;
Zack Rusinac92a212011-09-06 18:25:34 -0400135 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400136
José Fonseca61e61f72011-09-11 16:53:34 +0100137 m_parser.getBookmark(startBookmark);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400138
Zack Rusinac92a212011-09-06 18:25:34 -0400139 while ((call = m_parser.scan_call())) {
140 ++numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400141
Zack Rusinac92a212011-09-06 18:25:34 -0400142 if (isCallAFrameMarker(call)) {
José Fonseca61e61f72011-09-11 16:53:34 +0100143 FrameBookmark frameBookmark(startBookmark);
144 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400145
Zack Rusinac92a212011-09-06 18:25:34 -0400146 currentFrame = new ApiTraceFrame();
147 currentFrame->number = numOfFrames;
148 currentFrame->setNumChildren(numOfCalls);
Zack Rusin851d0b02011-09-14 22:04:07 -0400149 currentFrame->setLastCallIndex(call->no);
Zack Rusinac92a212011-09-06 18:25:34 -0400150 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400151
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400152 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100153 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400154 ++numOfFrames;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400155
Zack Rusinac92a212011-09-06 18:25:34 -0400156 if (m_parser.percentRead() - lastPercentReport >= 5) {
157 emit parsed(m_parser.percentRead());
158 lastPercentReport = m_parser.percentRead();
159 }
José Fonseca61e61f72011-09-11 16:53:34 +0100160 m_parser.getBookmark(startBookmark);
Zack Rusinac92a212011-09-06 18:25:34 -0400161 numOfCalls = 0;
162 }
Zack Rusinac92a212011-09-06 18:25:34 -0400163 delete call;
164 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400165
Zack Rusinac92a212011-09-06 18:25:34 -0400166 if (numOfCalls) {
José Fonseca61e61f72011-09-11 16:53:34 +0100167 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
168 FrameBookmark frameBookmark(startBookmark);
169 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400170
Zack Rusinac92a212011-09-06 18:25:34 -0400171 currentFrame = new ApiTraceFrame();
172 currentFrame->number = numOfFrames;
173 currentFrame->setNumChildren(numOfCalls);
174 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400175
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400176 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100177 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400178 ++numOfFrames;
179 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400180
Zack Rusinac92a212011-09-06 18:25:34 -0400181 emit parsed(100);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400182
Zack Rusinac92a212011-09-06 18:25:34 -0400183 emit framesLoaded(frames);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400184}
185
186void TraceLoader::parseTrace()
187{
Zack Rusinac92a212011-09-06 18:25:34 -0400188 QList<ApiTraceFrame*> frames;
189 ApiTraceFrame *currentFrame = 0;
190 int frameCount = 0;
191 QVector<ApiTraceCall*> calls;
192 quint64 binaryDataSize = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400193
Zack Rusinac92a212011-09-06 18:25:34 -0400194 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400195
Zack Rusinac92a212011-09-06 18:25:34 -0400196 Trace::Call *call = m_parser.parse_call();
197 while (call) {
198 //std::cout << *call;
199 if (!currentFrame) {
200 currentFrame = new ApiTraceFrame();
201 currentFrame->number = frameCount;
202 ++frameCount;
203 }
204 ApiTraceCall *apiCall =
205 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
206 calls.append(apiCall);
207 if (apiCall->hasBinaryData()) {
208 QByteArray data =
209 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
210 binaryDataSize += data.size();
211 }
212 if (ApiTrace::isCallAFrameMarker(apiCall,
213 m_frameMarker)) {
214 calls.squeeze();
215 currentFrame->setCalls(calls, binaryDataSize);
216 calls.clear();
217 frames.append(currentFrame);
218 currentFrame = 0;
219 binaryDataSize = 0;
220 if (frames.count() >= FRAMES_TO_CACHE) {
221 emit framesLoaded(frames);
222 frames.clear();
223 }
224 if (m_parser.percentRead() - lastPercentReport >= 5) {
225 emit parsed(m_parser.percentRead());
226 lastPercentReport = m_parser.percentRead();
227 }
228 }
229 delete call;
230 call = m_parser.parse_call();
231 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400232
Zack Rusinac92a212011-09-06 18:25:34 -0400233 //last frames won't have markers
234 // it's just a bunch of Delete calls for every object
235 // after the last SwapBuffers
236 if (currentFrame) {
237 calls.squeeze();
238 currentFrame->setCalls(calls, binaryDataSize);
239 frames.append(currentFrame);
240 currentFrame = 0;
241 }
242 if (frames.count()) {
243 emit framesLoaded(frames);
244 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400245}
246
247
Zack Rusinebf971e2011-09-06 17:44:43 -0400248ApiTraceCallSignature * TraceLoader::signature(unsigned id)
249{
250 if (id >= m_signatures.count()) {
251 m_signatures.resize(id + 1);
252 return NULL;
253 } else {
254 return m_signatures[id];
255 }
256}
257
258void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
259{
260 m_signatures[id] = signature;
261}
262
263ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
264{
265 if (id >= m_enumSignatures.count()) {
266 m_enumSignatures.resize(id + 1);
267 return NULL;
268 } else {
269 return m_enumSignatures[id];
270 }
271}
272
273void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
274{
275 m_enumSignatures[id] = signature;
276}
277
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400278void TraceLoader::searchNext(int startFrame,
279 const QString &str,
280 Qt::CaseSensitivity sensitivity)
281{
282 Q_ASSERT(m_parser.supportsOffsets());
283 if (m_parser.supportsOffsets()) {
284 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
285 m_parser.setBookmark(frameBookmark.start);
286 Trace::Call *call = 0;
287 while ((call = m_parser.parse_call())) {
288
289 if (callContains(call, str, sensitivity)) {
290 unsigned frameIdx = callInFrame(call->no);
291 ApiTraceFrame *frame = m_createdFrames[frameIdx];
292 const QVector<ApiTraceCall*> calls =
293 fetchFrameContents(frame);
294 for (int i = 0; i < calls.count(); ++i) {
295 if (calls[i]->index() == call->no) {
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400296 emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400297 break;
298 }
299 }
300 delete call;
301 return;
302 }
303
304 delete call;
305 }
306 }
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400307 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400308}
309
310void TraceLoader::searchPrev(int startFrame,
311 const QString &str,
312 Qt::CaseSensitivity sensitivity)
313{
Zack Rusin121e3162011-09-13 01:35:12 -0400314 Q_ASSERT(m_parser.supportsOffsets());
315 if (m_parser.supportsOffsets()) {
316 Trace::Call *call = 0;
317 QList<Trace::Call*> frameCalls;
318 int frameIdx = startFrame;
319
320 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
321 int numCallsToParse = frameBookmark.numberOfCalls;
322 m_parser.setBookmark(frameBookmark.start);
323
324 while ((call = m_parser.parse_call())) {
325
326 frameCalls.append(call);
327 --numCallsToParse;
328
329 if (numCallsToParse == 0) {
330 bool foundCall = searchCallsBackwards(frameCalls,
331 frameIdx,
332 str, sensitivity);
333
334 qDeleteAll(frameCalls);
335 frameCalls.clear();
336 if (foundCall) {
337 return;
338 }
339
340 --frameIdx;
341
342 if (frameIdx >= 0) {
343 const FrameBookmark &frameBookmark =
344 m_frameBookmarks[frameIdx];
345 m_parser.setBookmark(frameBookmark.start);
346 numCallsToParse = frameBookmark.numberOfCalls;
347 }
348 }
349 }
350 }
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400351 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
Zack Rusin121e3162011-09-13 01:35:12 -0400352}
353
354bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
355 int frameIdx,
356 const QString &str,
357 Qt::CaseSensitivity sensitivity)
358{
359 for (int i = calls.count() - 1; i >= 0; --i) {
360 Trace::Call *call = calls[i];
361 if (callContains(call, str, sensitivity)) {
362 ApiTraceFrame *frame = m_createdFrames[frameIdx];
363 const QVector<ApiTraceCall*> apiCalls =
364 fetchFrameContents(frame);
365 for (int i = 0; i < apiCalls.count(); ++i) {
366 if (apiCalls[i]->index() == call->no) {
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400367 emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
Zack Rusin121e3162011-09-13 01:35:12 -0400368 break;
369 }
370 }
371 return true;
372 }
373 }
374 return false;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400375}
376
377int TraceLoader::callInFrame(int callIdx) const
378{
379 unsigned numCalls = 0;
380
381 for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
382 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
383 unsigned firstCall = numCalls;
384 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
385 if (firstCall <= callIdx && endCall > callIdx) {
386 return frameIdx;
387 }
388 numCalls = endCall;
389 }
390 Q_ASSERT(!"call not in the trace");
391 return 0;
392}
393
394bool TraceLoader::callContains(Trace::Call *call,
395 const QString &str,
396 Qt::CaseSensitivity sensitivity)
397{
398 /*
399 * FIXME: do string comparison directly on Trace::Call
400 */
401 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
402 0, this);
403 bool result = apiCall->contains(str, sensitivity);
404 delete apiCall;
405 return result;
406}
407
408QVector<ApiTraceCall*>
409TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
410{
411 Q_ASSERT(currentFrame);
Zack Rusin99f84fa2011-09-19 23:44:25 -0400412
Zack Rusin447f4a52011-09-19 23:45:39 -0400413 if (currentFrame->isLoaded()) {
Zack Rusin99f84fa2011-09-19 23:44:25 -0400414 return currentFrame->calls();
415 }
416
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400417 if (m_parser.supportsOffsets()) {
418 unsigned frameIdx = currentFrame->number;
419 int numOfCalls = numberOfCallsInFrame(frameIdx);
420
421 if (numOfCalls) {
422 quint64 binaryDataSize = 0;
423 QVector<ApiTraceCall*> calls(numOfCalls);
424 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
425
426 m_parser.setBookmark(frameBookmark.start);
427
428 Trace::Call *call;
429 int parsedCalls = 0;
430 while ((call = m_parser.parse_call())) {
431 ApiTraceCall *apiCall =
432 apiCallFromTraceCall(call, m_helpHash,
433 currentFrame, this);
434 calls[parsedCalls] = apiCall;
435 Q_ASSERT(calls[parsedCalls]);
436 if (apiCall->hasBinaryData()) {
437 QByteArray data =
438 apiCall->arguments()[
439 apiCall->binaryDataIndex()].toByteArray();
440 binaryDataSize += data.size();
441 }
442
443 ++parsedCalls;
444
445 delete call;
446
447 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
448 break;
449 }
450
451 }
452 assert(parsedCalls == numOfCalls);
453 Q_ASSERT(parsedCalls == calls.size());
454 calls.squeeze();
455
456 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
457 emit frameContentsLoaded(currentFrame,
458 calls, binaryDataSize);
459 return calls;
460 }
461 }
462 return QVector<ApiTraceCall*>();
463}
464
Zack Rusin93e4d152011-09-13 02:23:39 -0400465void TraceLoader::findFrameStart(ApiTraceFrame *frame)
466{
Zack Rusin99f84fa2011-09-19 23:44:25 -0400467 if (!frame->isLoaded()) {
468 loadFrame(frame);
469 }
Zack Rusin93e4d152011-09-13 02:23:39 -0400470 emit foundFrameStart(frame);
471}
472
473void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
474{
Zack Rusin99f84fa2011-09-19 23:44:25 -0400475 if (!frame->isLoaded()) {
476 loadFrame(frame);
477 }
Zack Rusin93e4d152011-09-13 02:23:39 -0400478 emit foundFrameEnd(frame);
479}
480
Zack Rusinda7579b2011-09-13 17:33:05 -0400481void TraceLoader::findCallIndex(int index)
482{
483 int frameIdx = callInFrame(index);
484 ApiTraceFrame *frame = m_createdFrames[frameIdx];
485 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
486 QVector<ApiTraceCall*>::const_iterator itr;
487 ApiTraceCall *call = 0;
488 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
489 if ((*itr)->index() == index) {
490 call = *itr;
491 }
492 }
493 Q_ASSERT(call);
494 emit foundCallIndex(call);
495}
496
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400497#include "traceloader.moc"