1 #include "traceloader.h"
8 #define FRAMES_TO_CACHE 100
11 apiCallFromTraceCall(const trace::Call *call,
12 const QHash<QString, QUrl> &helpHash,
14 ApiTraceCall *parentCall,
17 ApiTraceCall *apiCall;
20 apiCall = new ApiTraceCall(parentCall, loader, call);
22 apiCall = new ApiTraceCall(frame, loader, call);
24 apiCall->setHelpUrl(helpHash.value(apiCall->name()));
29 TraceLoader::TraceLoader(QObject *parent)
34 TraceLoader::~TraceLoader()
37 qDeleteAll(m_signatures);
38 qDeleteAll(m_enumSignatures);
41 void TraceLoader::loadTrace(const QString &filename)
43 if (m_helpHash.isEmpty()) {
47 if (!m_frameBookmarks.isEmpty()) {
48 qDeleteAll(m_signatures);
49 qDeleteAll(m_enumSignatures);
51 m_enumSignatures.clear();
52 m_frameBookmarks.clear();
53 m_createdFrames.clear();
57 if (!m_parser.open(filename.toLatin1())) {
58 qDebug() << "error: failed to open " << filename;
62 emit startedParsing();
64 if (m_parser.supportsOffsets()) {
67 //Load the entire file into memory
70 emit guessedApi(static_cast<int>(m_parser.api));
71 emit finishedParsing();
74 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
76 fetchFrameContents(currentFrame);
79 int TraceLoader::numberOfFrames() const
81 return m_frameBookmarks.size();
84 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
86 if (frameIdx >= m_frameBookmarks.size()) {
89 FrameBookmarks::const_iterator itr =
90 m_frameBookmarks.find(frameIdx);
91 return itr->numberOfCalls;
94 void TraceLoader::loadHelpFile()
96 QFile file(":/resources/glreference.tsv");
97 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
99 while (!file.atEnd()) {
100 line = file.readLine();
101 QString function = line.section('\t', 0, 0).trimmed();
102 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
103 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
104 m_helpHash.insert(function, url);
107 qWarning() << "Couldn't open reference file "
113 void TraceLoader::scanTrace()
115 QList<ApiTraceFrame*> frames;
116 ApiTraceFrame *currentFrame = 0;
119 trace::ParseBookmark startBookmark;
122 int lastPercentReport = 0;
124 m_parser.getBookmark(startBookmark);
126 while ((call = m_parser.scan_call())) {
129 if (call->flags & trace::CALL_FLAG_END_FRAME) {
130 FrameBookmark frameBookmark(startBookmark);
131 frameBookmark.numberOfCalls = numOfCalls;
133 currentFrame = new ApiTraceFrame();
134 currentFrame->number = numOfFrames;
135 currentFrame->setNumChildren(numOfCalls);
136 currentFrame->setLastCallIndex(call->no);
137 frames.append(currentFrame);
139 m_createdFrames.append(currentFrame);
140 m_frameBookmarks[numOfFrames] = frameBookmark;
143 if (m_parser.percentRead() - lastPercentReport >= 5) {
144 emit parsed(m_parser.percentRead());
145 lastPercentReport = m_parser.percentRead();
147 m_parser.getBookmark(startBookmark);
154 //trace::File::Bookmark endBookmark = m_parser.currentBookmark();
155 FrameBookmark frameBookmark(startBookmark);
156 frameBookmark.numberOfCalls = numOfCalls;
158 currentFrame = new ApiTraceFrame();
159 currentFrame->number = numOfFrames;
160 currentFrame->setNumChildren(numOfCalls);
161 frames.append(currentFrame);
163 m_createdFrames.append(currentFrame);
164 m_frameBookmarks[numOfFrames] = frameBookmark;
170 emit framesLoaded(frames);
173 void TraceLoader::parseTrace()
175 QList<ApiTraceFrame*> frames;
176 ApiTraceFrame *currentFrame = 0;
178 QStack<ApiTraceCall*> groups;
179 QVector<ApiTraceCall*> topLevelItems;
180 QVector<ApiTraceCall*> allCalls;
181 quint64 binaryDataSize = 0;
183 int lastPercentReport = 0;
185 trace::Call *call = m_parser.parse_call();
187 //std::cout << *call;
189 currentFrame = new ApiTraceFrame();
190 currentFrame->number = frameCount;
193 ApiTraceCall *apiCall =
194 apiCallFromTraceCall(call, m_helpHash, currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
195 allCalls.append(apiCall);
196 if (groups.count() == 0) {
197 topLevelItems.append(apiCall);
199 if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
200 groups.push(apiCall);
201 } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
202 groups.top()->finishedAddingChildren();
205 if (!groups.isEmpty()) {
206 groups.top()->addChild(apiCall);
208 if (apiCall->hasBinaryData()) {
210 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
211 binaryDataSize += data.size();
213 if (call->flags & trace::CALL_FLAG_END_FRAME) {
215 topLevelItems.squeeze();
216 if (topLevelItems.count() == allCalls.count()) {
217 currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
219 currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
223 topLevelItems.clear();
224 frames.append(currentFrame);
227 if (frames.count() >= FRAMES_TO_CACHE) {
228 emit framesLoaded(frames);
231 if (m_parser.percentRead() - lastPercentReport >= 5) {
232 emit parsed(m_parser.percentRead());
233 lastPercentReport = m_parser.percentRead();
237 call = m_parser.parse_call();
240 //last frames won't have markers
241 // it's just a bunch of Delete calls for every object
242 // after the last SwapBuffers
245 if (topLevelItems.count() == allCalls.count()) {
246 currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
248 currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
250 frames.append(currentFrame);
253 if (frames.count()) {
254 emit framesLoaded(frames);
259 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
261 if (id >= m_signatures.count()) {
262 m_signatures.resize(id + 1);
265 return m_signatures[id];
269 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
271 m_signatures[id] = signature;
274 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
276 if (id >= m_enumSignatures.count()) {
277 m_enumSignatures.resize(id + 1);
280 return m_enumSignatures[id];
284 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
286 m_enumSignatures[id] = signature;
289 void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
291 Q_ASSERT(m_parser.supportsOffsets());
292 if (m_parser.supportsOffsets()) {
293 int startFrame = m_createdFrames.indexOf(request.frame);
294 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
295 m_parser.setBookmark(frameBookmark.start);
296 trace::Call *call = 0;
297 while ((call = m_parser.parse_call())) {
299 if (callContains(call, request.text, request.cs)) {
300 unsigned frameIdx = callInFrame(call->no);
301 ApiTraceFrame *frame = m_createdFrames[frameIdx];
302 const QVector<ApiTraceCall*> calls =
303 fetchFrameContents(frame);
304 for (int i = 0; i < calls.count(); ++i) {
305 if (calls[i]->index() == call->no) {
306 emit searchResult(request, ApiTrace::SearchResult_Found,
318 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
321 void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
323 Q_ASSERT(m_parser.supportsOffsets());
324 if (m_parser.supportsOffsets()) {
325 int startFrame = m_createdFrames.indexOf(request.frame);
326 trace::Call *call = 0;
327 QList<trace::Call*> frameCalls;
328 int frameIdx = startFrame;
330 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
331 int numCallsToParse = frameBookmark.numberOfCalls;
332 m_parser.setBookmark(frameBookmark.start);
334 while ((call = m_parser.parse_call())) {
336 frameCalls.append(call);
339 if (numCallsToParse == 0) {
340 bool foundCall = searchCallsBackwards(frameCalls,
344 qDeleteAll(frameCalls);
353 const FrameBookmark &frameBookmark =
354 m_frameBookmarks[frameIdx];
355 m_parser.setBookmark(frameBookmark.start);
356 numCallsToParse = frameBookmark.numberOfCalls;
361 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
364 bool TraceLoader::searchCallsBackwards(const QList<trace::Call*> &calls,
366 const ApiTrace::SearchRequest &request)
368 for (int i = calls.count() - 1; i >= 0; --i) {
369 trace::Call *call = calls[i];
370 if (callContains(call, request.text, request.cs)) {
371 ApiTraceFrame *frame = m_createdFrames[frameIdx];
372 const QVector<ApiTraceCall*> apiCalls =
373 fetchFrameContents(frame);
374 for (int i = 0; i < apiCalls.count(); ++i) {
375 if (apiCalls[i]->index() == call->no) {
376 emit searchResult(request,
377 ApiTrace::SearchResult_Found,
388 int TraceLoader::callInFrame(int callIdx) const
390 unsigned numCalls = 0;
392 for (int frameIdx = 0; frameIdx < m_frameBookmarks.size(); ++frameIdx) {
393 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
394 unsigned firstCall = numCalls;
395 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
396 if (firstCall <= callIdx && endCall > callIdx) {
401 Q_ASSERT(!"call not in the trace");
405 bool TraceLoader::callContains(trace::Call *call,
407 Qt::CaseSensitivity sensitivity)
410 * FIXME: do string comparison directly on trace::Call
412 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
414 bool result = apiCall->contains(str, sensitivity);
419 QVector<ApiTraceCall*>
420 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
422 Q_ASSERT(currentFrame);
424 if (currentFrame->isLoaded()) {
425 return currentFrame->calls();
428 if (m_parser.supportsOffsets()) {
429 unsigned frameIdx = currentFrame->number;
430 int numOfCalls = numberOfCallsInFrame(frameIdx);
433 quint64 binaryDataSize = 0;
434 QStack<ApiTraceCall*> groups;
435 QVector<ApiTraceCall*> topLevelItems;
436 QVector<ApiTraceCall*> allCalls(numOfCalls);
437 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
439 m_parser.setBookmark(frameBookmark.start);
443 while ((call = m_parser.parse_call())) {
444 ApiTraceCall *apiCall =
445 apiCallFromTraceCall(call, m_helpHash,
446 currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
448 Q_ASSERT(parsedCalls < calls.size());
449 allCalls[parsedCalls++] = apiCall;
450 if (groups.count() == 0) {
451 topLevelItems.append(apiCall);
453 if (!groups.isEmpty()) {
454 groups.top()->addChild(apiCall);
456 if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
457 groups.push(apiCall);
458 } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
459 groups.top()->finishedAddingChildren();
462 if (apiCall->hasBinaryData()) {
464 apiCall->arguments()[
465 apiCall->binaryDataIndex()].toByteArray();
466 binaryDataSize += data.size();
471 if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
476 // There can be fewer parsed calls when call in different
477 // threads cross the frame boundary
478 Q_ASSERT(parsedCalls <= numOfCalls);
479 Q_ASSERT(parsedCalls <= calls.size());
480 allCalls.resize(parsedCalls);
483 Q_ASSERT(parsedCalls <= currentFrame->numChildrenToLoad());
484 if (topLevelItems.count() == allCalls.count()) {
485 emit frameContentsLoaded(currentFrame, allCalls,
486 allCalls, binaryDataSize);
488 emit frameContentsLoaded(currentFrame, topLevelItems,
489 allCalls, binaryDataSize);
494 return QVector<ApiTraceCall*>();
497 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
499 if (!frame->isLoaded()) {
502 emit foundFrameStart(frame);
505 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
507 if (!frame->isLoaded()) {
510 emit foundFrameEnd(frame);
513 void TraceLoader::findCallIndex(int index)
515 int frameIdx = callInFrame(index);
516 ApiTraceFrame *frame = m_createdFrames[frameIdx];
517 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
518 QVector<ApiTraceCall*>::const_iterator itr;
519 ApiTraceCall *call = 0;
520 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
521 if ((*itr)->index() == index) {
526 emit foundCallIndex(call);
530 void TraceLoader::search(const ApiTrace::SearchRequest &request)
532 if (request.direction == ApiTrace::SearchRequest::Next) {
539 #include "traceloader.moc"