X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Ftraceloader.cpp;h=d09f0fe7fa019beeca4d4e3eb13133fc8e11c61d;hb=d9d9d22837705de6a2c42ad3f9b23223a2b98fe0;hp=11847fff975b4ed5386df43ce41c191f9eb5142a;hpb=8f98c3a529e7ef88e4111ef22cf8411916a9a065;p=apitrace diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp index 11847ff..d09f0fe 100644 --- a/gui/traceloader.cpp +++ b/gui/traceloader.cpp @@ -3,16 +3,23 @@ #include "apitrace.h" #include #include +#include #define FRAMES_TO_CACHE 100 static ApiTraceCall * -apiCallFromTraceCall(const Trace::Call *call, +apiCallFromTraceCall(const trace::Call *call, const QHash &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())); @@ -20,14 +27,15 @@ apiCallFromTraceCall(const Trace::Call *call, } TraceLoader::TraceLoader(QObject *parent) - : QObject(parent), - m_frameMarker(ApiTrace::FrameMarker_SwapBuffers) + : QObject(parent) { } TraceLoader::~TraceLoader() { m_parser.close(); + qDeleteAll(m_signatures); + qDeleteAll(m_enumSignatures); } void TraceLoader::loadTrace(const QString &filename) @@ -36,21 +44,30 @@ void TraceLoader::loadTrace(const QString &filename) loadHelpFile(); } + if (!m_frameBookmarks.isEmpty()) { + qDeleteAll(m_signatures); + qDeleteAll(m_enumSignatures); + m_signatures.clear(); + m_enumSignatures.clear(); + m_frameBookmarks.clear(); + m_createdFrames.clear(); + m_parser.close(); + } + if (!m_parser.open(filename.toLatin1())) { qDebug() << "error: failed to open " << filename; return; } - qDebug()<<"load trace with "< m_frameBookmarks.size()) { + if (frameIdx >= m_frameBookmarks.size()) { return 0; } FrameBookmarks::const_iterator itr = @@ -126,8 +115,8 @@ void TraceLoader::scanTrace() QList frames; ApiTraceFrame *currentFrame = 0; - Trace::Call *call; - Trace::ParseBookmark startBookmark; + trace::Call *call; + trace::ParseBookmark startBookmark; int numOfFrames = 0; int numOfCalls = 0; int lastPercentReport = 0; @@ -137,13 +126,14 @@ void TraceLoader::scanTrace() while ((call = m_parser.scan_call())) { ++numOfCalls; - if (isCallAFrameMarker(call)) { + if (call->flags & trace::CALL_FLAG_END_FRAME) { FrameBookmark frameBookmark(startBookmark); frameBookmark.numberOfCalls = numOfCalls; currentFrame = new ApiTraceFrame(); currentFrame->number = numOfFrames; currentFrame->setNumChildren(numOfCalls); + currentFrame->setLastCallIndex(call->no); frames.append(currentFrame); m_createdFrames.append(currentFrame); @@ -161,7 +151,7 @@ void TraceLoader::scanTrace() } if (numOfCalls) { - //Trace::File::Bookmark endBookmark = m_parser.currentBookmark(); + //trace::File::Bookmark endBookmark = m_parser.currentBookmark(); FrameBookmark frameBookmark(startBookmark); frameBookmark.numberOfCalls = numOfCalls; @@ -185,12 +175,14 @@ void TraceLoader::parseTrace() QList frames; ApiTraceFrame *currentFrame = 0; int frameCount = 0; - QVector calls; + QStack groups; + QVector topLevelItems; + QVector allCalls; quint64 binaryDataSize = 0; int lastPercentReport = 0; - Trace::Call *call = m_parser.parse_call(); + trace::Call *call = m_parser.parse_call(); while (call) { //std::cout << *call; if (!currentFrame) { @@ -199,18 +191,36 @@ void TraceLoader::parseTrace() ++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 (ApiTrace::isCallAFrameMarker(apiCall, - m_frameMarker)) { - calls.squeeze(); - currentFrame->setCalls(calls, binaryDataSize); - calls.clear(); + if (call->flags & trace::CALL_FLAG_END_FRAME) { + 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; @@ -231,8 +241,12 @@ void TraceLoader::parseTrace() // 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; } @@ -272,25 +286,25 @@ void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature m_enumSignatures[id] = signature; } -void TraceLoader::searchNext(int startFrame, - const QString &str, - Qt::CaseSensitivity sensitivity) +void TraceLoader::searchNext(const ApiTrace::SearchRequest &request) { Q_ASSERT(m_parser.supportsOffsets()); if (m_parser.supportsOffsets()) { + int startFrame = m_createdFrames.indexOf(request.frame); const FrameBookmark &frameBookmark = m_frameBookmarks[startFrame]; m_parser.setBookmark(frameBookmark.start); - Trace::Call *call = 0; + trace::Call *call = 0; while ((call = m_parser.parse_call())) { - if (callContains(call, str, sensitivity)) { + if (callContains(call, request.text, request.cs)) { unsigned frameIdx = callInFrame(call->no); ApiTraceFrame *frame = m_createdFrames[frameIdx]; const QVector calls = fetchFrameContents(frame); for (int i = 0; i < calls.count(); ++i) { if (calls[i]->index() == call->no) { - emit searchResult(ApiTrace::SearchFound, calls[i]); + emit searchResult(request, ApiTrace::SearchResult_Found, + calls[i]); break; } } @@ -301,20 +315,81 @@ void TraceLoader::searchNext(int startFrame, delete call; } } - emit searchResult(ApiTrace::SearchNotFound, 0); + emit searchResult(request, ApiTrace::SearchResult_NotFound, 0); } -void TraceLoader::searchPrev(int startFrame, - const QString &str, - Qt::CaseSensitivity sensitivity) +void TraceLoader::searchPrev(const ApiTrace::SearchRequest &request) { + Q_ASSERT(m_parser.supportsOffsets()); + if (m_parser.supportsOffsets()) { + int startFrame = m_createdFrames.indexOf(request.frame); + trace::Call *call = 0; + QList frameCalls; + int frameIdx = startFrame; + + const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx]; + int numCallsToParse = frameBookmark.numberOfCalls; + m_parser.setBookmark(frameBookmark.start); + + while ((call = m_parser.parse_call())) { + + frameCalls.append(call); + --numCallsToParse; + + if (numCallsToParse == 0) { + bool foundCall = searchCallsBackwards(frameCalls, + frameIdx, + request); + + qDeleteAll(frameCalls); + frameCalls.clear(); + if (foundCall) { + return; + } + + --frameIdx; + + if (frameIdx >= 0) { + const FrameBookmark &frameBookmark = + m_frameBookmarks[frameIdx]; + m_parser.setBookmark(frameBookmark.start); + numCallsToParse = frameBookmark.numberOfCalls; + } + } + } + } + emit searchResult(request, ApiTrace::SearchResult_NotFound, 0); +} + +bool TraceLoader::searchCallsBackwards(const QList &calls, + int frameIdx, + const ApiTrace::SearchRequest &request) +{ + for (int i = calls.count() - 1; i >= 0; --i) { + trace::Call *call = calls[i]; + if (callContains(call, request.text, request.cs)) { + ApiTraceFrame *frame = m_createdFrames[frameIdx]; + const QVector apiCalls = + fetchFrameContents(frame); + for (int i = 0; i < apiCalls.count(); ++i) { + if (apiCalls[i]->index() == call->no) { + emit searchResult(request, + ApiTrace::SearchResult_Found, + apiCalls[i]); + break; + } + } + return true; + } + } + return false; } int TraceLoader::callInFrame(int callIdx) const { unsigned numCalls = 0; - for (int frameIdx = 0; frameIdx <= m_frameBookmarks.size(); ++frameIdx) { + for (int frameIdx = 0; frameIdx < m_frameBookmarks.size(); ++frameIdx) { const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx]; unsigned firstCall = numCalls; unsigned endCall = numCalls + frameBookmark.numberOfCalls; @@ -327,15 +402,15 @@ int TraceLoader::callInFrame(int callIdx) const return 0; } -bool TraceLoader::callContains(Trace::Call *call, +bool TraceLoader::callContains(trace::Call *call, const QString &str, Qt::CaseSensitivity sensitivity) { /* - * FIXME: do string comparison directly on Trace::Call + * 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; @@ -345,25 +420,45 @@ QVector TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame) { Q_ASSERT(currentFrame); + + if (currentFrame->isLoaded()) { + return currentFrame->calls(); + } + if (m_parser.supportsOffsets()) { unsigned frameIdx = currentFrame->number; int numOfCalls = numberOfCallsInFrame(frameIdx); if (numOfCalls) { quint64 binaryDataSize = 0; - QVector calls(numOfCalls); + QStack groups; + QVector topLevelItems; + QVector allCalls(numOfCalls); const FrameBookmark &frameBookmark = m_frameBookmarks[frameIdx]; m_parser.setBookmark(frameBookmark.start); - Trace::Call *call; + trace::Call *call; int parsedCalls = 0; 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 < calls.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()[ @@ -371,26 +466,74 @@ TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame) binaryDataSize += data.size(); } - ++parsedCalls; - delete call; - if (ApiTrace::isCallAFrameMarker(apiCall, m_frameMarker)) { + if (apiCall->flags() & trace::CALL_FLAG_END_FRAME) { break; } } - 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 <= calls.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(); } +void TraceLoader::findFrameStart(ApiTraceFrame *frame) +{ + if (!frame->isLoaded()) { + loadFrame(frame); + } + emit foundFrameStart(frame); +} + +void TraceLoader::findFrameEnd(ApiTraceFrame *frame) +{ + if (!frame->isLoaded()) { + loadFrame(frame); + } + emit foundFrameEnd(frame); +} + +void TraceLoader::findCallIndex(int index) +{ + int frameIdx = callInFrame(index); + ApiTraceFrame *frame = m_createdFrames[frameIdx]; + QVector calls = fetchFrameContents(frame); + QVector::const_iterator itr; + ApiTraceCall *call = 0; + for (itr = calls.constBegin(); itr != calls.constEnd(); ++itr) { + if ((*itr)->index() == index) { + call = *itr; + } + } + if (call) { + emit foundCallIndex(call); + } +} + +void TraceLoader::search(const ApiTrace::SearchRequest &request) +{ + if (request.direction == ApiTrace::SearchRequest::Next) { + searchNext(request); + } else { + searchPrev(request); + } +} + #include "traceloader.moc"