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_frameBookmarks.isEmpty()) {
42 qDeleteAll(m_signatures);
43 qDeleteAll(m_enumSignatures);
45 m_enumSignatures.clear();
46 m_frameBookmarks.clear();
47 m_createdFrames.clear();
51 if (!m_parser.open(filename.toLatin1())) {
52 qDebug() << "error: failed to open " << filename;
56 emit startedParsing();
58 if (m_parser.supportsOffsets()) {
61 //Load the entire file into memory
64 emit finishedParsing();
67 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
69 fetchFrameContents(currentFrame);
72 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
74 m_frameMarker = marker;
77 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
79 std::string name = call->name();
81 switch (m_frameMarker) {
82 case ApiTrace::FrameMarker_SwapBuffers:
83 return name.find("SwapBuffers") != std::string::npos ||
84 name == "CGLFlushDrawable" ||
85 name == "glFrameTerminatorGREMEDY";
87 case ApiTrace::FrameMarker_Flush:
88 return name == "glFlush";
90 case ApiTrace::FrameMarker_Finish:
91 return name == "glFinish";
93 case ApiTrace::FrameMarker_Clear:
94 return name == "glClear";
100 int TraceLoader::numberOfFrames() const
102 return m_frameBookmarks.size();
105 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
107 if (frameIdx > m_frameBookmarks.size()) {
110 FrameBookmarks::const_iterator itr =
111 m_frameBookmarks.find(frameIdx);
112 return itr->numberOfCalls;
115 void TraceLoader::loadHelpFile()
117 QFile file(":/resources/glreference.tsv");
118 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
120 while (!file.atEnd()) {
121 line = file.readLine();
122 QString function = line.section('\t', 0, 0).trimmed();
123 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
124 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
125 m_helpHash.insert(function, url);
128 qWarning() << "Couldn't open reference file "
134 void TraceLoader::scanTrace()
136 QList<ApiTraceFrame*> frames;
137 ApiTraceFrame *currentFrame = 0;
140 Trace::ParseBookmark startBookmark;
143 int lastPercentReport = 0;
145 m_parser.getBookmark(startBookmark);
147 while ((call = m_parser.scan_call())) {
150 if (isCallAFrameMarker(call)) {
151 FrameBookmark frameBookmark(startBookmark);
152 frameBookmark.numberOfCalls = numOfCalls;
154 currentFrame = new ApiTraceFrame();
155 currentFrame->number = numOfFrames;
156 currentFrame->setNumChildren(numOfCalls);
157 currentFrame->setLastCallIndex(call->no);
158 frames.append(currentFrame);
160 m_createdFrames.append(currentFrame);
161 m_frameBookmarks[numOfFrames] = frameBookmark;
164 if (m_parser.percentRead() - lastPercentReport >= 5) {
165 emit parsed(m_parser.percentRead());
166 lastPercentReport = m_parser.percentRead();
168 m_parser.getBookmark(startBookmark);
175 //Trace::File::Bookmark endBookmark = m_parser.currentBookmark();
176 FrameBookmark frameBookmark(startBookmark);
177 frameBookmark.numberOfCalls = numOfCalls;
179 currentFrame = new ApiTraceFrame();
180 currentFrame->number = numOfFrames;
181 currentFrame->setNumChildren(numOfCalls);
182 frames.append(currentFrame);
184 m_createdFrames.append(currentFrame);
185 m_frameBookmarks[numOfFrames] = frameBookmark;
191 emit framesLoaded(frames);
194 void TraceLoader::parseTrace()
196 QList<ApiTraceFrame*> frames;
197 ApiTraceFrame *currentFrame = 0;
199 QVector<ApiTraceCall*> calls;
200 quint64 binaryDataSize = 0;
202 int lastPercentReport = 0;
204 Trace::Call *call = m_parser.parse_call();
206 //std::cout << *call;
208 currentFrame = new ApiTraceFrame();
209 currentFrame->number = frameCount;
212 ApiTraceCall *apiCall =
213 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
214 calls.append(apiCall);
215 if (apiCall->hasBinaryData()) {
217 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
218 binaryDataSize += data.size();
220 if (ApiTrace::isCallAFrameMarker(apiCall,
223 currentFrame->setCalls(calls, binaryDataSize);
225 frames.append(currentFrame);
228 if (frames.count() >= FRAMES_TO_CACHE) {
229 emit framesLoaded(frames);
232 if (m_parser.percentRead() - lastPercentReport >= 5) {
233 emit parsed(m_parser.percentRead());
234 lastPercentReport = m_parser.percentRead();
238 call = m_parser.parse_call();
241 //last frames won't have markers
242 // it's just a bunch of Delete calls for every object
243 // after the last SwapBuffers
246 currentFrame->setCalls(calls, binaryDataSize);
247 frames.append(currentFrame);
250 if (frames.count()) {
251 emit framesLoaded(frames);
256 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
258 if (id >= m_signatures.count()) {
259 m_signatures.resize(id + 1);
262 return m_signatures[id];
266 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
268 m_signatures[id] = signature;
271 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
273 if (id >= m_enumSignatures.count()) {
274 m_enumSignatures.resize(id + 1);
277 return m_enumSignatures[id];
281 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
283 m_enumSignatures[id] = signature;
286 void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
288 Q_ASSERT(m_parser.supportsOffsets());
289 if (m_parser.supportsOffsets()) {
290 int startFrame = m_createdFrames.indexOf(request.frame);
291 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
292 m_parser.setBookmark(frameBookmark.start);
293 Trace::Call *call = 0;
294 while ((call = m_parser.parse_call())) {
296 if (callContains(call, request.text, request.cs)) {
297 unsigned frameIdx = callInFrame(call->no);
298 ApiTraceFrame *frame = m_createdFrames[frameIdx];
299 const QVector<ApiTraceCall*> calls =
300 fetchFrameContents(frame);
301 for (int i = 0; i < calls.count(); ++i) {
302 if (calls[i]->index() == call->no) {
303 emit searchResult(request, ApiTrace::SearchResult_Found,
315 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
318 void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
320 Q_ASSERT(m_parser.supportsOffsets());
321 if (m_parser.supportsOffsets()) {
322 int startFrame = m_createdFrames.indexOf(request.frame);
323 Trace::Call *call = 0;
324 QList<Trace::Call*> frameCalls;
325 int frameIdx = startFrame;
327 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
328 int numCallsToParse = frameBookmark.numberOfCalls;
329 m_parser.setBookmark(frameBookmark.start);
331 while ((call = m_parser.parse_call())) {
333 frameCalls.append(call);
336 if (numCallsToParse == 0) {
337 bool foundCall = searchCallsBackwards(frameCalls,
341 qDeleteAll(frameCalls);
350 const FrameBookmark &frameBookmark =
351 m_frameBookmarks[frameIdx];
352 m_parser.setBookmark(frameBookmark.start);
353 numCallsToParse = frameBookmark.numberOfCalls;
358 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
361 bool TraceLoader::searchCallsBackwards(const QList<Trace::Call*> &calls,
363 const ApiTrace::SearchRequest &request)
365 for (int i = calls.count() - 1; i >= 0; --i) {
366 Trace::Call *call = calls[i];
367 if (callContains(call, request.text, request.cs)) {
368 ApiTraceFrame *frame = m_createdFrames[frameIdx];
369 const QVector<ApiTraceCall*> apiCalls =
370 fetchFrameContents(frame);
371 for (int i = 0; i < apiCalls.count(); ++i) {
372 if (apiCalls[i]->index() == call->no) {
373 emit searchResult(request,
374 ApiTrace::SearchResult_Found,
385 int TraceLoader::callInFrame(int callIdx) const
387 unsigned numCalls = 0;
389 for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) {
390 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
391 unsigned firstCall = numCalls;
392 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
393 if (firstCall <= callIdx && endCall > callIdx) {
398 Q_ASSERT(!"call not in the trace");
402 bool TraceLoader::callContains(Trace::Call *call,
404 Qt::CaseSensitivity sensitivity)
407 * FIXME: do string comparison directly on Trace::Call
409 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
411 bool result = apiCall->contains(str, sensitivity);
416 QVector<ApiTraceCall*>
417 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
419 Q_ASSERT(currentFrame);
421 if (currentFrame->isLoaded()) {
422 return currentFrame->calls();
425 if (m_parser.supportsOffsets()) {
426 unsigned frameIdx = currentFrame->number;
427 int numOfCalls = numberOfCallsInFrame(frameIdx);
430 quint64 binaryDataSize = 0;
431 QVector<ApiTraceCall*> calls(numOfCalls);
432 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
434 m_parser.setBookmark(frameBookmark.start);
438 while ((call = m_parser.parse_call())) {
439 ApiTraceCall *apiCall =
440 apiCallFromTraceCall(call, m_helpHash,
442 calls[parsedCalls] = apiCall;
443 Q_ASSERT(calls[parsedCalls]);
444 if (apiCall->hasBinaryData()) {
446 apiCall->arguments()[
447 apiCall->binaryDataIndex()].toByteArray();
448 binaryDataSize += data.size();
455 if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) {
460 assert(parsedCalls == numOfCalls);
461 Q_ASSERT(parsedCalls == calls.size());
464 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
465 emit frameContentsLoaded(currentFrame,
466 calls, binaryDataSize);
470 return QVector<ApiTraceCall*>();
473 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
475 if (!frame->isLoaded()) {
478 emit foundFrameStart(frame);
481 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
483 if (!frame->isLoaded()) {
486 emit foundFrameEnd(frame);
489 void TraceLoader::findCallIndex(int index)
491 int frameIdx = callInFrame(index);
492 ApiTraceFrame *frame = m_createdFrames[frameIdx];
493 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
494 QVector<ApiTraceCall*>::const_iterator itr;
495 ApiTraceCall *call = 0;
496 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
497 if ((*itr)->index() == index) {
502 emit foundCallIndex(call);
505 void TraceLoader::search(const ApiTrace::SearchRequest &request)
507 if (request.direction == ApiTrace::SearchRequest::Next) {
514 #include "traceloader.moc"