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()
33 void TraceLoader::loadTrace(const QString &filename)
35 if (m_helpHash.isEmpty()) {
39 if (!m_parser.open(filename.toLatin1())) {
40 qDebug() << "error: failed to open " << filename;
43 qDebug()<<"load trace with "<<filename;
44 emit startedParsing();
46 qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
47 if (m_parser.supportsOffsets()) {
50 //Load the entire file into memory
54 emit finishedParsing();
57 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
59 fetchFrameContents(currentFrame);
62 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
64 m_frameMarker = marker;
67 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
69 std::string name = call->name();
71 switch (m_frameMarker) {
72 case ApiTrace::FrameMarker_SwapBuffers:
73 return name.find("SwapBuffers") != std::string::npos ||
74 name == "CGLFlushDrawable" ||
75 name == "glFrameTerminatorGREMEDY";
77 case ApiTrace::FrameMarker_Flush:
78 return name == "glFlush";
80 case ApiTrace::FrameMarker_Finish:
81 return name == "glFinish";
83 case ApiTrace::FrameMarker_Clear:
84 return name == "glClear";
90 int TraceLoader::numberOfFrames() const
92 return m_frameBookmarks.size();
95 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
97 if (frameIdx > m_frameBookmarks.size()) {
100 FrameBookmarks::const_iterator itr =
101 m_frameBookmarks.find(frameIdx);
102 return itr->numberOfCalls;
105 void TraceLoader::loadHelpFile()
107 QFile file(":/resources/glreference.tsv");
108 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
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);
118 qWarning() << "Couldn't open reference file "
124 void TraceLoader::scanTrace()
126 QList<ApiTraceFrame*> frames;
127 ApiTraceFrame *currentFrame = 0;
130 Trace::ParseBookmark startBookmark;
133 int lastPercentReport = 0;
135 m_parser.getBookmark(startBookmark);
137 while ((call = m_parser.scan_call())) {
140 if (isCallAFrameMarker(call)) {
141 FrameBookmark frameBookmark(startBookmark);
142 frameBookmark.numberOfCalls = numOfCalls;
144 currentFrame = new ApiTraceFrame();
145 currentFrame->number = numOfFrames;
146 currentFrame->setNumChildren(numOfCalls);
147 currentFrame->setLastCallIndex(call->no);
148 frames.append(currentFrame);
150 m_createdFrames.append(currentFrame);
151 m_frameBookmarks[numOfFrames] = frameBookmark;
154 if (m_parser.percentRead() - lastPercentReport >= 5) {
155 emit parsed(m_parser.percentRead());
156 lastPercentReport = m_parser.percentRead();
158 m_parser.getBookmark(startBookmark);
165 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
166 FrameBookmark frameBookmark(startBookmark);
167 frameBookmark.numberOfCalls = numOfCalls;
169 currentFrame = new ApiTraceFrame();
170 currentFrame->number = numOfFrames;
171 currentFrame->setNumChildren(numOfCalls);
172 frames.append(currentFrame);
174 m_createdFrames.append(currentFrame);
175 m_frameBookmarks[numOfFrames] = frameBookmark;
181 emit framesLoaded(frames);
184 void TraceLoader::parseTrace()
186 QList<ApiTraceFrame*> frames;
187 ApiTraceFrame *currentFrame = 0;
189 QVector<ApiTraceCall*> calls;
190 quint64 binaryDataSize = 0;
192 int lastPercentReport = 0;
194 Trace::Call *call = m_parser.parse_call();
196 //std::cout << *call;
198 currentFrame = new ApiTraceFrame();
199 currentFrame->number = frameCount;
202 ApiTraceCall *apiCall =
203 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
204 calls.append(apiCall);
205 if (apiCall->hasBinaryData()) {
207 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
208 binaryDataSize += data.size();
210 if (ApiTrace::isCallAFrameMarker(apiCall,
213 currentFrame->setCalls(calls, binaryDataSize);
215 frames.append(currentFrame);
218 if (frames.count() >= FRAMES_TO_CACHE) {
219 emit framesLoaded(frames);
222 if (m_parser.percentRead() - lastPercentReport >= 5) {
223 emit parsed(m_parser.percentRead());
224 lastPercentReport = m_parser.percentRead();
228 call = m_parser.parse_call();
231 //last frames won't have markers
232 // it's just a bunch of Delete calls for every object
233 // after the last SwapBuffers
236 currentFrame->setCalls(calls, binaryDataSize);
237 frames.append(currentFrame);
240 if (frames.count()) {
241 emit framesLoaded(frames);
246 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
248 if (id >= m_signatures.count()) {
249 m_signatures.resize(id + 1);
252 return m_signatures[id];
256 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
258 m_signatures[id] = signature;
261 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
263 if (id >= m_enumSignatures.count()) {
264 m_enumSignatures.resize(id + 1);
267 return m_enumSignatures[id];
271 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
273 m_enumSignatures[id] = signature;
276 void TraceLoader::searchNext(int startFrame,
278 Qt::CaseSensitivity sensitivity)
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())) {
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]);
305 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
308 void TraceLoader::searchPrev(int startFrame,
310 Qt::CaseSensitivity sensitivity)
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;
318 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
319 int numCallsToParse = frameBookmark.numberOfCalls;
320 m_parser.setBookmark(frameBookmark.start);
322 while ((call = m_parser.parse_call())) {
324 frameCalls.append(call);
327 if (numCallsToParse == 0) {
328 bool foundCall = searchCallsBackwards(frameCalls,
332 qDeleteAll(frameCalls);
341 const FrameBookmark &frameBookmark =
342 m_frameBookmarks[frameIdx];
343 m_parser.setBookmark(frameBookmark.start);
344 numCallsToParse = frameBookmark.numberOfCalls;
349 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
352 bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
355 Qt::CaseSensitivity sensitivity)
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]);
375 int TraceLoader::callInFrame(int callIdx) const
377 unsigned numCalls = 0;
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) {
388 Q_ASSERT(!"call not in the trace");
392 bool TraceLoader::callContains(Trace::Call *call,
394 Qt::CaseSensitivity sensitivity)
397 * FIXME: do string comparison directly on Trace::Call
399 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
401 bool result = apiCall->contains(str, sensitivity);
406 QVector<ApiTraceCall*>
407 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
409 Q_ASSERT(currentFrame);
410 if (m_parser.supportsOffsets()) {
411 unsigned frameIdx = currentFrame->number;
412 int numOfCalls = numberOfCallsInFrame(frameIdx);
415 quint64 binaryDataSize = 0;
416 QVector<ApiTraceCall*> calls(numOfCalls);
417 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
419 m_parser.setBookmark(frameBookmark.start);
423 while ((call = m_parser.parse_call())) {
424 ApiTraceCall *apiCall =
425 apiCallFromTraceCall(call, m_helpHash,
427 calls[parsedCalls] = apiCall;
428 Q_ASSERT(calls[parsedCalls]);
429 if (apiCall->hasBinaryData()) {
431 apiCall->arguments()[
432 apiCall->binaryDataIndex()].toByteArray();
433 binaryDataSize += data.size();
440 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
445 assert(parsedCalls == numOfCalls);
446 Q_ASSERT(parsedCalls == calls.size());
449 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
450 emit frameContentsLoaded(currentFrame,
451 calls, binaryDataSize);
455 return QVector<ApiTraceCall*>();
458 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
461 emit foundFrameStart(frame);
464 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
467 emit foundFrameEnd(frame);
470 void TraceLoader::findCallIndex(int index)
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) {
483 emit foundCallIndex(call);
486 #include "traceloader.moc"