From: Zack Rusin Date: Fri, 11 Oct 2013 22:02:26 +0000 (-0400) Subject: Implement grouping of calls. X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=d9d9d22837705de6a2c42ad3f9b23223a2b98fe0;hp=52fc2b017b6914afb3799601b6e93f9306af0058;p=apitrace Implement grouping of calls. Use glPushDebugGroup and glPopDebugGroup to create nested groups of calls. It makes it easy to neatly group related calls (e.g. from nested function calls) into subgroups. --- diff --git a/common/trace_model.hpp b/common/trace_model.hpp index ba7c845..2ce1339 100644 --- a/common/trace_model.hpp +++ b/common/trace_model.hpp @@ -515,6 +515,13 @@ enum { * Whether this call is verbose (i.e., not usually interesting). */ CALL_FLAG_VERBOSE = (1 << 7), + + /** + * String markers. + */ + CALL_FLAG_MARKER = (1 << 8), + CALL_FLAG_MARKER_PUSH = (1 << 9), + CALL_FLAG_MARKER_POP = (1 << 10), }; diff --git a/common/trace_parser_flags.cpp b/common/trace_parser_flags.cpp index 0a63649..2cf55a2 100644 --- a/common/trace_parser_flags.cpp +++ b/common/trace_parser_flags.cpp @@ -519,9 +519,9 @@ callFlagTable[] = { { "glMultiModeDrawElementsIBM", CALL_FLAG_RENDER }, { "glObjectLabel", CALL_FLAG_NO_SIDE_EFFECTS }, { "glObjectPtrLabel", CALL_FLAG_NO_SIDE_EFFECTS }, - { "glPopDebugGroup", CALL_FLAG_NO_SIDE_EFFECTS }, - { "glPushDebugGroup", CALL_FLAG_NO_SIDE_EFFECTS }, - { "glStringMarkerGREMEDY", CALL_FLAG_NO_SIDE_EFFECTS }, + { "glPopDebugGroup", /* CALL_FLAG_NO_SIDE_EFFECTS | */ CALL_FLAG_MARKER | CALL_FLAG_MARKER_POP}, + { "glPushDebugGroup", /* CALL_FLAG_NO_SIDE_EFFECTS | */ CALL_FLAG_MARKER | CALL_FLAG_MARKER_PUSH }, + { "glStringMarkerGREMEDY", /* CALL_FLAG_NO_SIDE_EFFECTS | */ CALL_FLAG_MARKER }, { "glXGetClientString", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "glXGetCurrentContext", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, { "glXGetCurrentDisplay", CALL_FLAG_NO_SIDE_EFFECTS | CALL_FLAG_VERBOSE }, diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp index 671fc68..db57417 100644 --- a/gui/apitrace.cpp +++ b/gui/apitrace.cpp @@ -19,9 +19,9 @@ ApiTrace::ApiTrace() connect(m_loader, SIGNAL(framesLoaded(const QList)), this, SLOT(addFrames(const QList))); connect(m_loader, - SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector,quint64)), + SIGNAL(frameContentsLoaded(ApiTraceFrame*,QVector, QVector,quint64)), this, - SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector,quint64))); + SLOT(loaderFrameLoaded(ApiTraceFrame*,QVector,QVector,quint64))); connect(m_loader, SIGNAL(guessedApi(int)), this, SLOT(guessedApi(int))); connect(m_loader, SIGNAL(finishedParsing()), @@ -107,7 +107,7 @@ int ApiTrace::numCallsInFrame(int idx) const { const ApiTraceFrame *frame = frameAt(idx); if (frame) { - return frame->numChildren(); + return frame->numTotalCalls(); } else { return 0; } @@ -263,6 +263,7 @@ void ApiTrace::finishedParsing() } void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame, + const QVector &topLevelItems, const QVector &calls, quint64 binaryDataSize) { @@ -270,7 +271,7 @@ void ApiTrace::loaderFrameLoaded(ApiTraceFrame *frame, if (!frame->isLoaded()) { emit beginLoadingFrame(frame, calls.size()); - frame->setCalls(calls, binaryDataSize); + frame->setCalls(topLevelItems, calls, binaryDataSize); emit endLoadingFrame(frame); m_loadingFrames.remove(frame); } @@ -444,7 +445,7 @@ int ApiTrace::callInFrame(int callIdx) const for (int frameIdx = 0; frameIdx < m_frames.size(); ++frameIdx) { const ApiTraceFrame *frame = m_frames[frameIdx]; unsigned numCallsInFrame = frame->isLoaded() - ? frame->numChildren() + ? frame->numTotalCalls() : frame->numChildrenToLoad(); unsigned firstCall = numCalls; unsigned endCall = numCalls + numCallsInFrame; diff --git a/gui/apitrace.h b/gui/apitrace.h index 04e295c..a7b72d8 100644 --- a/gui/apitrace.h +++ b/gui/apitrace.h @@ -131,6 +131,7 @@ private slots: void guessedApi(int api); void finishedParsing(); void loaderFrameLoaded(ApiTraceFrame *frame, + const QVector &topLevelItems, const QVector &calls, quint64 binaryDataSize); void loaderSearchResult(const ApiTrace::SearchRequest &request, diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp index 0175bff..7987635 100644 --- a/gui/apitracecall.cpp +++ b/gui/apitracecall.cpp @@ -648,7 +648,31 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader, const trace::Call *call) : ApiTraceEvent(ApiTraceEvent::Call), - m_parentFrame(parentFrame) + m_parentFrame(parentFrame), + m_parentCall(0) +{ + loadData(loader, call); +} + +ApiTraceCall::ApiTraceCall(ApiTraceCall *parentCall, + TraceLoader *loader, + const trace::Call *call) + : ApiTraceEvent(ApiTraceEvent::Call), + m_parentFrame(parentCall->parentFrame()), + m_parentCall(parentCall) +{ + loadData(loader, call); +} + + +ApiTraceCall::~ApiTraceCall() +{ +} + + +void +ApiTraceCall::loadData(TraceLoader *loader, + const trace::Call *call) { m_index = call->no; @@ -712,10 +736,46 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, } } -ApiTraceCall::~ApiTraceCall() +ApiTraceCall * +ApiTraceCall::parentCall() const +{ + return m_parentCall; +} + + +ApiTraceEvent * +ApiTraceCall::parentEvent() const +{ + if (m_parentCall) + return m_parentCall; + else + return m_parentFrame; +} + +QVector +ApiTraceCall::children() const { + return m_children; } +void +ApiTraceCall::addChild(ApiTraceCall *call) +{ + m_children.append(call); +} + + +int +ApiTraceCall::callIndex(ApiTraceCall *call) const +{ + return m_children.indexOf(call); +} + +void +ApiTraceCall::finishedAddingChildren() +{ + m_children.squeeze(); +} bool ApiTraceCall::hasError() const { @@ -820,6 +880,15 @@ QVector ApiTraceCall::arguments() const return m_editedValues; } +ApiTraceEvent * +ApiTraceCall::eventAtRow(int row) const +{ + if (row < m_children.count()) + return m_children.value(row); + else + return NULL; +} + QVariant ApiTraceCall::returnValue() const { return m_returnValue; @@ -1011,7 +1080,7 @@ QString ApiTraceCall::searchText() const int ApiTraceCall::numChildren() const { - return 0; + return m_children.count(); } bool ApiTraceCall::contains(const QString &str, @@ -1074,22 +1143,17 @@ QStaticText ApiTraceFrame::staticText() const int ApiTraceFrame::numChildren() const { - return m_calls.count(); + return m_children.count(); } -ApiTrace * ApiTraceFrame::parentTrace() const +int ApiTraceFrame::numTotalCalls() const { - return m_parentTrace; + return m_calls.count(); } -void ApiTraceFrame::addCall(ApiTraceCall *call) +ApiTrace * ApiTraceFrame::parentTrace() const { - m_calls.append(call); - if (call->hasBinaryData()) { - QByteArray data = - call->arguments()[call->binaryDataIndex()].toByteArray(); - m_binaryDataSize += data.size(); - } + return m_parentTrace; } QVector ApiTraceFrame::calls() const @@ -1097,9 +1161,12 @@ QVector ApiTraceFrame::calls() const return m_calls; } -ApiTraceCall * ApiTraceFrame::call(int idx) const +ApiTraceEvent * ApiTraceFrame::eventAtRow(int row) const { - return m_calls.value(idx); + if (row < m_children.count()) + return m_children.value(row); + else + return NULL; } @@ -1116,7 +1183,7 @@ ApiTraceCall * ApiTraceFrame::callWithIndex(int index) const int ApiTraceFrame::callIndex(ApiTraceCall *call) const { - return m_calls.indexOf(call); + return m_children.indexOf(call); } bool ApiTraceFrame::isEmpty() const @@ -1133,9 +1200,11 @@ int ApiTraceFrame::binaryDataSize() const return m_binaryDataSize; } -void ApiTraceFrame::setCalls(const QVector &calls, +void ApiTraceFrame::setCalls(const QVector &children, + const QVector &calls, quint64 binaryDataSize) { + m_children = children; m_calls = calls; m_binaryDataSize = binaryDataSize; m_loaded = true; @@ -1148,11 +1217,6 @@ bool ApiTraceFrame::isLoaded() const return m_loaded; } -void ApiTraceFrame::setLoaded(bool l) -{ - m_loaded = l; -} - void ApiTraceFrame::setNumChildren(int num) { m_callsToLoad = num; diff --git a/gui/apitracecall.h b/gui/apitracecall.h index 8004ced..15bc627 100644 --- a/gui/apitracecall.h +++ b/gui/apitracecall.h @@ -203,6 +203,8 @@ private: QUrl m_helpUrl; }; +class ApiTraceCall; + class ApiTraceEvent { public: @@ -220,6 +222,8 @@ public: virtual QStaticText staticText() const = 0; virtual int numChildren() const = 0; + virtual int callIndex(ApiTraceCall *call) const = 0; + virtual ApiTraceEvent *eventAtRow(int row) const = 0; QVariantMap stateParameters() const; ApiTraceState *state() const; @@ -242,6 +246,8 @@ Q_DECLARE_METATYPE(ApiTraceEvent*); class ApiTraceCall : public ApiTraceEvent { public: + ApiTraceCall(ApiTraceCall *parentCall, TraceLoader *loader, + const trace::Call *tcall); ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader, const trace::Call *tcall); ~ApiTraceCall(); @@ -257,6 +263,15 @@ public: ApiTraceFrame *parentFrame()const; void setParentFrame(ApiTraceFrame *frame); + int callIndex(ApiTraceCall *call) const; + + ApiTraceEvent *parentEvent() const; + ApiTraceCall *parentCall() const; + QVector children() const; + ApiTraceEvent *eventAtRow(int row) const; + void addChild(ApiTraceCall *call); + void finishedAddingChildren(); + bool hasError() const; QString error() const; void setError(const QString &msg); @@ -282,6 +297,9 @@ public: QString backtrace() const; void setBacktrace(QString backtrace); +private: + void loadData(TraceLoader *loader, + const trace::Call *tcall); private: int m_index; ApiTraceCallSignature *m_signature; @@ -289,6 +307,8 @@ private: QVariant m_returnValue; trace::CallFlags m_flags; ApiTraceFrame *m_parentFrame; + ApiTraceCall *m_parentCall; + QVector m_children; QVector m_editedValues; @@ -316,14 +336,15 @@ public: void setNumChildren(int num); int numChildren() const; int numChildrenToLoad() const; + int numTotalCalls() const; QStaticText staticText() const; + ApiTraceEvent *eventAtRow(int row) const; int callIndex(ApiTraceCall *call) const; - ApiTraceCall *call(int idx) const; ApiTraceCall *callWithIndex(int index) const; - void addCall(ApiTraceCall *call); QVector calls() const; - void setCalls(const QVector &calls, + void setCalls(const QVector &topLevelCalls, + const QVector &allCalls, quint64 binaryDataSize); ApiTraceCall *findNextCall(ApiTraceCall *from, @@ -337,7 +358,6 @@ public: int binaryDataSize() const; bool isLoaded() const; - void setLoaded(bool l); void setLastCallIndex(unsigned index); unsigned lastCallIndex() const; @@ -348,6 +368,7 @@ public: private: ApiTrace *m_parentTrace; quint64 m_binaryDataSize; + QVector m_children; QVector m_calls; bool m_loaded; unsigned m_callsToLoad; diff --git a/gui/apitracemodel.cpp b/gui/apitracemodel.cpp index 0863c1b..fb33967 100644 --- a/gui/apitracemodel.cpp +++ b/gui/apitracemodel.cpp @@ -92,7 +92,7 @@ QVariant ApiTraceModel::data(const QModelIndex &index, int role) const } int numCalls = frame->isLoaded() - ? frame->numChildren() + ? frame->numTotalCalls() : frame->numChildrenToLoad(); return tr(htmlTempl) @@ -141,18 +141,16 @@ QModelIndex ApiTraceModel::index(int row, int column, if ((parent.isValid() && parent.column() != 0) || column != 0) return QModelIndex(); - ApiTraceEvent *event = item(parent); - if (event) { - if (event->type() != ApiTraceEvent::Frame) { - qDebug()<<"got a valid parent but it's not a frame "<type(); + //qDebug()<<"At row = "<eventAtRow(row); + if (event) { + Q_ASSERT(event->type() == ApiTraceEvent::Call); + return createIndex(row, column, event); + } else { return QModelIndex(); } - ApiTraceFrame *frame = static_cast(event); - ApiTraceCall *call = frame->call(row); - if (call) - return createIndex(row, column, call); - else - return QModelIndex(); } else { ApiTraceFrame *frame = m_trace->frameAt(row); if (frame) @@ -167,11 +165,16 @@ bool ApiTraceModel::hasChildren(const QModelIndex &parent) const { if (parent.isValid()) { ApiTraceEvent *event = item(parent); - if (event && event->type() == ApiTraceEvent::Frame) { + if (!event) + return false; + if (event->type() == ApiTraceEvent::Frame) { ApiTraceFrame *frame = static_cast(event); return !frame->isEmpty(); - } else - return false; + } else { + Q_ASSERT(event->type() == ApiTraceEvent::Call); + ApiTraceCall *call = static_cast(event); + return call->numChildren() != 0; + } } else { return (rowCount() > 0); } @@ -183,11 +186,19 @@ QModelIndex ApiTraceModel::parent(const QModelIndex &index) const return QModelIndex(); ApiTraceEvent *event = item(index); - if (event && event->type() == ApiTraceEvent::Call) { + + if (event->type() == ApiTraceEvent::Call) { ApiTraceCall *call = static_cast(event); - Q_ASSERT(call->parentFrame()); - return createIndex(call->parentFrame()->number, - 0, call->parentFrame()); + + if (call->parentCall()) { + ApiTraceCall *parentCall = call->parentCall(); + ApiTraceEvent *topEvent = parentCall->parentEvent(); + return createIndex(topEvent->callIndex(parentCall), 0, parentCall); + } else { + Q_ASSERT(call->parentFrame()); + return createIndex(call->parentFrame()->number, + 0, call->parentFrame()); + } } return QModelIndex(); } @@ -198,14 +209,10 @@ int ApiTraceModel::rowCount(const QModelIndex &parent) const return m_trace->numFrames(); ApiTraceEvent *event = item(parent); - if (!event || event->type() == ApiTraceEvent::Call) + if (!event) return 0; - ApiTraceFrame *frame = static_cast(event); - if (frame) - return frame->numChildren(); - - return 0; + return event->numChildren(); } int ApiTraceModel::columnCount(const QModelIndex &parent) const @@ -288,9 +295,7 @@ void ApiTraceModel::stateSetOnEvent(ApiTraceEvent *event) if (event->type() == ApiTraceEvent::Call) { ApiTraceCall *call = static_cast(event); - ApiTraceFrame *frame = call->parentFrame(); - int row = frame->callIndex(call); - QModelIndex index = createIndex(row, 0, call); + QModelIndex index = indexForCall(call); emit dataChanged(index, index); } else if (event->type() == ApiTraceEvent::Frame) { ApiTraceFrame *frame = static_cast(event); @@ -307,10 +312,10 @@ QModelIndex ApiTraceModel::indexForCall(ApiTraceCall *call) const return QModelIndex(); } - ApiTraceFrame *frame = call->parentFrame(); - Q_ASSERT(frame); + ApiTraceEvent *parentEvent = call->parentEvent(); + Q_ASSERT(parentEvent); - int row = frame->callIndex(call); + int row = parentEvent->callIndex(call); if (row < 0) { qDebug() << "Couldn't find call num "<index()<<" inside parent!"; return QModelIndex(); @@ -342,9 +347,7 @@ void ApiTraceModel::callChanged(ApiTraceCall *call) if (trace->needsSaving()) trace->save(); - ApiTraceFrame *frame = call->parentFrame(); - int row = frame->callIndex(call); - QModelIndex index = createIndex(row, 0, call); + QModelIndex index = indexForCall(call); emit dataChanged(index, index); } diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 3278330..3accf6e 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -1265,7 +1265,8 @@ void MainWindow::saveSelectedSurface() imageIndex = tr("_call_%1") .arg(selectedCall()->index()); } else if (selectedFrame()) { - ApiTraceCall *firstCall = selectedFrame()->call(0); + ApiTraceCall *firstCall = + static_cast(selectedFrame()->eventAtRow(0)); if (firstCall) { imageIndex = tr("_frame_%1") .arg(firstCall->index()); diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp index 6110c59..d09f0fe 100644 --- a/gui/traceloader.cpp +++ b/gui/traceloader.cpp @@ -3,6 +3,7 @@ #include "apitrace.h" #include #include +#include #define FRAMES_TO_CACHE 100 @@ -10,9 +11,15 @@ static ApiTraceCall * 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())); @@ -168,7 +175,9 @@ 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; @@ -182,17 +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 (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; @@ -213,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; } @@ -378,7 +410,7 @@ bool TraceLoader::callContains(trace::Call *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; @@ -399,7 +431,9 @@ TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame) 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); @@ -409,10 +443,22 @@ TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame) while ((call = m_parser.parse_call())) { ApiTraceCall *apiCall = apiCallFromTraceCall(call, m_helpHash, - currentFrame, this); + currentFrame, groups.isEmpty() ? 0 : groups.top(), this); Q_ASSERT(apiCall); Q_ASSERT(parsedCalls < calls.size()); - calls[parsedCalls++] = apiCall; + 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()[ @@ -431,13 +477,18 @@ TraceLoader::fetchFrameContents(ApiTraceFrame *currentFrame) // threads cross the frame boundary Q_ASSERT(parsedCalls <= numOfCalls); Q_ASSERT(parsedCalls <= calls.size()); - calls.resize(parsedCalls); - calls.squeeze(); + allCalls.resize(parsedCalls); + allCalls.squeeze(); Q_ASSERT(parsedCalls <= currentFrame->numChildrenToLoad()); - emit frameContentsLoaded(currentFrame, - calls, binaryDataSize); - return calls; + if (topLevelItems.count() == allCalls.count()) { + emit frameContentsLoaded(currentFrame, allCalls, + allCalls, binaryDataSize); + } else { + emit frameContentsLoaded(currentFrame, topLevelItems, + allCalls, binaryDataSize); + } + return allCalls; } } return QVector(); diff --git a/gui/traceloader.h b/gui/traceloader.h index 0954078..1725adb 100644 --- a/gui/traceloader.h +++ b/gui/traceloader.h @@ -40,6 +40,7 @@ signals: void framesLoaded(const QList &frames); void frameContentsLoaded(ApiTraceFrame *frame, + const QVector &topLevelItems, const QVector &calls, quint64 binaryDataSize);