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;
45 qDebug()<<"load trace with "<<filename;
46 emit startedParsing();
48 qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
49 if (m_parser.supportsOffsets()) {
52 //Load the entire file into memory
56 emit finishedParsing();
59 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
61 fetchFrameContents(currentFrame);
64 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
66 m_frameMarker = marker;
69 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
71 std::string name = call->name();
73 switch (m_frameMarker) {
74 case ApiTrace::FrameMarker_SwapBuffers:
75 return name.find("SwapBuffers") != std::string::npos ||
76 name == "CGLFlushDrawable" ||
77 name == "glFrameTerminatorGREMEDY";
79 case ApiTrace::FrameMarker_Flush:
80 return name == "glFlush";
82 case ApiTrace::FrameMarker_Finish:
83 return name == "glFinish";
85 case ApiTrace::FrameMarker_Clear:
86 return name == "glClear";
92 int TraceLoader::numberOfFrames() const
94 return m_frameBookmarks.size();
97 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
99 if (frameIdx > m_frameBookmarks.size()) {
102 FrameBookmarks::const_iterator itr =
103 m_frameBookmarks.find(frameIdx);
104 return itr->numberOfCalls;
107 void TraceLoader::loadHelpFile()
109 QFile file(":/resources/glreference.tsv");
110 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
112 while (!file.atEnd()) {
113 line = file.readLine();
114 QString function = line.section('\t', 0, 0).trimmed();
115 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
116 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
117 m_helpHash.insert(function, url);
120 qWarning() << "Couldn't open reference file "
126 void TraceLoader::scanTrace()
128 QList<ApiTraceFrame*> frames;
129 ApiTraceFrame *currentFrame = 0;
132 Trace::ParseBookmark startBookmark;
135 int lastPercentReport = 0;
137 m_parser.getBookmark(startBookmark);
139 while ((call = m_parser.scan_call())) {
142 if (isCallAFrameMarker(call)) {
143 FrameBookmark frameBookmark(startBookmark);
144 frameBookmark.numberOfCalls = numOfCalls;
146 currentFrame = new ApiTraceFrame();
147 currentFrame->number = numOfFrames;
148 currentFrame->setNumChildren(numOfCalls);
149 currentFrame->setLastCallIndex(call->no);
150 frames.append(currentFrame);
152 m_createdFrames.append(currentFrame);
153 m_frameBookmarks[numOfFrames] = frameBookmark;
156 if (m_parser.percentRead() - lastPercentReport >= 5) {
157 emit parsed(m_parser.percentRead());
158 lastPercentReport = m_parser.percentRead();
160 m_parser.getBookmark(startBookmark);
167 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
168 FrameBookmark frameBookmark(startBookmark);
169 frameBookmark.numberOfCalls = numOfCalls;
171 currentFrame = new ApiTraceFrame();
172 currentFrame->number = numOfFrames;
173 currentFrame->setNumChildren(numOfCalls);
174 frames.append(currentFrame);
176 m_createdFrames.append(currentFrame);
177 m_frameBookmarks[numOfFrames] = frameBookmark;
183 emit framesLoaded(frames);
186 void TraceLoader::parseTrace()
188 QList<ApiTraceFrame*> frames;
189 ApiTraceFrame *currentFrame = 0;
191 QVector<ApiTraceCall*> calls;
192 quint64 binaryDataSize = 0;
194 int lastPercentReport = 0;
196 Trace::Call *call = m_parser.parse_call();
198 //std::cout << *call;
200 currentFrame = new ApiTraceFrame();
201 currentFrame->number = frameCount;
204 ApiTraceCall *apiCall =
205 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
206 calls.append(apiCall);
207 if (apiCall->hasBinaryData()) {
209 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
210 binaryDataSize += data.size();
212 if (ApiTrace::isCallAFrameMarker(apiCall,
215 currentFrame->setCalls(calls, binaryDataSize);
217 frames.append(currentFrame);
220 if (frames.count() >= FRAMES_TO_CACHE) {
221 emit framesLoaded(frames);
224 if (m_parser.percentRead() - lastPercentReport >= 5) {
225 emit parsed(m_parser.percentRead());
226 lastPercentReport = m_parser.percentRead();
230 call = m_parser.parse_call();
233 //last frames won't have markers
234 // it's just a bunch of Delete calls for every object
235 // after the last SwapBuffers
238 currentFrame->setCalls(calls, binaryDataSize);
239 frames.append(currentFrame);
242 if (frames.count()) {
243 emit framesLoaded(frames);
248 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
250 if (id >= m_signatures.count()) {
251 m_signatures.resize(id + 1);
254 return m_signatures[id];
258 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
260 m_signatures[id] = signature;
263 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
265 if (id >= m_enumSignatures.count()) {
266 m_enumSignatures.resize(id + 1);
269 return m_enumSignatures[id];
273 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
275 m_enumSignatures[id] = signature;
278 void TraceLoader::searchNext(int startFrame,
280 Qt::CaseSensitivity sensitivity)
282 Q_ASSERT(m_parser.supportsOffsets());
283 if (m_parser.supportsOffsets()) {
284 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
285 m_parser.setBookmark(frameBookmark.start);
286 Trace::Call *call = 0;
287 while ((call = m_parser.parse_call())) {
289 if (callContains(call, str, sensitivity)) {
290 unsigned frameIdx = callInFrame(call->no);
291 ApiTraceFrame *frame = m_createdFrames[frameIdx];
292 const QVector<ApiTraceCall*> calls =
293 fetchFrameContents(frame);
294 for (int i = 0; i < calls.count(); ++i) {
295 if (calls[i]->index() == call->no) {
296 emit searchResult(ApiTrace::SearchResult_Found, calls[i]);
307 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
310 void TraceLoader::searchPrev(int startFrame,
312 Qt::CaseSensitivity sensitivity)
314 Q_ASSERT(m_parser.supportsOffsets());
315 if (m_parser.supportsOffsets()) {
316 Trace::Call *call = 0;
317 QList<Trace::Call*> frameCalls;
318 int frameIdx = startFrame;
320 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
321 int numCallsToParse = frameBookmark.numberOfCalls;
322 m_parser.setBookmark(frameBookmark.start);
324 while ((call = m_parser.parse_call())) {
326 frameCalls.append(call);
329 if (numCallsToParse == 0) {
330 bool foundCall = searchCallsBackwards(frameCalls,
334 qDeleteAll(frameCalls);
343 const FrameBookmark &frameBookmark =
344 m_frameBookmarks[frameIdx];
345 m_parser.setBookmark(frameBookmark.start);
346 numCallsToParse = frameBookmark.numberOfCalls;
351 emit searchResult(ApiTrace::SearchResult_NotFound, 0);
354 bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
357 Qt::CaseSensitivity sensitivity)
359 for (int i = calls.count() - 1; i >= 0; --i) {
360 Trace::Call *call = calls[i];
361 if (callContains(call, str, sensitivity)) {
362 ApiTraceFrame *frame = m_createdFrames[frameIdx];
363 const QVector<ApiTraceCall*> apiCalls =
364 fetchFrameContents(frame);
365 for (int i = 0; i < apiCalls.count(); ++i) {
366 if (apiCalls[i]->index() == call->no) {
367 emit searchResult(ApiTrace::SearchResult_Found, apiCalls[i]);
377 int TraceLoader::callInFrame(int callIdx) const
379 unsigned numCalls = 0;
381 for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
382 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
383 unsigned firstCall = numCalls;
384 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
385 if (firstCall <= callIdx && endCall > callIdx) {
390 Q_ASSERT(!"call not in the trace");
394 bool TraceLoader::callContains(Trace::Call *call,
396 Qt::CaseSensitivity sensitivity)
399 * FIXME: do string comparison directly on Trace::Call
401 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
403 bool result = apiCall->contains(str, sensitivity);
408 QVector<ApiTraceCall*>
409 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
411 Q_ASSERT(currentFrame);
413 if (currentFrame->isLoaded()) {
414 return currentFrame->calls();
417 if (m_parser.supportsOffsets()) {
418 unsigned frameIdx = currentFrame->number;
419 int numOfCalls = numberOfCallsInFrame(frameIdx);
422 quint64 binaryDataSize = 0;
423 QVector<ApiTraceCall*> calls(numOfCalls);
424 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
426 m_parser.setBookmark(frameBookmark.start);
430 while ((call = m_parser.parse_call())) {
431 ApiTraceCall *apiCall =
432 apiCallFromTraceCall(call, m_helpHash,
434 calls[parsedCalls] = apiCall;
435 Q_ASSERT(calls[parsedCalls]);
436 if (apiCall->hasBinaryData()) {
438 apiCall->arguments()[
439 apiCall->binaryDataIndex()].toByteArray();
440 binaryDataSize += data.size();
447 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
452 assert(parsedCalls == numOfCalls);
453 Q_ASSERT(parsedCalls == calls.size());
456 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
457 emit frameContentsLoaded(currentFrame,
458 calls, binaryDataSize);
462 return QVector<ApiTraceCall*>();
465 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
467 if (!frame->isLoaded()) {
470 emit foundFrameStart(frame);
473 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
475 if (!frame->isLoaded()) {
478 emit foundFrameEnd(frame);
481 void TraceLoader::findCallIndex(int index)
483 int frameIdx = callInFrame(index);
484 ApiTraceFrame *frame = m_createdFrames[frameIdx];
485 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
486 QVector<ApiTraceCall*>::const_iterator itr;
487 ApiTraceCall *call = 0;
488 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
489 if ((*itr)->index() == index) {
494 emit foundCallIndex(call);
497 #include "traceloader.moc"