From: Zack Rusin Date: Tue, 6 Sep 2011 15:50:07 +0000 (-0400) Subject: Implement an incremental on demand loader for the gui. X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=20b1f6dc3783cec612fe3712c4b6c1ca65d4a5f4;p=apitrace Implement an incremental on demand loader for the gui. --- diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 6973450..e0cfe44 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -21,6 +21,7 @@ set(qapitrace_SRCS settingsdialog.cpp shaderssourcewidget.cpp tracedialog.cpp + traceloader.cpp traceprocess.cpp vertexdatainterpreter.cpp ) diff --git a/gui/apitrace.cpp b/gui/apitrace.cpp index 51c4755..9a68e63 100644 --- a/gui/apitrace.cpp +++ b/gui/apitrace.cpp @@ -180,6 +180,7 @@ void ApiTrace::detectFrames() if (!currentFrame) { currentFrame = new ApiTraceFrame(this); currentFrame->number = m_frames.count(); + currentFrame->setLoaded(true); } apiCall->setParentFrame(currentFrame); currentFrame->addCall(apiCall); diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp index bd30aaa..680d22a 100644 --- a/gui/apitracecall.cpp +++ b/gui/apitracecall.cpp @@ -923,7 +923,9 @@ int ApiTraceCall::numChildren() const ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace) : ApiTraceEvent(ApiTraceEvent::Frame), m_parentTrace(parentTrace), - m_binaryDataSize(0) + m_binaryDataSize(0), + m_loaded(false), + m_callsToLoad(0) { } @@ -964,7 +966,11 @@ QStaticText ApiTraceFrame::staticText() const int ApiTraceFrame::numChildren() const { - return m_calls.count(); + if (m_loaded) { + return m_calls.count(); + } else { + return m_callsToLoad; + } } ApiTrace * ApiTraceFrame::parentTrace() const @@ -1012,4 +1018,20 @@ void ApiTraceFrame::setCalls(const QVector &calls, { m_calls = calls; m_binaryDataSize = binaryDataSize; + m_loaded = true; +} + +bool ApiTraceFrame::loaded() 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 33648f2..5a5a64b 100644 --- a/gui/apitracecall.h +++ b/gui/apitracecall.h @@ -291,6 +291,7 @@ public: ApiTrace *parentTrace() const; + void setNumChildren(int num); int numChildren() const; QStaticText staticText() const; @@ -302,10 +303,15 @@ public: quint64 binaryDataSize); int binaryDataSize() const; + + bool loaded() const; + void setLoaded(bool l); private: ApiTrace *m_parentTrace; quint64 m_binaryDataSize; QVector m_calls; + bool m_loaded; + unsigned m_callsToLoad; }; Q_DECLARE_METATYPE(ApiTraceFrame*); diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp new file mode 100644 index 0000000..40609ad --- /dev/null +++ b/gui/traceloader.cpp @@ -0,0 +1,273 @@ +#include "traceloader.h" + +#include +#include + +#define FRAMES_TO_CACHE 100 + +static ApiTraceCall * +apiCallFromTraceCall(const Trace::Call *call, + const QHash &helpHash, + ApiTraceFrame *frame) +{ + ApiTraceCall *apiCall = new ApiTraceCall(frame, call); + + apiCall->setHelpUrl(helpHash.value(apiCall->name())); + + return apiCall; +} + +TraceLoader::TraceLoader(ApiTrace *parent) + : QObject(parent), + m_trace(parent), + m_frameMarker(ApiTrace::FrameMarker_SwapBuffers) +{ +} + +TraceLoader::~TraceLoader() +{ + m_parser.close(); +} + +void TraceLoader::loadTrace(const QString &filename) +{ + if (m_helpHash.isEmpty()) { + loadHelpFile(); + } + + if (!m_parser.open(filename.toLatin1())) { + qDebug() << "error: failed to open " << filename; + return; + } + + emit startedParsing(); + + if (m_parser.supportsOffsets()) { + scanTrace(); + } else { + //Load the entire file into memory + parseTrace(); + } + + emit finishedParsing(); +} + +void TraceLoader::loadFrame(int frameIdx) +{ + if (m_parser.supportsOffsets()) { + int numOfCalls = numberOfCallsInFrame(frameIdx); + if (numOfCalls) { + const FrameOffset &frameOffset = m_frameOffsets[frameIdx]; + std::vector calls(numOfCalls); + m_parser.setCurrentOffset(frameOffset.start); + m_parser.setCurrentCallNumber(frameOffset.callNumber); + + Trace::Call *call; + int parsedCalls = 0; + while ((call = m_parser.parse_call())) { + + calls[parsedCalls] = call; + ++parsedCalls; + + if (isCallAFrameMarker(call)) { + break; + } + + } + assert(parsedCalls == numOfCalls); +// emit parsedFrame(); + } + } +} + +void TraceLoader::setFrameMarker(ApiTrace::FrameMarker marker) +{ + m_frameMarker = marker; +} + +bool TraceLoader::isCallAFrameMarker(const Trace::Call *call) const +{ + std::string name = call->name(); + + switch (m_frameMarker) { + case ApiTrace::FrameMarker_SwapBuffers: + return name.find("SwapBuffers") != std::string::npos || + name == "CGLFlushDrawable" || + name == "glFrameTerminatorGREMEDY"; + break; + case ApiTrace::FrameMarker_Flush: + return name == "glFlush"; + break; + case ApiTrace::FrameMarker_Finish: + return name == "glFinish"; + break; + case ApiTrace::FrameMarker_Clear: + return name == "glClear"; + break; + } + return false; +} + +int TraceLoader::numberOfFrames() const +{ + return m_frameOffsets.size(); +} + +int TraceLoader::numberOfCallsInFrame(int frameIdx) const +{ + if (frameIdx > m_frameOffsets.size()) { + return 0; + } + FrameOffsets::const_iterator itr = + m_frameOffsets.find(frameIdx); + return itr->numberOfCalls; +} + +void TraceLoader::loadHelpFile() +{ + QFile file(":/resources/glreference.tsv"); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QString line; + while (!file.atEnd()) { + line = file.readLine(); + QString function = line.section('\t', 0, 0).trimmed(); + QUrl url = QUrl(line.section('\t', 1, 1).trimmed()); + //qDebug()<<"function = "< frames; + ApiTraceFrame *currentFrame = 0; + + Trace::Call *call; + Trace::File::Offset startOffset; + int numOfFrames = 0; + int numOfCalls = 0; + unsigned callNum = 0; + int lastPercentReport = 0; + + startOffset = m_parser.currentOffset(); + callNum = m_parser.currentCallNumber(); + + while ((call = m_parser.scan_call())) { + ++numOfCalls; + + if (isCallAFrameMarker(call)) { + Trace::File::Offset endOffset = m_parser.currentOffset(); + FrameOffset frameOffset(startOffset); + frameOffset.numberOfCalls = numOfCalls; + frameOffset.callNumber = callNum; + + currentFrame = new ApiTraceFrame(m_trace); + currentFrame->number = numOfFrames; + currentFrame->setNumChildren(numOfCalls); + frames.append(currentFrame); + + m_frameOffsets[numOfFrames] = frameOffset; + ++numOfFrames; + + if (m_parser.percentRead() - lastPercentReport >= 5) { + emit parsed(m_parser.percentRead()); + lastPercentReport = m_parser.percentRead(); + } + startOffset = endOffset; + callNum = m_parser.currentCallNumber(); + numOfCalls = 0; + } + //call->dump(std::cout, color); + delete call; + } + + if (numOfCalls) { +// Trace::File::Offset endOffset = m_parser.currentOffset(); + FrameOffset frameOffset(startOffset); + frameOffset.numberOfCalls = numOfCalls; + frameOffset.callNumber = callNum; + + currentFrame = new ApiTraceFrame(m_trace); + currentFrame->number = numOfFrames; + currentFrame->setNumChildren(numOfCalls); + frames.append(currentFrame); + + m_frameOffsets[numOfFrames] = frameOffset; + ++numOfFrames; + } + + emit parsed(100); + + emit framesLoaded(frames); +} + +void TraceLoader::parseTrace() +{ + QList frames; + ApiTraceFrame *currentFrame = 0; + int frameCount = 0; + QVector calls; + quint64 binaryDataSize = 0; + + int lastPercentReport = 0; + + Trace::Call *call = m_parser.parse_call(); + while (call) { + //std::cout << *call; + if (!currentFrame) { + currentFrame = new ApiTraceFrame(m_trace); + currentFrame->number = frameCount; + ++frameCount; + } + ApiTraceCall *apiCall = + apiCallFromTraceCall(call, m_helpHash, currentFrame); + calls.append(apiCall); + if (apiCall->hasBinaryData()) { + QByteArray data = + apiCall->arguments()[apiCall->binaryDataIndex()].toByteArray(); + binaryDataSize += data.size(); + } + if (ApiTrace::isCallAFrameMarker(apiCall, + m_frameMarker)) { + calls.squeeze(); + currentFrame->setCalls(calls, binaryDataSize); + calls.clear(); + frames.append(currentFrame); + currentFrame = 0; + binaryDataSize = 0; + if (frames.count() >= FRAMES_TO_CACHE) { + emit framesLoaded(frames); + frames.clear(); + } + if (m_parser.percentRead() - lastPercentReport >= 5) { + emit parsed(m_parser.percentRead()); + lastPercentReport = m_parser.percentRead(); + } + } + delete call; + call = m_parser.parse_call(); + } + + //last frames won't have markers + // it's just a bunch of Delete calls for every object + // after the last SwapBuffers + if (currentFrame) { + if (!frames.count()) { + calls.squeeze(); + currentFrame->setCalls(calls, binaryDataSize); + } + frames.append(currentFrame); + currentFrame = 0; + } + if (frames.count()) { + emit framesLoaded(frames); + } +} + + +#include "traceloader.moc" diff --git a/gui/traceloader.h b/gui/traceloader.h new file mode 100644 index 0000000..e9c4171 --- /dev/null +++ b/gui/traceloader.h @@ -0,0 +1,68 @@ +#ifndef TRACELOADER_H +#define TRACELOADER_H + + +#include "apitrace.h" +#include "trace_file.hpp" +#include "trace_parser.hpp" + +#include +#include +#include + +class TraceLoader : public QObject +{ + Q_OBJECT +public: + TraceLoader(ApiTrace *parent); + ~TraceLoader(); + +public slots: + void loadTrace(const QString &filename); + void loadFrame(int frameIdx); + void setFrameMarker(ApiTrace::FrameMarker marker); + +signals: + void startedParsing(); + void parsed(float percent); + void finishedParsing(); + + void framesLoaded(const QList &frames); + void frameLoaded(int frameIdx, + const QVector &calls, + quint64 binaryDataSize); + +private: + struct FrameOffset { + FrameOffset() + : numberOfCalls(0) + {} + FrameOffset(const Trace::File::Offset &s) + : start(s), + numberOfCalls(0) + {} + + Trace::File::Offset start; + int numberOfCalls; + unsigned callNumber; + }; + bool isCallAFrameMarker(const Trace::Call *call) const; + int numberOfFrames() const; + int numberOfCallsInFrame(int frameIdx) const; + + void loadHelpFile(); + void scanTrace(); + void parseTrace(); +private: + ApiTrace *m_trace; + Trace::Parser m_parser; + QString m_fileName; + ApiTrace::FrameMarker m_frameMarker; + + typedef QMap FrameOffsets; + FrameOffsets m_frameOffsets; + + QHash m_helpHash; +}; + +#endif