blob: 0fee815ff6a811bbac9a58e9099453de6aa71fa5 [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 Rusin59b79552011-09-21 00:37:03 -040045
Zack Rusin20b1f6d2011-09-06 11:50:07 -040046 emit startedParsing();
47
48 if (m_parser.supportsOffsets()) {
Zack Rusinac92a212011-09-06 18:25:34 -040049 scanTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040050 } else {
Zack Rusinac92a212011-09-06 18:25:34 -040051 //Load the entire file into memory
52 parseTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040053 }
54
55 emit finishedParsing();
56}
57
Zack Rusin3176ebe2011-09-06 21:11:36 -040058void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040059{
Zack Rusin8f98c3a2011-09-11 18:21:29 -040060 fetchFrameContents(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040061}
62
63void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
64{
65 m_frameMarker = marker;
66}
67
68bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
69{
70 std::string name = call->name();
71
72 switch (m_frameMarker) {
73 case ApiTrace::FrameMarker_SwapBuffers:
Zack Rusinac92a212011-09-06 18:25:34 -040074 return name.find("SwapBuffers") != std::string::npos ||
75 name == "CGLFlushDrawable" ||
76 name == "glFrameTerminatorGREMEDY";
77 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040078 case ApiTrace::FrameMarker_Flush:
Zack Rusinac92a212011-09-06 18:25:34 -040079 return name == "glFlush";
80 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040081 case ApiTrace::FrameMarker_Finish:
Zack Rusinac92a212011-09-06 18:25:34 -040082 return name == "glFinish";
83 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040084 case ApiTrace::FrameMarker_Clear:
Zack Rusinac92a212011-09-06 18:25:34 -040085 return name == "glClear";
86 break;
Zack Rusin20b1f6d2011-09-06 11:50:07 -040087 }
88 return false;
89}
90
91int TraceLoader::numberOfFrames() const
92{
José Fonseca61e61f72011-09-11 16:53:34 +010093 return m_frameBookmarks.size();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040094}
95
96int TraceLoader::numberOfCallsInFrame(int frameIdx) const
97{
José Fonseca61e61f72011-09-11 16:53:34 +010098 if (frameIdx > m_frameBookmarks.size()) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -040099 return 0;
100 }
José Fonseca61e61f72011-09-11 16:53:34 +0100101 FrameBookmarks::const_iterator itr =
102 m_frameBookmarks.find(frameIdx);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400103 return itr->numberOfCalls;
104}
105
106void TraceLoader::loadHelpFile()
107{
Zack Rusinac92a212011-09-06 18:25:34 -0400108 QFile file(":/resources/glreference.tsv");
109 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
110 QString line;
111 while (!file.atEnd()) {
112 line = file.readLine();
113 QString function = line.section('\t', 0, 0).trimmed();
114 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
115 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
116 m_helpHash.insert(function, url);
117 }
118 } else {
119 qWarning() << "Couldn't open reference file "
120 << file.fileName();
121 }
122 file.close();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400123}
124
125void TraceLoader::scanTrace()
126{
Zack Rusinac92a212011-09-06 18:25:34 -0400127 QList<ApiTraceFrame*> frames;
128 ApiTraceFrame *currentFrame = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400129
Zack Rusinac92a212011-09-06 18:25:34 -0400130 Trace::Call *call;
José Fonseca61e61f72011-09-11 16:53:34 +0100131 Trace::ParseBookmark startBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400132 int numOfFrames = 0;
133 int numOfCalls = 0;
Zack Rusinac92a212011-09-06 18:25:34 -0400134 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400135
José Fonseca61e61f72011-09-11 16:53:34 +0100136 m_parser.getBookmark(startBookmark);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400137
Zack Rusinac92a212011-09-06 18:25:34 -0400138 while ((call = m_parser.scan_call())) {
139 ++numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400140
Zack Rusinac92a212011-09-06 18:25:34 -0400141 if (isCallAFrameMarker(call)) {
José Fonseca61e61f72011-09-11 16:53:34 +0100142 FrameBookmark frameBookmark(startBookmark);
143 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400144
Zack Rusinac92a212011-09-06 18:25:34 -0400145 currentFrame = new ApiTraceFrame();
146 currentFrame->number = numOfFrames;
147 currentFrame->setNumChildren(numOfCalls);
Zack Rusin851d0b02011-09-14 22:04:07 -0400148 currentFrame->setLastCallIndex(call->no);
Zack Rusinac92a212011-09-06 18:25:34 -0400149 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400150
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400151 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100152 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400153 ++numOfFrames;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400154
Zack Rusinac92a212011-09-06 18:25:34 -0400155 if (m_parser.percentRead() - lastPercentReport >= 5) {
156 emit parsed(m_parser.percentRead());
157 lastPercentReport = m_parser.percentRead();
158 }
José Fonseca61e61f72011-09-11 16:53:34 +0100159 m_parser.getBookmark(startBookmark);
Zack Rusinac92a212011-09-06 18:25:34 -0400160 numOfCalls = 0;
161 }
Zack Rusinac92a212011-09-06 18:25:34 -0400162 delete call;
163 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400164
Zack Rusinac92a212011-09-06 18:25:34 -0400165 if (numOfCalls) {
José Fonseca61e61f72011-09-11 16:53:34 +0100166 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
167 FrameBookmark frameBookmark(startBookmark);
168 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400169
Zack Rusinac92a212011-09-06 18:25:34 -0400170 currentFrame = new ApiTraceFrame();
171 currentFrame->number = numOfFrames;
172 currentFrame->setNumChildren(numOfCalls);
173 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400174
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400175 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100176 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400177 ++numOfFrames;
178 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400179
Zack Rusinac92a212011-09-06 18:25:34 -0400180 emit parsed(100);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400181
Zack Rusinac92a212011-09-06 18:25:34 -0400182 emit framesLoaded(frames);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400183}
184
185void TraceLoader::parseTrace()
186{
Zack Rusinac92a212011-09-06 18:25:34 -0400187 QList<ApiTraceFrame*> frames;
188 ApiTraceFrame *currentFrame = 0;
189 int frameCount = 0;
190 QVector<ApiTraceCall*> calls;
191 quint64 binaryDataSize = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400192
Zack Rusinac92a212011-09-06 18:25:34 -0400193 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400194
Zack Rusinac92a212011-09-06 18:25:34 -0400195 Trace::Call *call = m_parser.parse_call();
196 while (call) {
197 //std::cout << *call;
198 if (!currentFrame) {
199 currentFrame = new ApiTraceFrame();
200 currentFrame->number = frameCount;
201 ++frameCount;
202 }
203 ApiTraceCall *apiCall =
204 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
205 calls.append(apiCall);
206 if (apiCall->hasBinaryData()) {
207 QByteArray data =
208 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
209 binaryDataSize += data.size();
210 }
211 if (ApiTrace::isCallAFrameMarker(apiCall,
212 m_frameMarker)) {
213 calls.squeeze();
214 currentFrame->setCalls(calls, binaryDataSize);
215 calls.clear();
216 frames.append(currentFrame);
217 currentFrame = 0;
218 binaryDataSize = 0;
219 if (frames.count() >= FRAMES_TO_CACHE) {
220 emit framesLoaded(frames);
221 frames.clear();
222 }
223 if (m_parser.percentRead() - lastPercentReport >= 5) {
224 emit parsed(m_parser.percentRead());
225 lastPercentReport = m_parser.percentRead();
226 }
227 }
228 delete call;
229 call = m_parser.parse_call();
230 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400231
Zack Rusinac92a212011-09-06 18:25:34 -0400232 //last frames won't have markers
233 // it's just a bunch of Delete calls for every object
234 // after the last SwapBuffers
235 if (currentFrame) {
236 calls.squeeze();
237 currentFrame->setCalls(calls, binaryDataSize);
238 frames.append(currentFrame);
239 currentFrame = 0;
240 }
241 if (frames.count()) {
242 emit framesLoaded(frames);
243 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400244}
245
246
Zack Rusinebf971e2011-09-06 17:44:43 -0400247ApiTraceCallSignature * TraceLoader::signature(unsigned id)
248{
249 if (id >= m_signatures.count()) {
250 m_signatures.resize(id + 1);
251 return NULL;
252 } else {
253 return m_signatures[id];
254 }
255}
256
257void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
258{
259 m_signatures[id] = signature;
260}
261
262ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
263{
264 if (id >= m_enumSignatures.count()) {
265 m_enumSignatures.resize(id + 1);
266 return NULL;
267 } else {
268 return m_enumSignatures[id];
269 }
270}
271
272void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
273{
274 m_enumSignatures[id] = signature;
275}
276
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400277void TraceLoader::searchNext(int startFrame,
278 const QString &str,
279 Qt::CaseSensitivity sensitivity)
280{
281 Q_ASSERT(m_parser.supportsOffsets());
282 if (m_parser.supportsOffsets()) {
283 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
284 m_parser.setBookmark(frameBookmark.start);
285 Trace::Call *call = 0;
286 while ((call = m_parser.parse_call())) {
287
288 if (callContains(call, str, sensitivity)) {
289 unsigned frameIdx = callInFrame(call->no);
290 ApiTraceFrame *frame = m_createdFrames[frameIdx];
291 const QVector<ApiTraceCall*> calls =
292 fetchFrameContents(frame);
293 for (int i = 0; i < calls.count(); ++i) {
294 if (calls[i]->index() == call->no) {
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400295 emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400296 break;
297 }
298 }
299 delete call;
300 return;
301 }
302
303 delete call;
304 }
305 }
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400306 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400307}
308
309void TraceLoader::searchPrev(int startFrame,
310 const QString &str,
311 Qt::CaseSensitivity sensitivity)
312{
Zack Rusin121e3162011-09-13 01:35:12 -0400313 Q_ASSERT(m_parser.supportsOffsets());
314 if (m_parser.supportsOffsets()) {
315 Trace::Call *call = 0;
316 QList<Trace::Call*> frameCalls;
317 int frameIdx = startFrame;
318
319 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
320 int numCallsToParse = frameBookmark.numberOfCalls;
321 m_parser.setBookmark(frameBookmark.start);
322
323 while ((call = m_parser.parse_call())) {
324
325 frameCalls.append(call);
326 --numCallsToParse;
327
328 if (numCallsToParse == 0) {
329 bool foundCall = searchCallsBackwards(frameCalls,
330 frameIdx,
331 str, sensitivity);
332
333 qDeleteAll(frameCalls);
334 frameCalls.clear();
335 if (foundCall) {
336 return;
337 }
338
339 --frameIdx;
340
341 if (frameIdx >= 0) {
342 const FrameBookmark &frameBookmark =
343 m_frameBookmarks[frameIdx];
344 m_parser.setBookmark(frameBookmark.start);
345 numCallsToParse = frameBookmark.numberOfCalls;
346 }
347 }
348 }
349 }
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400350 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
Zack Rusin121e3162011-09-13 01:35:12 -0400351}
352
353bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
354 int frameIdx,
355 const QString &str,
356 Qt::CaseSensitivity sensitivity)
357{
358 for (int i = calls.count() - 1; i >= 0; --i) {
359 Trace::Call *call = calls[i];
360 if (callContains(call, str, sensitivity)) {
361 ApiTraceFrame *frame = m_createdFrames[frameIdx];
362 const QVector<ApiTraceCall*> apiCalls =
363 fetchFrameContents(frame);
364 for (int i = 0; i < apiCalls.count(); ++i) {
365 if (apiCalls[i]->index() == call->no) {
Zack Rusin1a9f7af2011-09-18 19:40:47 -0400366 emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
Zack Rusin121e3162011-09-13 01:35:12 -0400367 break;
368 }
369 }
370 return true;
371 }
372 }
373 return false;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400374}
375
376int TraceLoader::callInFrame(int callIdx) const
377{
378 unsigned numCalls = 0;
379
380 for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
381 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
382 unsigned firstCall = numCalls;
383 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
384 if (firstCall <= callIdx && endCall > callIdx) {
385 return frameIdx;
386 }
387 numCalls = endCall;
388 }
389 Q_ASSERT(!"call not in the trace");
390 return 0;
391}
392
393bool TraceLoader::callContains(Trace::Call *call,
394 const QString &str,
395 Qt::CaseSensitivity sensitivity)
396{
397 /*
398 * FIXME: do string comparison directly on Trace::Call
399 */
400 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
401 0, this);
402 bool result = apiCall->contains(str, sensitivity);
403 delete apiCall;
404 return result;
405}
406
407QVector<ApiTraceCall*>
408TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
409{
410 Q_ASSERT(currentFrame);
Zack Rusin99f84fa2011-09-19 23:44:25 -0400411
Zack Rusin447f4a52011-09-19 23:45:39 -0400412 if (currentFrame->isLoaded()) {
Zack Rusin99f84fa2011-09-19 23:44:25 -0400413 return currentFrame->calls();
414 }
415
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400416 if (m_parser.supportsOffsets()) {
417 unsigned frameIdx = currentFrame->number;
418 int numOfCalls = numberOfCallsInFrame(frameIdx);
419
420 if (numOfCalls) {
421 quint64 binaryDataSize = 0;
422 QVector<ApiTraceCall*> calls(numOfCalls);
423 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
424
425 m_parser.setBookmark(frameBookmark.start);
426
427 Trace::Call *call;
428 int parsedCalls = 0;
429 while ((call = m_parser.parse_call())) {
430 ApiTraceCall *apiCall =
431 apiCallFromTraceCall(call, m_helpHash,
432 currentFrame, this);
433 calls[parsedCalls] = apiCall;
434 Q_ASSERT(calls[parsedCalls]);
435 if (apiCall->hasBinaryData()) {
436 QByteArray data =
437 apiCall->arguments()[
438 apiCall->binaryDataIndex()].toByteArray();
439 binaryDataSize += data.size();
440 }
441
442 ++parsedCalls;
443
444 delete call;
445
446 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
447 break;
448 }
449
450 }
451 assert(parsedCalls == numOfCalls);
452 Q_ASSERT(parsedCalls == calls.size());
453 calls.squeeze();
454
455 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
456 emit frameContentsLoaded(currentFrame,
457 calls, binaryDataSize);
458 return calls;
459 }
460 }
461 return QVector<ApiTraceCall*>();
462}
463
Zack Rusin93e4d152011-09-13 02:23:39 -0400464void TraceLoader::findFrameStart(ApiTraceFrame *frame)
465{
Zack Rusin99f84fa2011-09-19 23:44:25 -0400466 if (!frame->isLoaded()) {
467 loadFrame(frame);
468 }
Zack Rusin93e4d152011-09-13 02:23:39 -0400469 emit foundFrameStart(frame);
470}
471
472void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
473{
Zack Rusin99f84fa2011-09-19 23:44:25 -0400474 if (!frame->isLoaded()) {
475 loadFrame(frame);
476 }
Zack Rusin93e4d152011-09-13 02:23:39 -0400477 emit foundFrameEnd(frame);
478}
479
Zack Rusinda7579b2011-09-13 17:33:05 -0400480void TraceLoader::findCallIndex(int index)
481{
482 int frameIdx = callInFrame(index);
483 ApiTraceFrame *frame = m_createdFrames[frameIdx];
484 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
485 QVector<ApiTraceCall*>::const_iterator itr;
486 ApiTraceCall *call = 0;
487 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
488 if ((*itr)->index() == index) {
489 call = *itr;
490 }
491 }
492 Q_ASSERT(call);
493 emit foundCallIndex(call);
494}
495
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400496#include "traceloader.moc"