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 guessedApi(static_cast<int>(m_parser.api));
64 emit finishedParsing();
67 void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
69 fetchFrameContents(currentFrame);
72 int TraceLoader::numberOfFrames() const
74 return m_frameBookmarks.size();
77 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
79 if (frameIdx >= m_frameBookmarks.size()) {
82 FrameBookmarks::const_iterator itr =
83 m_frameBookmarks.find(frameIdx);
84 return itr->numberOfCalls;
87 void TraceLoader::loadHelpFile()
89 QFile file(":/resources/glreference.tsv");
90 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
92 while (!file.atEnd()) {
93 line = file.readLine();
94 QString function = line.section('\t', 0, 0).trimmed();
95 QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
96 //qDebug()<<"function = "<<function<<", url = "<<url.toString();
97 m_helpHash.insert(function, url);
100 qWarning() << "Couldn't open reference file "
106 void TraceLoader::scanTrace()
108 QList<ApiTraceFrame*> frames;
109 ApiTraceFrame *currentFrame = 0;
112 trace::ParseBookmark startBookmark;
115 int lastPercentReport = 0;
117 m_parser.getBookmark(startBookmark);
119 while ((call = m_parser.scan_call())) {
122 if (call->flags & trace::CALL_FLAG_END_FRAME) {
123 FrameBookmark frameBookmark(startBookmark);
124 frameBookmark.numberOfCalls = numOfCalls;
126 currentFrame = new ApiTraceFrame();
127 currentFrame->number = numOfFrames;
128 currentFrame->setNumChildren(numOfCalls);
129 currentFrame->setLastCallIndex(call->no);
130 frames.append(currentFrame);
132 m_createdFrames.append(currentFrame);
133 m_frameBookmarks[numOfFrames] = frameBookmark;
136 if (m_parser.percentRead() - lastPercentReport >= 5) {
137 emit parsed(m_parser.percentRead());
138 lastPercentReport = m_parser.percentRead();
140 m_parser.getBookmark(startBookmark);
147 //trace::File::Bookmark endBookmark = m_parser.currentBookmark();
148 FrameBookmark frameBookmark(startBookmark);
149 frameBookmark.numberOfCalls = numOfCalls;
151 currentFrame = new ApiTraceFrame();
152 currentFrame->number = numOfFrames;
153 currentFrame->setNumChildren(numOfCalls);
154 frames.append(currentFrame);
156 m_createdFrames.append(currentFrame);
157 m_frameBookmarks[numOfFrames] = frameBookmark;
163 emit framesLoaded(frames);
166 void TraceLoader::parseTrace()
168 QList<ApiTraceFrame*> frames;
169 ApiTraceFrame *currentFrame = 0;
171 QVector<ApiTraceCall*> calls;
172 quint64 binaryDataSize = 0;
174 int lastPercentReport = 0;
176 trace::Call *call = m_parser.parse_call();
178 //std::cout << *call;
180 currentFrame = new ApiTraceFrame();
181 currentFrame->number = frameCount;
184 ApiTraceCall *apiCall =
185 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
186 calls.append(apiCall);
187 if (apiCall->hasBinaryData()) {
189 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
190 binaryDataSize += data.size();
192 if (call->flags & trace::CALL_FLAG_END_FRAME) {
194 currentFrame->setCalls(calls, binaryDataSize);
196 frames.append(currentFrame);
199 if (frames.count() >= FRAMES_TO_CACHE) {
200 emit framesLoaded(frames);
203 if (m_parser.percentRead() - lastPercentReport >= 5) {
204 emit parsed(m_parser.percentRead());
205 lastPercentReport = m_parser.percentRead();
209 call = m_parser.parse_call();
212 //last frames won't have markers
213 // it's just a bunch of Delete calls for every object
214 // after the last SwapBuffers
217 currentFrame->setCalls(calls, binaryDataSize);
218 frames.append(currentFrame);
221 if (frames.count()) {
222 emit framesLoaded(frames);
227 ApiTraceCallSignature * TraceLoader::signature(unsigned id)
229 if (id >= m_signatures.count()) {
230 m_signatures.resize(id + 1);
233 return m_signatures[id];
237 void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
239 m_signatures[id] = signature;
242 ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
244 if (id >= m_enumSignatures.count()) {
245 m_enumSignatures.resize(id + 1);
248 return m_enumSignatures[id];
252 void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
254 m_enumSignatures[id] = signature;
257 void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
259 Q_ASSERT(m_parser.supportsOffsets());
260 if (m_parser.supportsOffsets()) {
261 int startFrame = m_createdFrames.indexOf(request.frame);
262 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
263 m_parser.setBookmark(frameBookmark.start);
264 trace::Call *call = 0;
265 while ((call = m_parser.parse_call())) {
267 if (callContains(call, request.text, request.cs)) {
268 unsigned frameIdx = callInFrame(call->no);
269 ApiTraceFrame *frame = m_createdFrames[frameIdx];
270 const QVector<ApiTraceCall*> calls =
271 fetchFrameContents(frame);
272 for (int i = 0; i < calls.count(); ++i) {
273 if (calls[i]->index() == call->no) {
274 emit searchResult(request, ApiTrace::SearchResult_Found,
286 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
289 void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
291 Q_ASSERT(m_parser.supportsOffsets());
292 if (m_parser.supportsOffsets()) {
293 int startFrame = m_createdFrames.indexOf(request.frame);
294 trace::Call *call = 0;
295 QList<trace::Call*> frameCalls;
296 int frameIdx = startFrame;
298 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
299 int numCallsToParse = frameBookmark.numberOfCalls;
300 m_parser.setBookmark(frameBookmark.start);
302 while ((call = m_parser.parse_call())) {
304 frameCalls.append(call);
307 if (numCallsToParse == 0) {
308 bool foundCall = searchCallsBackwards(frameCalls,
312 qDeleteAll(frameCalls);
321 const FrameBookmark &frameBookmark =
322 m_frameBookmarks[frameIdx];
323 m_parser.setBookmark(frameBookmark.start);
324 numCallsToParse = frameBookmark.numberOfCalls;
329 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
332 bool TraceLoader::searchCallsBackwards(const QList<trace::Call*> &calls,
334 const ApiTrace::SearchRequest &request)
336 for (int i = calls.count() - 1; i >= 0; --i) {
337 trace::Call *call = calls[i];
338 if (callContains(call, request.text, request.cs)) {
339 ApiTraceFrame *frame = m_createdFrames[frameIdx];
340 const QVector<ApiTraceCall*> apiCalls =
341 fetchFrameContents(frame);
342 for (int i = 0; i < apiCalls.count(); ++i) {
343 if (apiCalls[i]->index() == call->no) {
344 emit searchResult(request,
345 ApiTrace::SearchResult_Found,
356 int TraceLoader::callInFrame(int callIdx) const
358 unsigned numCalls = 0;
360 for (int frameIdx = 0; frameIdx < m_frameBookmarks.size(); ++frameIdx) {
361 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
362 unsigned firstCall = numCalls;
363 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
364 if (firstCall <= callIdx && endCall > callIdx) {
369 Q_ASSERT(!"call not in the trace");
373 bool TraceLoader::callContains(trace::Call *call,
375 Qt::CaseSensitivity sensitivity)
378 * FIXME: do string comparison directly on trace::Call
380 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
382 bool result = apiCall->contains(str, sensitivity);
387 QVector<ApiTraceCall*>
388 TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
390 Q_ASSERT(currentFrame);
392 if (currentFrame->isLoaded()) {
393 return currentFrame->calls();
396 if (m_parser.supportsOffsets()) {
397 unsigned frameIdx = currentFrame->number;
398 int numOfCalls = numberOfCallsInFrame(frameIdx);
401 quint64 binaryDataSize = 0;
402 QVector<ApiTraceCall*> calls(numOfCalls);
403 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
405 m_parser.setBookmark(frameBookmark.start);
409 while ((call = m_parser.parse_call())) {
410 ApiTraceCall *apiCall =
411 apiCallFromTraceCall(call, m_helpHash,
414 Q_ASSERT(parsedCalls < calls.size());
415 calls[parsedCalls++] = apiCall;
416 if (apiCall->hasBinaryData()) {
418 apiCall->arguments()[
419 apiCall->binaryDataIndex()].toByteArray();
420 binaryDataSize += data.size();
425 if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
430 // There can be fewer parsed calls when call in different
431 // threads cross the frame boundary
432 Q_ASSERT(parsedCalls <= numOfCalls);
433 Q_ASSERT(parsedCalls <= calls.size());
434 calls.resize(parsedCalls);
437 Q_ASSERT(parsedCalls <= currentFrame->numChildrenToLoad());
438 emit frameContentsLoaded(currentFrame,
439 calls, binaryDataSize);
443 return QVector<ApiTraceCall*>();
446 void TraceLoader::findFrameStart(ApiTraceFrame *frame)
448 if (!frame->isLoaded()) {
451 emit foundFrameStart(frame);
454 void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
456 if (!frame->isLoaded()) {
459 emit foundFrameEnd(frame);
462 void TraceLoader::findCallIndex(int index)
464 int frameIdx = callInFrame(index);
465 ApiTraceFrame *frame = m_createdFrames[frameIdx];
466 QVector<ApiTraceCall*> calls = fetchFrameContents(frame);
467 QVector<ApiTraceCall*>::const_iterator itr;
468 ApiTraceCall *call = 0;
469 for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) {
470 if ((*itr)->index() == index) {
475 emit foundCallIndex(call);
479 void TraceLoader::search(const ApiTrace::SearchRequest &request)
481 if (request.direction == ApiTrace::SearchRequest::Next) {
488 #include "traceloader.moc"