]> git.notmuchmail.org Git - apitrace/blob - gui/traceloader.cpp
Implement an incremental on demand loader for the gui.
[apitrace] / gui / traceloader.cpp
1 #include "traceloader.h"
2
3 #include <QDebug>
4 #include <QFile>
5
6 #define FRAMES_TO_CACHE 100
7
8 static ApiTraceCall *
9 apiCallFromTraceCall(const Trace::Call *call,
10                      const QHash<QString, QUrl> &helpHash,
11                      ApiTraceFrame *frame)
12 {
13     ApiTraceCall *apiCall = new ApiTraceCall(frame, call);
14
15     apiCall->setHelpUrl(helpHash.value(apiCall->name()));
16
17     return apiCall;
18 }
19
20 TraceLoader::TraceLoader(ApiTrace *parent)
21     : QObject(parent),
22       m_trace(parent),
23       m_frameMarker(ApiTrace::FrameMarker_SwapBuffers)
24 {
25 }
26
27 TraceLoader::~TraceLoader()
28 {
29     m_parser.close();
30 }
31
32 void TraceLoader::loadTrace(const QString &filename)
33 {
34     if (m_helpHash.isEmpty()) {
35         loadHelpFile();
36     }
37
38     if (!m_parser.open(filename.toLatin1())) {
39         qDebug() << "error: failed to open " << filename;
40         return;
41     }
42
43     emit startedParsing();
44
45     if (m_parser.supportsOffsets()) {
46        scanTrace();
47     } else {
48        //Load the entire file into memory
49        parseTrace();
50     }
51
52     emit finishedParsing();
53 }
54
55 void TraceLoader::loadFrame(int frameIdx)
56 {
57     if (m_parser.supportsOffsets()) {
58         int numOfCalls = numberOfCallsInFrame(frameIdx);
59         if (numOfCalls) {
60             const FrameOffset &frameOffset = m_frameOffsets[frameIdx];
61             std::vector<Trace::Call*> calls(numOfCalls);
62             m_parser.setCurrentOffset(frameOffset.start);
63             m_parser.setCurrentCallNumber(frameOffset.callNumber);
64
65             Trace::Call *call;
66             int parsedCalls = 0;
67             while ((call = m_parser.parse_call())) {
68
69                 calls[parsedCalls] = call;
70                 ++parsedCalls;
71
72                 if (isCallAFrameMarker(call)) {
73                     break;
74                 }
75
76             }
77             assert(parsedCalls == numOfCalls);
78 //            emit parsedFrame();
79         }
80     }
81 }
82
83 void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker)
84 {
85     m_frameMarker = marker;
86 }
87
88 bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const
89 {
90     std::string name = call->name();
91
92     switch (m_frameMarker) {
93     case ApiTrace::FrameMarker_SwapBuffers:
94        return  name.find("SwapBuffers") != std::string::npos ||
95                name == "CGLFlushDrawable" ||
96                name == "glFrameTerminatorGREMEDY";
97        break;
98     case ApiTrace::FrameMarker_Flush:
99        return name == "glFlush";
100        break;
101     case ApiTrace::FrameMarker_Finish:
102        return name == "glFinish";
103        break;
104     case ApiTrace::FrameMarker_Clear:
105        return name == "glClear";
106        break;
107     }
108     return false;
109 }
110
111 int TraceLoader::numberOfFrames() const
112 {
113     return m_frameOffsets.size();
114 }
115
116 int TraceLoader::numberOfCallsInFrame(int frameIdx) const
117 {
118     if (frameIdx > m_frameOffsets.size()) {
119         return 0;
120     }
121     FrameOffsets::const_iterator itr =
122           m_frameOffsets.find(frameIdx);
123     return itr->numberOfCalls;
124 }
125
126 void TraceLoader::loadHelpFile()
127 {
128    QFile file(":/resources/glreference.tsv");
129    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
130       QString line;
131       while (!file.atEnd()) {
132          line = file.readLine();
133          QString function = line.section('\t', 0, 0).trimmed();
134          QUrl url = QUrl(line.section('\t', 1, 1).trimmed());
135          //qDebug()<<"function = "<<function<<", url = "<<url.toString();
136          m_helpHash.insert(function, url);
137       }
138    } else {
139       qWarning() << "Couldn't open reference file "
140                  << file.fileName();
141    }
142    file.close();
143 }
144
145 void TraceLoader::scanTrace()
146 {
147    QList<ApiTraceFrame*> frames;
148    ApiTraceFrame *currentFrame = 0;
149
150    Trace::Call *call;
151    Trace::File::Offset startOffset;
152    int numOfFrames = 0;
153    int numOfCalls = 0;
154    unsigned callNum = 0;
155    int lastPercentReport = 0;
156
157    startOffset = m_parser.currentOffset();
158    callNum = m_parser.currentCallNumber();
159
160    while ((call = m_parser.scan_call())) {
161        ++numOfCalls;
162
163        if (isCallAFrameMarker(call)) {
164            Trace::File::Offset endOffset = m_parser.currentOffset();
165            FrameOffset frameOffset(startOffset);
166            frameOffset.numberOfCalls = numOfCalls;
167            frameOffset.callNumber = callNum;
168
169            currentFrame = new ApiTraceFrame(m_trace);
170            currentFrame->number = numOfFrames;
171            currentFrame->setNumChildren(numOfCalls);
172            frames.append(currentFrame);
173
174            m_frameOffsets[numOfFrames] = frameOffset;
175            ++numOfFrames;
176
177            if (m_parser.percentRead() - lastPercentReport >= 5) {
178                emit parsed(m_parser.percentRead());
179                lastPercentReport = m_parser.percentRead();
180            }
181            startOffset = endOffset;
182            callNum = m_parser.currentCallNumber();
183            numOfCalls = 0;
184        }
185        //call->dump(std::cout, color);
186        delete call;
187    }
188
189    if (numOfCalls) {
190 //      Trace::File::Offset endOffset = m_parser.currentOffset();
191       FrameOffset frameOffset(startOffset);
192       frameOffset.numberOfCalls = numOfCalls;
193       frameOffset.callNumber = callNum;
194
195       currentFrame = new ApiTraceFrame(m_trace);
196       currentFrame->number = numOfFrames;
197       currentFrame->setNumChildren(numOfCalls);
198       frames.append(currentFrame);
199
200       m_frameOffsets[numOfFrames] = frameOffset;
201       ++numOfFrames;
202    }
203
204    emit parsed(100);
205
206    emit framesLoaded(frames);
207 }
208
209 void TraceLoader::parseTrace()
210 {
211    QList<ApiTraceFrame*> frames;
212    ApiTraceFrame *currentFrame = 0;
213    int frameCount = 0;
214    QVector<ApiTraceCall*> calls;
215    quint64 binaryDataSize = 0;
216
217    int lastPercentReport = 0;
218
219    Trace::Call *call = m_parser.parse_call();
220    while (call) {
221       //std::cout << *call;
222       if (!currentFrame) {
223          currentFrame = new ApiTraceFrame(m_trace);
224          currentFrame->number = frameCount;
225          ++frameCount;
226       }
227       ApiTraceCall *apiCall =
228             apiCallFromTraceCall(call, m_helpHash, currentFrame);
229       calls.append(apiCall);
230       if (apiCall->hasBinaryData()) {
231          QByteArray data =
232                apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
233          binaryDataSize += data.size();
234       }
235       if (ApiTrace::isCallAFrameMarker(apiCall,
236                                        m_frameMarker)) {
237          calls.squeeze();
238          currentFrame->setCalls(calls, binaryDataSize);
239          calls.clear();
240          frames.append(currentFrame);
241          currentFrame = 0;
242          binaryDataSize = 0;
243          if (frames.count() >= FRAMES_TO_CACHE) {
244             emit framesLoaded(frames);
245             frames.clear();
246          }
247          if (m_parser.percentRead() - lastPercentReport >= 5) {
248             emit parsed(m_parser.percentRead());
249             lastPercentReport = m_parser.percentRead();
250          }
251       }
252       delete call;
253       call = m_parser.parse_call();
254    }
255
256    //last frames won't have markers
257    //  it's just a bunch of Delete calls for every object
258    //  after the last SwapBuffers
259    if (currentFrame) {
260       if (!frames.count()) {
261          calls.squeeze();
262          currentFrame->setCalls(calls, binaryDataSize);
263       }
264       frames.append(currentFrame);
265       currentFrame = 0;
266    }
267    if (frames.count()) {
268       emit framesLoaded(frames);
269    }
270 }
271
272
273 #include "traceloader.moc"