1 #include "traceloader.h"
7 #define FRAMES_TO_CACHE 100
10 apiCallFromTraceCall(const Trace::Call *call,
11 const QHash<QString, QUrl> &helpHash,
15 ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
17 apiCall->setHelpUrl(helpHash.value(apiCall->name()));
22 TraceLoader::TraceLoader(QObject *parent)
24 m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
28 TraceLoader::~TraceLoader()
31 qDeleteAll(m_signatures);
32 qDeleteAll(m_enumSignatures);
35 void TraceLoader::loadTrace(const QString &filename)
37 if (m_helpHash.isEmpty()) {
41 if (!m_parser.open(filename.toLatin1())) {
42 qDebug() << "error: failed to open " << filename;
46 emit startedParsing();
48 if (m_parser.supportsOffsets()) {
51 //Load the entire file into memory
55 emit finishedParsing();
58 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
60 fetchFrameContents(currentFrame);
63 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
65 m_frameMarker = marker;
68 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
70 std::string name = call->name();
72 switch (m_frameMarker) {
73 case ApiTrace::FrameMarker_SwapBuffers:
74 return name.find("SwapBuffers") != std::string::npos ||
75 name == "CGLFlushDrawable" ||
76 name == "glFrameTerminatorGREMEDY";
78 case ApiTrace::FrameMarker_Flush:
79 return name == "glFlush";
81 case ApiTrace::FrameMarker_Finish:
82 return name == "glFinish";
84 case ApiTrace::FrameMarker_Clear:
85 return name == "glClear";
91 int TraceLoader::numberOfFrames() const
93 return m_frameBookmarks.size();
96 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
98 if (frameIdx > m_frameBookmarks.size()) {
101 FrameBookmarks::const_iterator itr =
102 m_frameBookmarks.find(frameIdx);
103 return itr->numberOfCalls;
106 void TraceLoader::loadHelpFile()
108 QFile file(":/resources/glreference.tsv");
109 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
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);
119 qWarning() << "Couldn't open reference file "
125 void TraceLoader::scanTrace()
127 QList<ApiTraceFrame*> frames;
128 ApiTraceFrame *currentFrame = 0;
131 Trace::ParseBookmark startBookmark;
134 int lastPercentReport = 0;
136 m_parser.getBookmark(startBookmark);
138 while ((call = m_parser.scan_call())) {
141 if (isCallAFrameMarker(call)) {
142 FrameBookmark frameBookmark(startBookmark);
143 frameBookmark.numberOfCalls = numOfCalls;
145 currentFrame = new ApiTraceFrame();
146 currentFrame->number = numOfFrames;
147 currentFrame->setNumChildren(numOfCalls);
148 currentFrame->setLastCallIndex(call->no);
149 frames.append(currentFrame);
151 m_createdFrames.append(currentFrame);
152 m_frameBookmarks[numOfFrames] = frameBookmark;
155 if (m_parser.percentRead() - lastPercentReport >= 5) {
156 emit parsed(m_parser.percentRead());
157 lastPercentReport = m_parser.percentRead();
159 m_parser.getBookmark(startBookmark);
166 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
167 FrameBookmark frameBookmark(startBookmark);
168 frameBookmark.numberOfCalls = numOfCalls;
170 currentFrame = new ApiTraceFrame();
171 currentFrame->number = numOfFrames;
172 currentFrame->setNumChildren(numOfCalls);
173 frames.append(currentFrame);
175 m_createdFrames.append(currentFrame);
176 m_frameBookmarks[numOfFrames] = frameBookmark;
182 emit framesLoaded(frames);
185 void TraceLoader::parseTrace()
187 QList<ApiTraceFrame*> frames;
188 ApiTraceFrame *currentFrame = 0;
190 QVector<ApiTraceCall*> calls;
191 quint64 binaryDataSize = 0;
193 int lastPercentReport = 0;
195 Trace::Call *call = m_parser.parse_call();
197 //std::cout << *call;
199 currentFrame = new ApiTraceFrame();
200 currentFrame->number = frameCount;
203 ApiTraceCall *apiCall =
204 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
205 calls.append(apiCall);
206 if (apiCall->hasBinaryData()) {
208 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
209 binaryDataSize += data.size();
211 if (ApiTrace::isCallAFrameMarker(apiCall,
214 currentFrame->setCalls(calls, binaryDataSize);
216 frames.append(currentFrame);
219 if (frames.count() >= FRAMES_TO_CACHE) {
220 emit framesLoaded(frames);
223 if (m_parser.percentRead() - lastPercentReport >= 5) {
224 emit parsed(m_parser.percentRead());
225 lastPercentReport = m_parser.percentRead();
229 call = m_parser.parse_call();
232 //last frames won't have markers
233 // it's just a bunch of Delete calls for every object
234 // after the last SwapBuffers
237 currentFrame->setCalls(calls, binaryDataSize);
238 frames.append(currentFrame);
241 if (frames.count()) {
242 emit framesLoaded(frames);
247 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
249 if (id >= m_signatures.count()) {
250 m_signatures.resize(id + 1);
253 return m_signatures[id];
257 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
259 m_signatures[id] = signature;
262 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
264 if (id >= m_enumSignatures.count()) {
265 m_enumSignatures.resize(id + 1);
268 return m_enumSignatures[id];
272 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
274 m_enumSignatures[id] = signature;
277 void TraceLoader::searchNext(int startFrame,
279 Qt::CaseSensitivity sensitivity)
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())) {
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) {
295 emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
306 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
309 void TraceLoader::searchPrev(int startFrame,
311 Qt::CaseSensitivity sensitivity)
313 Q_ASSERT(m_parser.supportsOffsets());
314 if (m_parser.supportsOffsets()) {
315 Trace::Call *call = 0;
316 QList<Trace::Call*> frameCalls;
317 int frameIdx = startFrame;
319 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
320 int numCallsToParse = frameBookmark.numberOfCalls;
321 m_parser.setBookmark(frameBookmark.start);
323 while ((call = m_parser.parse_call())) {
325 frameCalls.append(call);
328 if (numCallsToParse == 0) {
329 bool foundCall = searchCallsBackwards(frameCalls,
333 qDeleteAll(frameCalls);
342 const FrameBookmark &frameBookmark =
343 m_frameBookmarks[frameIdx];
344 m_parser.setBookmark(frameBookmark.start);
345 numCallsToParse = frameBookmark.numberOfCalls;
350 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
353 bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
356 Qt::CaseSensitivity sensitivity)
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) {
366 emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
376 int TraceLoader::callInFrame(int callIdx) const
378 unsigned numCalls = 0;
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) {
389 Q_ASSERT(!"call not in the trace");
393 bool TraceLoader::callContains(Trace::Call *call,
395 Qt::CaseSensitivity sensitivity)
398 * FIXME: do string comparison directly on Trace::Call
400 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
402 bool result = apiCall->contains(str, sensitivity);
407 QVector<ApiTraceCall*>
408 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
410 Q_ASSERT(currentFrame);
412 if (currentFrame->isLoaded()) {
413 return currentFrame->calls();
416 if (m_parser.supportsOffsets()) {
417 unsigned frameIdx = currentFrame->number;
418 int numOfCalls = numberOfCallsInFrame(frameIdx);
421 quint64 binaryDataSize = 0;
422 QVector<ApiTraceCall*> calls(numOfCalls);
423 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
425 m_parser.setBookmark(frameBookmark.start);
429 while ((call = m_parser.parse_call())) {
430 ApiTraceCall *apiCall =
431 apiCallFromTraceCall(call, m_helpHash,
433 calls[parsedCalls] = apiCall;
434 Q_ASSERT(calls[parsedCalls]);
435 if (apiCall->hasBinaryData()) {
437 apiCall->arguments()[
438 apiCall->binaryDataIndex()].toByteArray();
439 binaryDataSize += data.size();
446 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
451 assert(parsedCalls == numOfCalls);
452 Q_ASSERT(parsedCalls == calls.size());
455 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
456 emit frameContentsLoaded(currentFrame,
457 calls, binaryDataSize);
461 return QVector<ApiTraceCall*>();
464 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
466 if (!frame->isLoaded()) {
469 emit foundFrameStart(frame);
472 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
474 if (!frame->isLoaded()) {
477 emit foundFrameEnd(frame);
480 void TraceLoader::findCallIndex(int index)
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) {
493 emit foundCallIndex(call);
496 #include "traceloader.moc"