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)
27 TraceLoader::~TraceLoader()
30 qDeleteAll(m_signatures);
31 qDeleteAll(m_enumSignatures);
34 void TraceLoader::loadTrace(const QString &filename)
36 if (m_helpHash.isEmpty()) {
40 if (!m_frameBookmarks.isEmpty()) {
41 qDeleteAll(m_signatures);
42 qDeleteAll(m_enumSignatures);
44 m_enumSignatures.clear();
45 m_frameBookmarks.clear();
46 m_createdFrames.clear();
50 if (!m_parser.open(filename.toLatin1())) {
51 qDebug() << "error: failed to open " << filename;
55 emit startedParsing();
57 if (m_parser.supportsOffsets()) {
60 //Load the entire file into memory
63 emit finishedParsing();
66 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
68 fetchFrameContents(currentFrame);
71 int TraceLoader::numberOfFrames() const
73 return m_frameBookmarks.size();
76 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
78 if (frameIdx >= m_frameBookmarks.size()) {
81 FrameBookmarks::const_iterator itr =
82 m_frameBookmarks.find(frameIdx);
83 return itr->numberOfCalls;
86 void TraceLoader::loadHelpFile()
88 QFile file(":/resources/glreference.tsv");
89 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
91 while (!file.atEnd()) {
92 line = file.readLine();
93 QString function = line.section('\t', 0, 0).trimmed();
94 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
95 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
96 m_helpHash.insert(function, url);
99 qWarning() << "Couldn't open reference file "
105 void TraceLoader::scanTrace()
107 QList<ApiTraceFrame*> frames;
108 ApiTraceFrame *currentFrame = 0;
111 trace::ParseBookmark startBookmark;
114 int lastPercentReport = 0;
116 m_parser.getBookmark(startBookmark);
118 while ((call = m_parser.scan_call())) {
121 if (call->flags & trace::CALL_FLAG_END_FRAME) {
122 FrameBookmark frameBookmark(startBookmark);
123 frameBookmark.numberOfCalls = numOfCalls;
125 currentFrame = new ApiTraceFrame();
126 currentFrame->number = numOfFrames;
127 currentFrame->setNumChildren(numOfCalls);
128 currentFrame->setLastCallIndex(call->no);
129 frames.append(currentFrame);
131 m_createdFrames.append(currentFrame);
132 m_frameBookmarks[numOfFrames] = frameBookmark;
135 if (m_parser.percentRead() - lastPercentReport >= 5) {
136 emit parsed(m_parser.percentRead());
137 lastPercentReport = m_parser.percentRead();
139 m_parser.getBookmark(startBookmark);
146 //trace::File::Bookmark endBookmark = m_parser.currentBookmark();
147 FrameBookmark frameBookmark(startBookmark);
148 frameBookmark.numberOfCalls = numOfCalls;
150 currentFrame = new ApiTraceFrame();
151 currentFrame->number = numOfFrames;
152 currentFrame->setNumChildren(numOfCalls);
153 frames.append(currentFrame);
155 m_createdFrames.append(currentFrame);
156 m_frameBookmarks[numOfFrames] = frameBookmark;
162 emit framesLoaded(frames);
165 void TraceLoader::parseTrace()
167 QList<ApiTraceFrame*> frames;
168 ApiTraceFrame *currentFrame = 0;
170 QVector<ApiTraceCall*> calls;
171 quint64 binaryDataSize = 0;
173 int lastPercentReport = 0;
175 trace::Call *call = m_parser.parse_call();
177 //std::cout << *call;
179 currentFrame = new ApiTraceFrame();
180 currentFrame->number = frameCount;
183 ApiTraceCall *apiCall =
184 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
185 calls.append(apiCall);
186 if (apiCall->hasBinaryData()) {
188 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
189 binaryDataSize += data.size();
191 if (call->flags & trace::CALL_FLAG_END_FRAME) {
193 currentFrame->setCalls(calls, binaryDataSize);
195 frames.append(currentFrame);
198 if (frames.count() >= FRAMES_TO_CACHE) {
199 emit framesLoaded(frames);
202 if (m_parser.percentRead() - lastPercentReport >= 5) {
203 emit parsed(m_parser.percentRead());
204 lastPercentReport = m_parser.percentRead();
208 call = m_parser.parse_call();
211 //last frames won't have markers
212 // it's just a bunch of Delete calls for every object
213 // after the last SwapBuffers
216 currentFrame->setCalls(calls, binaryDataSize);
217 frames.append(currentFrame);
220 if (frames.count()) {
221 emit framesLoaded(frames);
226 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
228 if (id >= m_signatures.count()) {
229 m_signatures.resize(id + 1);
232 return m_signatures[id];
236 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
238 m_signatures[id] = signature;
241 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
243 if (id >= m_enumSignatures.count()) {
244 m_enumSignatures.resize(id + 1);
247 return m_enumSignatures[id];
251 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
253 m_enumSignatures[id] = signature;
256 void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
258 Q_ASSERT(m_parser.supportsOffsets());
259 if (m_parser.supportsOffsets()) {
260 int startFrame = m_createdFrames.indexOf(request.frame);
261 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
262 m_parser.setBookmark(frameBookmark.start);
263 trace::Call *call = 0;
264 while ((call = m_parser.parse_call())) {
266 if (callContains(call, request.text, request.cs)) {
267 unsigned frameIdx = callInFrame(call->no);
268 ApiTraceFrame *frame = m_createdFrames[frameIdx];
269 const QVector<ApiTraceCall*> calls =
270 fetchFrameContents(frame);
271 for (int i = 0; i < calls.count(); ++i) {
272 if (calls[i]->index() == call->no) {
273 emit searchResult(request, ApiTrace::SearchResult_Found,
285 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
288 void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
290 Q_ASSERT(m_parser.supportsOffsets());
291 if (m_parser.supportsOffsets()) {
292 int startFrame = m_createdFrames.indexOf(request.frame);
293 trace::Call *call = 0;
294 QList<trace::Call*> frameCalls;
295 int frameIdx = startFrame;
297 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
298 int numCallsToParse = frameBookmark.numberOfCalls;
299 m_parser.setBookmark(frameBookmark.start);
301 while ((call = m_parser.parse_call())) {
303 frameCalls.append(call);
306 if (numCallsToParse == 0) {
307 bool foundCall = searchCallsBackwards(frameCalls,
311 qDeleteAll(frameCalls);
320 const FrameBookmark &frameBookmark =
321 m_frameBookmarks[frameIdx];
322 m_parser.setBookmark(frameBookmark.start);
323 numCallsToParse = frameBookmark.numberOfCalls;
328 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
331 bool TraceLoader::searchCallsBackwards(const QList<trace::Call*> &calls,
333 const ApiTrace::SearchRequest &request)
335 for (int i = calls.count() - 1; i >= 0; --i) {
336 trace::Call *call = calls[i];
337 if (callContains(call, request.text, request.cs)) {
338 ApiTraceFrame *frame = m_createdFrames[frameIdx];
339 const QVector<ApiTraceCall*> apiCalls =
340 fetchFrameContents(frame);
341 for (int i = 0; i < apiCalls.count(); ++i) {
342 if (apiCalls[i]->index() == call->no) {
343 emit searchResult(request,
344 ApiTrace::SearchResult_Found,
355 int TraceLoader::callInFrame(int callIdx) const
357 unsigned numCalls = 0;
359 for (int frameIdx = 0; frameIdx < m_frameBookmarks.size(); ++frameIdx) {
360 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
361 unsigned firstCall = numCalls;
362 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
363 if (firstCall <= callIdx && endCall > callIdx) {
368 Q_ASSERT(!"call not in the trace");
372 bool TraceLoader::callContains(trace::Call *call,
374 Qt::CaseSensitivity sensitivity)
377 * FIXME: do string comparison directly on trace::Call
379 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
381 bool result = apiCall->contains(str, sensitivity);
386 QVector<ApiTraceCall*>
387 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
389 Q_ASSERT(currentFrame);
391 if (currentFrame->isLoaded()) {
392 return currentFrame->calls();
395 if (m_parser.supportsOffsets()) {
396 unsigned frameIdx = currentFrame->number;
397 int numOfCalls = numberOfCallsInFrame(frameIdx);
400 quint64 binaryDataSize = 0;
401 QVector<ApiTraceCall*> calls(numOfCalls);
402 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
404 m_parser.setBookmark(frameBookmark.start);
408 while ((call = m_parser.parse_call())) {
409 ApiTraceCall *apiCall =
410 apiCallFromTraceCall(call, m_helpHash,
412 calls[parsedCalls] = apiCall;
413 Q_ASSERT(calls[parsedCalls]);
414 if (apiCall->hasBinaryData()) {
416 apiCall->arguments()[
417 apiCall->binaryDataIndex()].toByteArray();
418 binaryDataSize += data.size();
425 if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
430 assert(parsedCalls == numOfCalls);
431 Q_ASSERT(parsedCalls == calls.size());
434 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
435 emit frameContentsLoaded(currentFrame,
436 calls, binaryDataSize);
440 return QVector<ApiTraceCall*>();
443 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
445 if (!frame->isLoaded()) {
448 emit foundFrameStart(frame);
451 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
453 if (!frame->isLoaded()) {
456 emit foundFrameEnd(frame);
459 void TraceLoader::findCallIndex(int index)
461 int frameIdx = callInFrame(index);
462 ApiTraceFrame *frame = m_createdFrames[frameIdx];
463 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
464 QVector<ApiTraceCall*>::const_iterator itr;
465 ApiTraceCall *call = 0;
466 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
467 if ((*itr)->index() == index) {
472 emit foundCallIndex(call);
475 void TraceLoader::search(const ApiTrace::SearchRequest &request)
477 if (request.direction == ApiTrace::SearchRequest::Next) {
484 #include "traceloader.moc"