]> git.cworth.org Git - apitrace/blob - gui/traceloader.cpp
Delete loadertest and cleanup some of the new api.
[apitrace] / gui / traceloader.cpp
1 #include "traceloader.h"
2
3 #include "apitrace.h"
4 #include <QDebug>
5 #include <QFile>
6
7 #define FRAMES_TO_CACHE 100
8
9 static ApiTraceCall *
10 apiCallFromTraceCall(const Trace::Call *call,
11                      const QHash<QString, QUrl> &helpHash,
12                      ApiTraceFrame *frame,
13                      TraceLoader *loader)
14 {
15     ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
16
17     apiCall->setHelpUrl(helpHash.value(apiCall->name()));
18
19     return apiCall;
20 }
21
22 TraceLoader::TraceLoader(QObject *parent)
23     : QObject(parent),
24       m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
25 {
26 }
27
28 TraceLoader::~TraceLoader()
29 {
30     m_parser.close();
31 }
32
33 void 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     }
43     qDebug()<<"load trace with "<<filename;
44     emit startedParsing();
45
46     qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
47     if (m_parser.supportsOffsets()) {
48         scanTrace();
49     } else {
50         //Load the entire file into memory
51         parseTrace();
52     }
53
54     emit finishedParsing();
55 }
56
57 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
58 {
59     fetchFrameContents(currentFrame);
60 }
61
62 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
63 {
64     m_frameMarker = marker;
65 }
66
67 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
68 {
69     std::string name = call->name();
70
71     switch (m_frameMarker) {
72     case ApiTrace::FrameMarker_SwapBuffers:
73         return  name.find("SwapBuffers") != std::string::npos ||
74                 name == "CGLFlushDrawable" ||
75                 name == "glFrameTerminatorGREMEDY";
76         break;
77     case ApiTrace::FrameMarker_Flush:
78         return name == "glFlush";
79         break;
80     case ApiTrace::FrameMarker_Finish:
81         return name == "glFinish";
82         break;
83     case ApiTrace::FrameMarker_Clear:
84         return name == "glClear";
85         break;
86     }
87     return false;
88 }
89
90 int TraceLoader::numberOfFrames() const
91 {
92     return m_frameBookmarks.size();
93 }
94
95 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
96 {
97     if (frameIdx > m_frameBookmarks.size()) {
98         return 0;
99     }
100     FrameBookmarks::const_iterator itr =
101             m_frameBookmarks.find(frameIdx);
102     return itr->numberOfCalls;
103 }
104
105 void TraceLoader::loadHelpFile()
106 {
107     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();
122 }
123
124 void TraceLoader::scanTrace()
125 {
126     QList<ApiTraceFrame*> frames;
127     ApiTraceFrame *currentFrame = 0;
128
129     Trace::Call *call;
130     Trace::ParseBookmark startBookmark;
131     int numOfFrames = 0;
132     int numOfCalls = 0;
133     int lastPercentReport = 0;
134
135     m_parser.getBookmark(startBookmark);
136
137     while ((call = m_parser.scan_call())) {
138         ++numOfCalls;
139
140         if (isCallAFrameMarker(call)) {
141             FrameBookmark frameBookmark(startBookmark);
142             frameBookmark.numberOfCalls = numOfCalls;
143
144             currentFrame = new ApiTraceFrame();
145             currentFrame->number = numOfFrames;
146             currentFrame->setNumChildren(numOfCalls);
147             currentFrame->setLastCallIndex(call->no);
148             frames.append(currentFrame);
149
150             m_createdFrames.append(currentFrame);
151             m_frameBookmarks[numOfFrames] = frameBookmark;
152             ++numOfFrames;
153
154             if (m_parser.percentRead() - lastPercentReport >= 5) {
155                 emit parsed(m_parser.percentRead());
156                 lastPercentReport = m_parser.percentRead();
157             }
158             m_parser.getBookmark(startBookmark);
159             numOfCalls = 0;
160         }
161         delete call;
162     }
163
164     if (numOfCalls) {
165         //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
166         FrameBookmark frameBookmark(startBookmark);
167         frameBookmark.numberOfCalls = numOfCalls;
168
169         currentFrame = new ApiTraceFrame();
170         currentFrame->number = numOfFrames;
171         currentFrame->setNumChildren(numOfCalls);
172         frames.append(currentFrame);
173
174         m_createdFrames.append(currentFrame);
175         m_frameBookmarks[numOfFrames] = frameBookmark;
176         ++numOfFrames;
177     }
178
179     emit parsed(100);
180
181     emit framesLoaded(frames);
182 }
183
184 void TraceLoader::parseTrace()
185 {
186     QList<ApiTraceFrame*> frames;
187     ApiTraceFrame *currentFrame = 0;
188     int frameCount = 0;
189     QVector<ApiTraceCall*> calls;
190     quint64 binaryDataSize = 0;
191
192     int lastPercentReport = 0;
193
194     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     }
230
231     //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     }
243 }
244
245
246 ApiTraceCallSignature * 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
256 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
257 {
258     m_signatures[id] = signature;
259 }
260
261 ApiTraceEnumSignature * 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
271 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
272 {
273     m_enumSignatures[id] = signature;
274 }
275
276 void 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::SearchResult_Found, calls[i]);
295                         break;
296                     }
297                 }
298                 delete call;
299                 return;
300             }
301
302             delete call;
303         }
304     }
305     emit searchResult(ApiTrace::SearchResult_NotFound, 0);
306 }
307
308 void TraceLoader::searchPrev(int startFrame,
309                              const QString &str,
310                              Qt::CaseSensitivity sensitivity)
311 {
312     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::SearchResult_NotFound, 0);
350 }
351
352 bool 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::SearchResult_Found, apiCalls[i]);
366                     break;
367                 }
368             }
369             return true;
370         }
371     }
372     return false;
373 }
374
375 int 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
392 bool 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
406 QVector<ApiTraceCall*>
407 TraceLoader::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
458 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
459 {
460     loadFrame(frame);
461     emit foundFrameStart(frame);
462 }
463
464 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
465 {
466     loadFrame(frame);
467     emit foundFrameEnd(frame);
468 }
469
470 void 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
486 #include "traceloader.moc"