blob: 6cd8cff744b4aedfd35857059f9b69d388fa3653 [file] [log] [blame]
Zack Rusin20b1f6d2011-09-06 11:50:07 -04001#include "traceloader.h"
2
Zack Rusin3176ebe2011-09-06 21:11:36 -04003#include "apitrace.h"
Zack Rusin20b1f6d2011-09-06 11:50:07 -04004#include <QDebug>
5#include <QFile>
6
7#define FRAMES_TO_CACHE 100
8
9static ApiTraceCall *
José Fonsecab4a3d142011-10-27 07:43:19 +010010apiCallFromTraceCall(const trace::Call *call,
Zack Rusin20b1f6d2011-09-06 11:50:07 -040011 const QHash<QString, QUrl> &helpHash,
Zack Rusinebf971e2011-09-06 17:44:43 -040012 ApiTraceFrame *frame,
13 TraceLoader *loader)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040014{
Zack Rusinebf971e2011-09-06 17:44:43 -040015 ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040016
17 apiCall->setHelpUrl(helpHash.value(apiCall->name()));
18
19 return apiCall;
20}
21
Zack Rusinebf971e2011-09-06 17:44:43 -040022TraceLoader::TraceLoader(QObject *parent)
José Fonseca5cd8d992012-03-25 23:12:20 +010023 : QObject(parent)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040024{
25}
26
27TraceLoader::~TraceLoader()
28{
29 m_parser.close();
Zack Rusin081e59d2011-09-21 00:25:03 -040030 qDeleteAll(m_signatures);
31 qDeleteAll(m_enumSignatures);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040032}
33
34void TraceLoader::loadTrace(const QString &filename)
35{
36 if (m_helpHash.isEmpty()) {
37 loadHelpFile();
38 }
39
Zack Rusindaf82af2011-09-24 13:42:53 -040040 if (!m_frameBookmarks.isEmpty()) {
41 qDeleteAll(m_signatures);
42 qDeleteAll(m_enumSignatures);
43 m_signatures.clear();
44 m_enumSignatures.clear();
45 m_frameBookmarks.clear();
46 m_createdFrames.clear();
47 m_parser.close();
48 }
49
Zack Rusin20b1f6d2011-09-06 11:50:07 -040050 if (!m_parser.open(filename.toLatin1())) {
51 qDebug() << "error: failed to open " << filename;
52 return;
53 }
Zack Rusin59b79552011-09-21 00:37:03 -040054
Zack Rusin20b1f6d2011-09-06 11:50:07 -040055 emit startedParsing();
56
57 if (m_parser.supportsOffsets()) {
Zack Rusinac92a212011-09-06 18:25:34 -040058 scanTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040059 } else {
Zack Rusinac92a212011-09-06 18:25:34 -040060 //Load the entire file into memory
61 parseTrace();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040062 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -040063 emit finishedParsing();
64}
65
Zack Rusin3176ebe2011-09-06 21:11:36 -040066void TraceLoader::loadFrame(ApiTraceFrame *currentFrame)
Zack Rusin20b1f6d2011-09-06 11:50:07 -040067{
Zack Rusin8f98c3a2011-09-11 18:21:29 -040068 fetchFrameContents(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040069}
70
Zack Rusin20b1f6d2011-09-06 11:50:07 -040071int TraceLoader::numberOfFrames() const
72{
José Fonseca61e61f72011-09-11 16:53:34 +010073 return m_frameBookmarks.size();
Zack Rusin20b1f6d2011-09-06 11:50:07 -040074}
75
76int TraceLoader::numberOfCallsInFrame(int frameIdx) const
77{
José Fonseca6bfa32f2012-03-22 16:26:47 +000078 if (frameIdx >= m_frameBookmarks.size()) {
Zack Rusin20b1f6d2011-09-06 11:50:07 -040079 return 0;
80 }
José Fonseca61e61f72011-09-11 16:53:34 +010081 FrameBookmarks::const_iterator itr =
82 m_frameBookmarks.find(frameIdx);
Zack Rusin20b1f6d2011-09-06 11:50:07 -040083 return itr->numberOfCalls;
84}
85
86void TraceLoader::loadHelpFile()
87{
Zack Rusinac92a212011-09-06 18:25:34 -040088 QFile file(":/resources/glreference.tsv");
89 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
90 QString line;
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);
97 }
98 } else {
99 qWarning() << "Couldn't open reference file "
100 << file.fileName();
101 }
102 file.close();
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400103}
104
105void TraceLoader::scanTrace()
106{
Zack Rusinac92a212011-09-06 18:25:34 -0400107 QList<ApiTraceFrame*> frames;
108 ApiTraceFrame *currentFrame = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400109
José Fonsecab4a3d142011-10-27 07:43:19 +0100110 trace::Call *call;
111 trace::ParseBookmark startBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400112 int numOfFrames = 0;
113 int numOfCalls = 0;
Zack Rusinac92a212011-09-06 18:25:34 -0400114 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400115
José Fonseca61e61f72011-09-11 16:53:34 +0100116 m_parser.getBookmark(startBookmark);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400117
Zack Rusinac92a212011-09-06 18:25:34 -0400118 while ((call = m_parser.scan_call())) {
119 ++numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400120
José Fonseca5cd8d992012-03-25 23:12:20 +0100121 if (call->flags & trace::CALL_FLAG_END_FRAME) {
José Fonseca61e61f72011-09-11 16:53:34 +0100122 FrameBookmark frameBookmark(startBookmark);
123 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400124
Zack Rusinac92a212011-09-06 18:25:34 -0400125 currentFrame = new ApiTraceFrame();
126 currentFrame->number = numOfFrames;
127 currentFrame->setNumChildren(numOfCalls);
Zack Rusin851d0b02011-09-14 22:04:07 -0400128 currentFrame->setLastCallIndex(call->no);
Zack Rusinac92a212011-09-06 18:25:34 -0400129 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400130
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400131 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100132 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400133 ++numOfFrames;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400134
Zack Rusinac92a212011-09-06 18:25:34 -0400135 if (m_parser.percentRead() - lastPercentReport >= 5) {
136 emit parsed(m_parser.percentRead());
137 lastPercentReport = m_parser.percentRead();
138 }
José Fonseca61e61f72011-09-11 16:53:34 +0100139 m_parser.getBookmark(startBookmark);
Zack Rusinac92a212011-09-06 18:25:34 -0400140 numOfCalls = 0;
141 }
Zack Rusinac92a212011-09-06 18:25:34 -0400142 delete call;
143 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400144
Zack Rusinac92a212011-09-06 18:25:34 -0400145 if (numOfCalls) {
José Fonsecab4a3d142011-10-27 07:43:19 +0100146 //trace::File::Bookmark endBookmark = m_parser.currentBookmark();
José Fonseca61e61f72011-09-11 16:53:34 +0100147 FrameBookmark frameBookmark(startBookmark);
148 frameBookmark.numberOfCalls = numOfCalls;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400149
Zack Rusinac92a212011-09-06 18:25:34 -0400150 currentFrame = new ApiTraceFrame();
151 currentFrame->number = numOfFrames;
152 currentFrame->setNumChildren(numOfCalls);
153 frames.append(currentFrame);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400154
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400155 m_createdFrames.append(currentFrame);
José Fonseca61e61f72011-09-11 16:53:34 +0100156 m_frameBookmarks[numOfFrames] = frameBookmark;
Zack Rusinac92a212011-09-06 18:25:34 -0400157 ++numOfFrames;
158 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400159
Zack Rusinac92a212011-09-06 18:25:34 -0400160 emit parsed(100);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400161
Zack Rusinac92a212011-09-06 18:25:34 -0400162 emit framesLoaded(frames);
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400163}
164
165void TraceLoader::parseTrace()
166{
Zack Rusinac92a212011-09-06 18:25:34 -0400167 QList<ApiTraceFrame*> frames;
168 ApiTraceFrame *currentFrame = 0;
169 int frameCount = 0;
170 QVector<ApiTraceCall*> calls;
171 quint64 binaryDataSize = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400172
Zack Rusinac92a212011-09-06 18:25:34 -0400173 int lastPercentReport = 0;
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400174
José Fonsecab4a3d142011-10-27 07:43:19 +0100175 trace::Call *call = m_parser.parse_call();
Zack Rusinac92a212011-09-06 18:25:34 -0400176 while (call) {
177 //std::cout << *call;
178 if (!currentFrame) {
179 currentFrame = new ApiTraceFrame();
180 currentFrame->number = frameCount;
181 ++frameCount;
182 }
183 ApiTraceCall *apiCall =
184 apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
185 calls.append(apiCall);
186 if (apiCall->hasBinaryData()) {
187 QByteArray data =
188 apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
189 binaryDataSize += data.size();
190 }
José Fonseca5cd8d992012-03-25 23:12:20 +0100191 if (call->flags & trace::CALL_FLAG_END_FRAME) {
Zack Rusinac92a212011-09-06 18:25:34 -0400192 calls.squeeze();
193 currentFrame->setCalls(calls, binaryDataSize);
194 calls.clear();
195 frames.append(currentFrame);
196 currentFrame = 0;
197 binaryDataSize = 0;
198 if (frames.count() >= FRAMES_TO_CACHE) {
199 emit framesLoaded(frames);
200 frames.clear();
201 }
202 if (m_parser.percentRead() - lastPercentReport >= 5) {
203 emit parsed(m_parser.percentRead());
204 lastPercentReport = m_parser.percentRead();
205 }
206 }
207 delete call;
208 call = m_parser.parse_call();
209 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400210
Zack Rusinac92a212011-09-06 18:25:34 -0400211 //last frames won't have markers
212 // it's just a bunch of Delete calls for every object
213 // after the last SwapBuffers
214 if (currentFrame) {
215 calls.squeeze();
216 currentFrame->setCalls(calls, binaryDataSize);
217 frames.append(currentFrame);
218 currentFrame = 0;
219 }
220 if (frames.count()) {
221 emit framesLoaded(frames);
222 }
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400223}
224
225
Zack Rusinebf971e2011-09-06 17:44:43 -0400226ApiTraceCallSignature * TraceLoader::signature(unsigned id)
227{
228 if (id >= m_signatures.count()) {
229 m_signatures.resize(id + 1);
230 return NULL;
231 } else {
232 return m_signatures[id];
233 }
234}
235
236void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature)
237{
238 m_signatures[id] = signature;
239}
240
241ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id)
242{
243 if (id >= m_enumSignatures.count()) {
244 m_enumSignatures.resize(id + 1);
245 return NULL;
246 } else {
247 return m_enumSignatures[id];
248 }
249}
250
251void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature)
252{
253 m_enumSignatures[id] = signature;
254}
255
Zack Rusinad513b32011-09-25 14:33:41 -0400256void TraceLoader::searchNext(const ApiTrace::SearchRequest &request)
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400257{
258 Q_ASSERT(m_parser.supportsOffsets());
259 if (m_parser.supportsOffsets()) {
Zack Rusinad513b32011-09-25 14:33:41 -0400260 int startFrame = m_createdFrames.indexOf(request.frame);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400261 const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame];
262 m_parser.setBookmark(frameBookmark.start);
José Fonsecab4a3d142011-10-27 07:43:19 +0100263 trace::Call *call = 0;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400264 while ((call = m_parser.parse_call())) {
265
Zack Rusinad513b32011-09-25 14:33:41 -0400266 if (callContains(call, request.text, request.cs)) {
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400267 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) {
Zack Rusinad513b32011-09-25 14:33:41 -0400273 emit searchResult(request, ApiTrace::SearchResult_Found,
274 calls[i]);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400275 break;
276 }
277 }
278 delete call;
279 return;
280 }
281
282 delete call;
283 }
284 }
Zack Rusinad513b32011-09-25 14:33:41 -0400285 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400286}
287
Zack Rusinad513b32011-09-25 14:33:41 -0400288void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request)
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400289{
Zack Rusin121e3162011-09-13 01:35:12 -0400290 Q_ASSERT(m_parser.supportsOffsets());
291 if (m_parser.supportsOffsets()) {
Zack Rusinad513b32011-09-25 14:33:41 -0400292 int startFrame = m_createdFrames.indexOf(request.frame);
José Fonsecab4a3d142011-10-27 07:43:19 +0100293 trace::Call *call = 0;
294 QList<trace::Call*> frameCalls;
Zack Rusin121e3162011-09-13 01:35:12 -0400295 int frameIdx = startFrame;
296
297 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
298 int numCallsToParse = frameBookmark.numberOfCalls;
299 m_parser.setBookmark(frameBookmark.start);
300
301 while ((call = m_parser.parse_call())) {
302
303 frameCalls.append(call);
304 --numCallsToParse;
305
306 if (numCallsToParse == 0) {
307 bool foundCall = searchCallsBackwards(frameCalls,
308 frameIdx,
Zack Rusinad513b32011-09-25 14:33:41 -0400309 request);
Zack Rusin121e3162011-09-13 01:35:12 -0400310
311 qDeleteAll(frameCalls);
312 frameCalls.clear();
313 if (foundCall) {
314 return;
315 }
316
317 --frameIdx;
318
319 if (frameIdx >= 0) {
320 const FrameBookmark &frameBookmark =
321 m_frameBookmarks[frameIdx];
322 m_parser.setBookmark(frameBookmark.start);
323 numCallsToParse = frameBookmark.numberOfCalls;
324 }
325 }
326 }
327 }
Zack Rusinad513b32011-09-25 14:33:41 -0400328 emit searchResult(request, ApiTrace::SearchResult_NotFound, 0);
Zack Rusin121e3162011-09-13 01:35:12 -0400329}
330
José Fonsecab4a3d142011-10-27 07:43:19 +0100331bool TraceLoader::searchCallsBackwards(const QList<trace::Call*> &calls,
Zack Rusin121e3162011-09-13 01:35:12 -0400332 int frameIdx,
Zack Rusinad513b32011-09-25 14:33:41 -0400333 const ApiTrace::SearchRequest &request)
Zack Rusin121e3162011-09-13 01:35:12 -0400334{
335 for (int i = calls.count() - 1; i >= 0; --i) {
José Fonsecab4a3d142011-10-27 07:43:19 +0100336 trace::Call *call = calls[i];
Zack Rusinad513b32011-09-25 14:33:41 -0400337 if (callContains(call, request.text, request.cs)) {
Zack Rusin121e3162011-09-13 01:35:12 -0400338 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) {
Zack Rusinad513b32011-09-25 14:33:41 -0400343 emit searchResult(request,
344 ApiTrace::SearchResult_Found,
345 apiCalls[i]);
Zack Rusin121e3162011-09-13 01:35:12 -0400346 break;
347 }
348 }
349 return true;
350 }
351 }
352 return false;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400353}
354
355int TraceLoader::callInFrame(int callIdx) const
356{
357 unsigned numCalls = 0;
358
José Fonseca6bfa32f2012-03-22 16:26:47 +0000359 for (int frameIdx = 0; frameIdx < m_frameBookmarks.size(); ++frameIdx) {
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400360 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
361 unsigned firstCall = numCalls;
362 unsigned endCall = numCalls + frameBookmark.numberOfCalls;
363 if (firstCall <= callIdx && endCall > callIdx) {
364 return frameIdx;
365 }
366 numCalls = endCall;
367 }
368 Q_ASSERT(!"call not in the trace");
369 return 0;
370}
371
José Fonsecab4a3d142011-10-27 07:43:19 +0100372bool TraceLoader::callContains(trace::Call *call,
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400373 const QString &str,
374 Qt::CaseSensitivity sensitivity)
375{
376 /*
José Fonsecab4a3d142011-10-27 07:43:19 +0100377 * FIXME: do string comparison directly on trace::Call
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400378 */
379 ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
380 0, this);
381 bool result = apiCall->contains(str, sensitivity);
382 delete apiCall;
383 return result;
384}
385
386QVector<ApiTraceCall*>
387TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame)
388{
389 Q_ASSERT(currentFrame);
Zack Rusin99f84fa2011-09-19 23:44:25 -0400390
Zack Rusin447f4a52011-09-19 23:45:39 -0400391 if (currentFrame->isLoaded()) {
Zack Rusin99f84fa2011-09-19 23:44:25 -0400392 return currentFrame->calls();
393 }
394
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400395 if (m_parser.supportsOffsets()) {
396 unsigned frameIdx = currentFrame->number;
397 int numOfCalls = numberOfCallsInFrame(frameIdx);
398
399 if (numOfCalls) {
400 quint64 binaryDataSize = 0;
401 QVector<ApiTraceCall*> calls(numOfCalls);
402 const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
403
404 m_parser.setBookmark(frameBookmark.start);
405
José Fonsecab4a3d142011-10-27 07:43:19 +0100406 trace::Call *call;
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400407 int parsedCalls = 0;
408 while ((call = m_parser.parse_call())) {
409 ApiTraceCall *apiCall =
410 apiCallFromTraceCall(call, m_helpHash,
411 currentFrame, this);
412 calls[parsedCalls] = apiCall;
413 Q_ASSERT(calls[parsedCalls]);
414 if (apiCall->hasBinaryData()) {
415 QByteArray data =
416 apiCall->arguments()[
417 apiCall->binaryDataIndex()].toByteArray();
418 binaryDataSize += data.size();
419 }
420
421 ++parsedCalls;
422
423 delete call;
424
José Fonseca5cd8d992012-03-25 23:12:20 +0100425 if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
Zack Rusin8f98c3a2011-09-11 18:21:29 -0400426 break;
427 }
428
429 }
430 assert(parsedCalls == numOfCalls);
431 Q_ASSERT(parsedCalls == calls.size());
432 calls.squeeze();
433
434 Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
435 emit frameContentsLoaded(currentFrame,
436 calls, binaryDataSize);
437 return calls;
438 }
439 }
440 return QVector<ApiTraceCall*>();
441}
442
Zack Rusin93e4d152011-09-13 02:23:39 -0400443void TraceLoader::findFrameStart(ApiTraceFrame *frame)
444{
Zack Rusin99f84fa2011-09-19 23:44:25 -0400445 if (!frame->isLoaded()) {
446 loadFrame(frame);
447 }
Zack Rusin93e4d152011-09-13 02:23:39 -0400448 emit foundFrameStart(frame);
449}
450
451void TraceLoader::findFrameEnd(ApiTraceFrame *frame)
452{
Zack Rusin99f84fa2011-09-19 23:44:25 -0400453 if (!frame->isLoaded()) {
454 loadFrame(frame);
455 }
Zack Rusin93e4d152011-09-13 02:23:39 -0400456 emit foundFrameEnd(frame);
457}
458
Zack Rusinda7579b2011-09-13 17:33:05 -0400459void TraceLoader::findCallIndex(int index)
460{
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) {
468 call = *itr;
469 }
470 }
471 Q_ASSERT(call);
472 emit foundCallIndex(call);
473}
474
Zack Rusinad513b32011-09-25 14:33:41 -0400475void TraceLoader::search(const ApiTrace::SearchRequest &request)
476{
477 if (request.direction == ApiTrace::SearchRequest::Next) {
478 searchNext(request);
479 } else {
480 searchPrev(request);
481 }
482}
483
Zack Rusin20b1f6d2011-09-06 11:50:07 -0400484#include "traceloader.moc"