#include "apitrace.h"
#include <QDebug>
#include <QFile>
+#include <QStack>
#define FRAMES_TO_CACHE 100
apiCallFromTraceCall(const trace::Call *call,
const QHash<QString, QUrl> &helpHash,
ApiTraceFrame *frame,
+ ApiTraceCall *parentCall,
TraceLoader *loader)
{
- ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call);
+ ApiTraceCall *apiCall;
+
+ if (parentCall)
+ apiCall = new ApiTraceCall(parentCall, loader, call);
+ else
+ apiCall = new ApiTraceCall(frame, loader, call);
apiCall->setHelpUrl(helpHash.value(apiCall->name()));
QList<ApiTraceFrame*> frames;
ApiTraceFrame *currentFrame = 0;
int frameCount = 0;
- QVector<ApiTraceCall*> calls;
+ QStack<ApiTraceCall*> groups;
+ QVector<ApiTraceCall*> topLevelItems;
+ QVector<ApiTraceCall*> allCalls;
quint64 binaryDataSize = 0;
int lastPercentReport = 0;
++frameCount;
}
ApiTraceCall *apiCall =
- apiCallFromTraceCall(call, m_helpHash, currentFrame, this);
- calls.append(apiCall);
+ apiCallFromTraceCall(call, m_helpHash, currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
+ allCalls.append(apiCall);
+ if (groups.count() == 0) {
+ topLevelItems.append(apiCall);
+ }
+ if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
+ groups.push(apiCall);
+ } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
+ groups.top()->finishedAddingChildren();
+ groups.pop();
+ }
+ if (!groups.isEmpty()) {
+ groups.top()->addChild(apiCall);
+ }
if (apiCall->hasBinaryData()) {
QByteArray data =
- apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
+ apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray();
binaryDataSize += data.size();
}
if (call->flags & trace::CALL_FLAG_END_FRAME) {
- calls.squeeze();
- currentFrame->setCalls(calls, binaryDataSize);
- calls.clear();
+ allCalls.squeeze();
+ topLevelItems.squeeze();
+ if (topLevelItems.count() == allCalls.count()) {
+ currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
+ } else {
+ currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
+ }
+ allCalls.clear();
+ groups.clear();
+ topLevelItems.clear();
frames.append(currentFrame);
currentFrame = 0;
binaryDataSize = 0;
// it's just a bunch of Delete calls for every object
// after the last SwapBuffers
if (currentFrame) {
- calls.squeeze();
- currentFrame->setCalls(calls, binaryDataSize);
+ allCalls.squeeze();
+ if (topLevelItems.count() == allCalls.count()) {
+ currentFrame->setCalls(allCalls, allCalls, binaryDataSize);
+ } else {
+ currentFrame->setCalls(topLevelItems, allCalls, binaryDataSize);
+ }
frames.append(currentFrame);
currentFrame = 0;
}
* FIXME: do string comparison directly on trace::Call
*/
ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash,
- 0, this);
+ 0, 0, this);
bool result = apiCall->contains(str, sensitivity);
delete apiCall;
return result;
if (numOfCalls) {
quint64 binaryDataSize = 0;
- QVector<ApiTraceCall*> calls(numOfCalls);
+ QStack<ApiTraceCall*> groups;
+ QVector<ApiTraceCall*> topLevelItems;
+ QVector<ApiTraceCall*> allCalls(numOfCalls);
const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx];
m_parser.setBookmark(frameBookmark.start);
while ((call = m_parser.parse_call())) {
ApiTraceCall *apiCall =
apiCallFromTraceCall(call, m_helpHash,
- currentFrame, this);
- calls[parsedCalls] = apiCall;
- Q_ASSERT(calls[parsedCalls]);
+ currentFrame, groups.isEmpty() ? 0 : groups.top(), this);
+ Q_ASSERT(apiCall);
+ Q_ASSERT(parsedCalls < allCalls.size());
+ allCalls[parsedCalls++] = apiCall;
+ if (groups.count() == 0) {
+ topLevelItems.append(apiCall);
+ }
+ if (!groups.isEmpty()) {
+ groups.top()->addChild(apiCall);
+ }
+ if (call->flags & trace::CALL_FLAG_MARKER_PUSH) {
+ groups.push(apiCall);
+ } else if (call->flags & trace::CALL_FLAG_MARKER_POP) {
+ groups.top()->finishedAddingChildren();
+ groups.pop();
+ }
if (apiCall->hasBinaryData()) {
QByteArray data =
apiCall->arguments()[
binaryDataSize += data.size();
}
- ++parsedCalls;
-
delete call;
if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) {
}
}
- assert(parsedCalls == numOfCalls);
- Q_ASSERT(parsedCalls == calls.size());
- calls.squeeze();
-
- Q_ASSERT(parsedCalls == currentFrame->numChildrenToLoad());
- emit frameContentsLoaded(currentFrame,
- calls, binaryDataSize);
- return calls;
+ // There can be fewer parsed calls when call in different
+ // threads cross the frame boundary
+ Q_ASSERT(parsedCalls <= numOfCalls);
+ Q_ASSERT(parsedCalls <= allCalls.size());
+ allCalls.resize(parsedCalls);
+ allCalls.squeeze();
+
+ Q_ASSERT(parsedCalls <= currentFrame->numChildrenToLoad());
+ if (topLevelItems.count() == allCalls.count()) {
+ emit frameContentsLoaded(currentFrame, allCalls,
+ allCalls, binaryDataSize);
+ } else {
+ emit frameContentsLoaded(currentFrame, topLevelItems,
+ allCalls, binaryDataSize);
+ }
+ return allCalls;
}
}
return QVector<ApiTraceCall*>();
call = *itr;
}
}
- Q_ASSERT(call);
- emit foundCallIndex(call);
+ if (call) {
+ emit foundCallIndex(call);
+ }
}
void TraceLoader::search(const ApiTrace::SearchRequest &request)