From: Zack Rusin Date: Tue, 6 Sep 2011 21:45:34 +0000 (-0400) Subject: Merge remote-tracking branch 'origin/master' into on-demand-loading X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=46963dad18214fc45b248ecdc9f5931cf417705d;hp=b96ab8e352a1aa89d25b9ecb5c7276a3f298961a;p=apitrace Merge remote-tracking branch 'origin/master' into on-demand-loading --- diff --git a/CMakeLists.txt b/CMakeLists.txt index e840f21..2ee433a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,7 @@ add_library (common trace_writer.cpp trace_local_writer.cpp trace_model_writer.cpp + trace_loader.cpp image.cpp image_bmp.cpp image_pnm.cpp @@ -204,6 +205,8 @@ link_libraries (common) add_executable (tracedump tracedump.cpp) install (TARGETS tracedump RUNTIME DESTINATION bin) +add_executable (loadertest loadertest.cpp) +install (TARGETS loadertest RUNTIME DESTINATION bin) ############################################################################## # API tracers diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 6973450..777bc92 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -12,7 +12,6 @@ set(qapitrace_SRCS glsledit.cpp imageviewer.cpp jumpwidget.cpp - loaderthread.cpp mainwindow.cpp main.cpp retracer.cpp @@ -21,6 +20,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..d6a9e41 100644 --- a/gui/apitrace.cpp +++ b/gui/apitrace.cpp @@ -1,31 +1,46 @@ #include "apitrace.h" -#include "loaderthread.h" +#include "traceloader.h" #include "saverthread.h" #include +#include ApiTrace::ApiTrace() : m_frameMarker(ApiTrace::FrameMarker_SwapBuffers), m_needsSaving(false) { - m_loader = new LoaderThread(this); - connect(m_loader, SIGNAL(parsedFrames(const QList)), + m_loader = new TraceLoader(); + connect(this, SIGNAL(loadTrace(QString)), + m_loader, SLOT(loadTrace(QString))); + connect(m_loader, SIGNAL(framesLoaded(const QList)), this, SLOT(addFrames(const QList))); - connect(m_loader, SIGNAL(started()), + connect(m_loader, SIGNAL(frameLoaded(int,QVector,quint64)), + this, SLOT(fillFrame(int,QVector,quint64))); + + connect(m_loader, SIGNAL(startedParsing()), this, SIGNAL(startedLoadingTrace())); - connect(m_loader, SIGNAL(finished()), + connect(m_loader, SIGNAL(parsed(int)), + this, SIGNAL(loaded(int))); + connect(m_loader, SIGNAL(finishedParsing()), this, SIGNAL(finishedLoadingTrace())); + m_saver = new SaverThread(this); connect(m_saver, SIGNAL(traceSaved()), this, SLOT(slotSaved())); connect(m_saver, SIGNAL(traceSaved()), this, SIGNAL(saved())); + + m_loaderThread = new QThread(); + m_loader->moveToThread(m_loaderThread); + m_loaderThread->start(); } ApiTrace::~ApiTrace() { + m_loaderThread->quit(); + m_loaderThread->deleteLater(); qDeleteAll(m_calls); qDeleteAll(m_frames); delete m_loader; @@ -118,10 +133,6 @@ void ApiTrace::setFileName(const QString &name) if (m_fileName != name) { m_fileName = name; - if (m_loader->isRunning()) { - m_loader->terminate(); - m_loader->wait(); - } m_frames.clear(); m_calls.clear(); m_errors.clear(); @@ -129,7 +140,8 @@ void ApiTrace::setFileName(const QString &name) m_needsSaving = false; emit invalidated(); - m_loader->loadFile(m_fileName); +// m_loader->loadTrace(m_fileName); + emit loadTrace(m_fileName); } } @@ -157,7 +169,7 @@ void ApiTrace::addFrames(const QList &frames) int currentCalls = m_calls.count(); int numNewCalls = 0; foreach(ApiTraceFrame *frame, frames) { - Q_ASSERT(this == frame->parentTrace()); + frame->setParentTrace(this); numNewCalls += frame->numChildren(); calls += frame->calls(); } @@ -180,6 +192,7 @@ void ApiTrace::detectFrames() if (!currentFrame) { currentFrame = new ApiTraceFrame(this); currentFrame->number = m_frames.count(); + currentFrame->setLoaded(true); } apiCall->setParentFrame(currentFrame); currentFrame->addCall(apiCall); @@ -289,34 +302,9 @@ bool ApiTrace::hasErrors() const return !m_errors.isEmpty(); } -ApiTraceCallSignature * ApiTrace::signature(unsigned id) -{ - if (id >= m_signatures.count()) { - m_signatures.resize(id + 1); - return NULL; - } else { - return m_signatures[id]; - } -} - -void ApiTrace::addSignature(unsigned id, ApiTraceCallSignature *signature) -{ - m_signatures[id] = signature; -} - -ApiTraceEnumSignature * ApiTrace::enumSignature(unsigned id) -{ - if (id >= m_enumSignatures.count()) { - m_enumSignatures.resize(id + 1); - return NULL; - } else { - return m_enumSignatures[id]; - } -} - -void ApiTrace::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature) +void ApiTrace::fillFrame(int frameIdx, const QVector &calls, + quint64 binaryDataSize) { - m_enumSignatures[id] = signature; } #include "apitrace.moc" diff --git a/gui/apitrace.h b/gui/apitrace.h index 036a84c..3b737e0 100644 --- a/gui/apitrace.h +++ b/gui/apitrace.h @@ -6,8 +6,9 @@ #include #include -class LoaderThread; +class TraceLoader; class SaverThread; +class QThread; class ApiTrace : public QObject { @@ -33,13 +34,6 @@ public: ApiTraceState defaultState() const; - ApiTraceCallSignature *signature(unsigned id); - void addSignature(unsigned id, ApiTraceCallSignature *signature); - - ApiTraceEnumSignature *enumSignature(unsigned id); - void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature); - - QVector calls() const; ApiTraceCall *callAt(int idx) const; ApiTraceCall *callWithIndex(int idx) const; @@ -67,7 +61,9 @@ public slots: void save(); signals: + void loadTrace(const QString &name); void startedLoadingTrace(); + void loaded(int percent); void finishedLoadingTrace(); void invalidated(); void framesInvalidated(); @@ -81,6 +77,8 @@ signals: private slots: void addFrames(const QList &frames); + void fillFrame(int frameIdx, const QVector &calls, + quint64 binaryDataSize); void slotSaved(); private: void detectFrames(); @@ -93,7 +91,8 @@ private: FrameMarker m_frameMarker; - LoaderThread *m_loader; + TraceLoader *m_loader; + QThread *m_loaderThread; SaverThread *m_saver; QSet m_editedCalls; @@ -101,8 +100,6 @@ private: bool m_needsSaving; QSet m_errors; - QVector m_signatures; - QVector m_enumSignatures; }; #endif diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp index bd30aaa..d1de5a8 100644 --- a/gui/apitracecall.cpp +++ b/gui/apitracecall.cpp @@ -1,6 +1,7 @@ #include "apitracecall.h" #include "apitrace.h" +#include "traceloader.h" #include "trace_model.hpp" #include @@ -175,15 +176,15 @@ void VariantVisitor::visit(Trace::Enum *e) { ApiTraceEnumSignature *sig = 0; - if (m_trace) { - sig = m_trace->enumSignature(e->sig->id); + if (m_loader) { + sig = m_loader->enumSignature(e->sig->id); } if (!sig) { sig = new ApiTraceEnumSignature( QString::fromStdString(e->sig->name), QVariant(e->sig->value)); - if (m_trace) { - m_trace->addEnumSignature(e->sig->id, sig); + if (m_loader) { + m_loader->addEnumSignature(e->sig->id, sig); } } @@ -600,17 +601,15 @@ void ApiTraceEvent::setState(ApiTraceState *state) m_state = state; } -ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call) +ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, + TraceLoader *loader, + const Trace::Call *call) : ApiTraceEvent(ApiTraceEvent::Call), m_parentFrame(parentFrame) { - ApiTrace *trace = parentTrace(); - - Q_ASSERT(trace); - m_index = call->no; - m_signature = trace->signature(call->sig->id); + m_signature = loader->signature(call->sig->id); if (!m_signature) { QString name = QString::fromStdString(call->sig->name); @@ -620,16 +619,16 @@ ApiTraceCall::ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *call) argNames += QString::fromStdString(call->sig->arg_names[i]); } m_signature = new ApiTraceCallSignature(name, argNames); - trace->addSignature(call->sig->id, m_signature); + loader->addSignature(call->sig->id, m_signature); } if (call->ret) { - VariantVisitor retVisitor(trace); + VariantVisitor retVisitor(loader); call->ret->visit(retVisitor); m_returnValue = retVisitor.variant(); } m_argValues.reserve(call->args.size()); for (int i = 0; i < call->args.size(); ++i) { - VariantVisitor argVisitor(trace); + VariantVisitor argVisitor(loader); call->args[i]->visit(argVisitor); m_argValues.append(argVisitor.variant()); if (m_argValues[i].type() == QVariant::ByteArray) { @@ -923,7 +922,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 +965,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 +1017,25 @@ 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; +} + +void ApiTraceFrame::setParentTrace(ApiTrace *parent) +{ + m_parentTrace = parent; } diff --git a/gui/apitracecall.h b/gui/apitracecall.h index 33648f2..865f60c 100644 --- a/gui/apitracecall.h +++ b/gui/apitracecall.h @@ -12,12 +12,13 @@ class ApiTrace; +class TraceLoader; class VariantVisitor : public Trace::Visitor { public: - VariantVisitor(ApiTrace *trace) - : m_trace(trace) + VariantVisitor(TraceLoader *loader) + : m_loader(loader) {} virtual void visit(Trace::Null *); virtual void visit(Trace::Bool *node); @@ -37,7 +38,7 @@ public: return m_variant; } private: - ApiTrace *m_trace; + TraceLoader *m_loader; QVariant m_variant; }; @@ -233,7 +234,8 @@ Q_DECLARE_METATYPE(ApiTraceEvent*); class ApiTraceCall : public ApiTraceEvent { public: - ApiTraceCall(ApiTraceFrame *parentFrame, const Trace::Call *tcall); + ApiTraceCall(ApiTraceFrame *parentFrame, TraceLoader *loader, + const Trace::Call *tcall); ~ApiTraceCall(); int index() const; @@ -284,13 +286,15 @@ Q_DECLARE_METATYPE(ApiTraceCall*); class ApiTraceFrame : public ApiTraceEvent { public: - ApiTraceFrame(ApiTrace *parent); + ApiTraceFrame(ApiTrace *parent=0); int number; bool isEmpty() const; + void setParentTrace(ApiTrace *parent); ApiTrace *parentTrace() const; + void setNumChildren(int num); int numChildren() const; QStaticText staticText() const; @@ -302,10 +306,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/apitracemodel.cpp b/gui/apitracemodel.cpp index 5860cf9..800b5c7 100644 --- a/gui/apitracemodel.cpp +++ b/gui/apitracemodel.cpp @@ -1,7 +1,7 @@ #include "apitracemodel.h" #include "apitracecall.h" -#include "loaderthread.h" +#include "traceloader.h" #include "trace_parser.hpp" #include diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 591c557..e5f6d9b 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -647,7 +647,7 @@ void MainWindow::initObjects() m_ui.callView->setContextMenuPolicy(Qt::CustomContextMenu); m_progressBar = new QProgressBar(); - m_progressBar->setRange(0, 0); + m_progressBar->setRange(0, 100); statusBar()->addPermanentWidget(m_progressBar); m_progressBar->hide(); @@ -682,6 +682,8 @@ void MainWindow::initConnections() { connect(m_trace, SIGNAL(startedLoadingTrace()), this, SLOT(startedLoadingTrace())); + connect(m_trace, SIGNAL(loaded(int)), + this, SLOT(loadProgess(int))); connect(m_trace, SIGNAL(finishedLoadingTrace()), this, SLOT(finishedLoadingTrace())); connect(m_trace, SIGNAL(startedSaving()), @@ -1159,4 +1161,9 @@ void MainWindow::saveSelectedSurface() statusBar()->showMessage( tr("Saved '%1'").arg(fileName), 5000); } +void MainWindow::loadProgess(int percent) +{ + m_progressBar->setValue(percent); +} + #include "mainwindow.moc" diff --git a/gui/mainwindow.h b/gui/mainwindow.h index f3e3181..00fe04b 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -46,6 +46,7 @@ private slots: void replayStateFound(ApiTraceState *state); void replayError(const QString &msg); void startedLoadingTrace(); + void loadProgess(int percent); void finishedLoadingTrace(); void lookupState(); void showSettings(); diff --git a/gui/traceloader.cpp b/gui/traceloader.cpp new file mode 100644 index 0000000..0303ee7 --- /dev/null +++ b/gui/traceloader.cpp @@ -0,0 +1,305 @@ +#include "traceloader.h" + +#include +#include + +#define FRAMES_TO_CACHE 100 + +static ApiTraceCall * +apiCallFromTraceCall(const Trace::Call *call, + const QHash &helpHash, + ApiTraceFrame *frame, + TraceLoader *loader) +{ + ApiTraceCall *apiCall = new ApiTraceCall(frame, loader, call); + + apiCall->setHelpUrl(helpHash.value(apiCall->name())); + + return apiCall; +} + +TraceLoader::TraceLoader(QObject *parent) + : QObject(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; + } + qDebug()<<"load trace with "< 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(); + 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(); + 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(); + currentFrame->number = frameCount; + ++frameCount; + } + ApiTraceCall *apiCall = + apiCallFromTraceCall(call, m_helpHash, currentFrame, this); + 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) { + qDebug()<<"emitting = " << m_parser.percentRead(); + 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); + } +} + + +ApiTraceCallSignature * TraceLoader::signature(unsigned id) +{ + if (id >= m_signatures.count()) { + m_signatures.resize(id + 1); + return NULL; + } else { + return m_signatures[id]; + } +} + +void TraceLoader::addSignature(unsigned id, ApiTraceCallSignature *signature) +{ + m_signatures[id] = signature; +} + +ApiTraceEnumSignature * TraceLoader::enumSignature(unsigned id) +{ + if (id >= m_enumSignatures.count()) { + m_enumSignatures.resize(id + 1); + return NULL; + } else { + return m_enumSignatures[id]; + } +} + +void TraceLoader::addEnumSignature(unsigned id, ApiTraceEnumSignature *signature) +{ + m_enumSignatures[id] = signature; +} + +#include "traceloader.moc" diff --git a/gui/traceloader.h b/gui/traceloader.h new file mode 100644 index 0000000..32c7f16 --- /dev/null +++ b/gui/traceloader.h @@ -0,0 +1,78 @@ +#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(QObject *parent=0); + ~TraceLoader(); + + + ApiTraceCallSignature *signature(unsigned id); + void addSignature(unsigned id, ApiTraceCallSignature *signature); + + ApiTraceEnumSignature *enumSignature(unsigned id); + void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature); + +public slots: + void loadTrace(const QString &filename); + void loadFrame(int frameIdx); + void setFrameMarker(ApiTrace::FrameMarker marker); + +signals: + void startedParsing(); + void parsed(int 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: + Trace::Parser m_parser; + QString m_fileName; + ApiTrace::FrameMarker m_frameMarker; + + typedef QMap FrameOffsets; + FrameOffsets m_frameOffsets; + + QHash m_helpHash; + + QVector m_signatures; + QVector m_enumSignatures; +}; + +#endif diff --git a/loadertest.cpp b/loadertest.cpp new file mode 100644 index 0000000..397187a --- /dev/null +++ b/loadertest.cpp @@ -0,0 +1,72 @@ +#include "trace_loader.hpp" +#include "os.hpp" + +#include + + +static const double msecsInSec = 1000000; + +static void timeFrameFetch(Trace::Loader &loader, unsigned frameIdx) +{ + long long t1, t2; + std::vector frame; + + t1 = OS::GetTime(); + frame = loader.frame(frameIdx); + t2 = OS::GetTime(); + std::cout << "Time to fetch the frame[" + << frameIdx + << "] size " + << frame.size() + << " is = " + << (t2 - t1)/msecsInSec + << " secs "<file); + fseek(stream->file,0,SEEK_END); + m_endOffset = ftell(stream->file); + fseek(stream->file, loc, SEEK_SET); + } + return m_gzFile != NULL; } @@ -133,3 +162,20 @@ void ZLibFile::rawFlush() { gzflush(m_gzFile, Z_SYNC_FLUSH); } + + +bool ZLibFile::supportsOffsets() const +{ + return false; +} + +bool ZLibFile::rawSkip(size_t) +{ + return false; +} + +int ZLibFile::rawPercentRead() +{ + gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile; + return 100 * (ftell(stream->file) / m_endOffset); +} diff --git a/trace_file.hpp b/trace_file.hpp index 60a8459..f6e77ae 100644 --- a/trace_file.hpp +++ b/trace_file.hpp @@ -29,6 +29,7 @@ #include #include +#include namespace Trace { @@ -38,6 +39,15 @@ public: Read, Write }; + struct Offset { + Offset() + : chunk(0), + offsetInChunk(0) + {} + uint64_t chunk; + uint32_t offsetInChunk; + }; + public: static bool isZLibCompressed(const std::string &filename); static bool isSnappyCompressed(const std::string &filename); @@ -57,7 +67,12 @@ public: void close(); void flush(void); int getc(); + bool skip(size_t length); + int percentRead(); + virtual bool supportsOffsets() const = 0; + virtual File::Offset currentOffset(); + virtual void setCurrentOffset(const File::Offset &offset); protected: virtual bool rawOpen(const std::string &filename, File::Mode mode) = 0; virtual bool rawWrite(const void *buffer, size_t length) = 0; @@ -65,6 +80,8 @@ protected: virtual int rawGetc() = 0; virtual void rawClose() = 0; virtual void rawFlush() = 0; + virtual bool rawSkip(size_t length) = 0; + virtual int rawPercentRead() = 0; protected: std::string m_filename; @@ -114,6 +131,14 @@ inline bool File::read(void *buffer, size_t length) return rawRead(buffer, length); } +inline int File::percentRead() +{ + if (!m_isOpened || m_mode != File::Read) { + return 0; + } + return rawPercentRead(); +} + inline void File::close() { if (m_isOpened) { @@ -137,12 +162,22 @@ inline int File::getc() return rawGetc(); } +inline bool File::skip(size_t length) +{ + if (!m_isOpened || m_mode != File::Read) { + return false; + } + return rawSkip(length); +} + class ZLibFile : public File { public: ZLibFile(const std::string &filename = std::string(), File::Mode mode = File::Read); virtual ~ZLibFile(); + + virtual bool supportsOffsets() const; protected: virtual bool rawOpen(const std::string &filename, File::Mode mode); virtual bool rawWrite(const void *buffer, size_t length); @@ -150,10 +185,47 @@ protected: virtual int rawGetc(); virtual void rawClose(); virtual void rawFlush(); + virtual bool rawSkip(size_t length); + virtual int rawPercentRead(); private: void *m_gzFile; + double m_endOffset; }; +inline bool +operator<(const File::Offset &one, const File::Offset &two) +{ + return one.chunk < two.chunk || + (one.chunk == two.chunk && one.offsetInChunk < two.offsetInChunk); +} + +inline bool +operator==(const File::Offset &one, const File::Offset &two) +{ + return one.chunk == two.chunk && + one.offsetInChunk == two.offsetInChunk; +} + +inline bool +operator>=(const File::Offset &one, const File::Offset &two) +{ + return one.chunk > two.chunk || + (one.chunk == two.chunk && one.offsetInChunk >= two.offsetInChunk); +} + +inline bool +operator>(const File::Offset &one, const File::Offset &two) +{ + return two < one; +} + +inline bool +operator<=(const File::Offset &one, const File::Offset &two) +{ + return two >= one; +} + + } #endif diff --git a/trace_loader.cpp b/trace_loader.cpp new file mode 100644 index 0000000..f91e09b --- /dev/null +++ b/trace_loader.cpp @@ -0,0 +1,145 @@ +#include "trace_loader.hpp" + +#include "trace_snappyfile.hpp" + +using namespace Trace; + +Loader::Loader() + : m_frameMarker(FrameMarker_SwapBuffers) +{ +} + +Loader::~Loader() +{ + close(); +} + +Loader::FrameMarker Loader::frameMarker() const +{ + return m_frameMarker; +} + +void Loader::setFrameMarker(Loader::FrameMarker marker) +{ + m_frameMarker = marker; +} + +int Loader::numberOfFrames() const +{ + return m_frameOffsets.size(); +} + +int Loader::numberOfCallsInFrame(int frameIdx) const +{ + if (frameIdx > m_frameOffsets.size()) { + return 0; + } + FrameOffsets::const_iterator itr = + m_frameOffsets.find(frameIdx); + return itr->second.numberOfCalls; +} + +bool Loader::open(const char *filename) +{ + if (!m_parser.open(filename)) { + std::cerr << "error: failed to open " << filename << "\n"; + return false; + } + if (!m_parser.supportsOffsets()) { + std::cerr << "error: " <= 5) { + std::cerr << "\tPercent scanned = " + << m_parser.percentRead() + << "..."<dump(std::cout, color); + delete call; + } + return true; +} + +void Loader::close() +{ + m_parser.close(); +} + +bool Loader::isCallAFrameMarker(const Trace::Call *call) const +{ + std::string name = call->name(); + + switch (m_frameMarker) { + case FrameMarker_SwapBuffers: + return name.find("SwapBuffers") != std::string::npos || + name == "CGLFlushDrawable" || + name == "glFrameTerminatorGREMEDY"; + break; + case FrameMarker_Flush: + return name == "glFlush"; + break; + case FrameMarker_Finish: + return name == "glFinish"; + break; + case FrameMarker_Clear: + return name == "glClear"; + break; + } + return false; +} + +std::vector Loader::frame(int idx) +{ + int numOfCalls = numberOfCallsInFrame(idx); + if (numOfCalls) { + const FrameOffset &frameOffset = m_frameOffsets[idx]; + 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); + return calls; + } + return std::vector(); +} diff --git a/trace_loader.hpp b/trace_loader.hpp new file mode 100644 index 0000000..86a56bd --- /dev/null +++ b/trace_loader.hpp @@ -0,0 +1,66 @@ +#ifndef TRACE_LOADER_HPP +#define TRACE_LOADER_HPP + +#include "trace_file.hpp" +#include "trace_parser.hpp" + +#include +#include +#include +#include + +namespace Trace { + +class Frame; + +class Loader +{ +public: + enum FrameMarker { + FrameMarker_SwapBuffers, + FrameMarker_Flush, + FrameMarker_Finish, + FrameMarker_Clear + }; +public: + Loader(); + ~Loader(); + + Loader::FrameMarker frameMarker() const; + void setFrameMarker(Loader::FrameMarker marker); + + int numberOfFrames() const; + int numberOfCallsInFrame(int frameIdx) const; + + bool open(const char *filename); + void close(); + + std::vector frame(int idx); + +private: + struct FrameOffset { + FrameOffset() + : numberOfCalls(0) + {} + FrameOffset(const File::Offset &s) + : start(s), + numberOfCalls(0) + {} + + File::Offset start; + int numberOfCalls; + unsigned callNumber; + }; + bool isCallAFrameMarker(const Trace::Call *call) const; + +private: + Trace::Parser m_parser; + FrameMarker m_frameMarker; + + typedef std::map FrameOffsets; + FrameOffsets m_frameOffsets; +}; + +} + +#endif // TRACE_LOADER_HPP diff --git a/trace_parser.cpp b/trace_parser.cpp index 44d1786..2ef77b6 100644 --- a/trace_parser.cpp +++ b/trace_parser.cpp @@ -43,6 +43,7 @@ Parser::Parser() { file = NULL; next_call_no = 0; version = 0; + m_supportsSeeking = false; } @@ -62,6 +63,7 @@ bool Parser::open(const char *filename) { if (!file->open(filename, File::Read)) { return false; } + m_supportsSeeking = file->supportsOffsets(); version = read_uint(); if (version > TRACE_VERSION) { @@ -146,21 +148,44 @@ void Parser::parse_enter(void) { size_t id = read_uint(); FunctionSig *sig = lookup(functions, id); - if (!sig) { - sig = new FunctionSig; - sig->id = id; - sig->name = read_string(); - sig->num_args = read_uint(); - const char **arg_names = new const char *[sig->num_args]; - for (unsigned i = 0; i < sig->num_args; ++i) { - arg_names[i] = read_string(); + + + File::Offset offset; + bool callWithSig = false; + if (m_supportsSeeking) { + offset = file->currentOffset(); + callWithSig = callWithSignature(offset); + } + + if (!sig || callWithSig) { + if (!sig) { + sig = new FunctionSig; + sig->id = id; + sig->name = read_string(); + sig->num_args = read_uint(); + const char **arg_names = new const char *[sig->num_args]; + for (unsigned i = 0; i < sig->num_args; ++i) { + arg_names[i] = read_string(); + } + sig->arg_names = arg_names; + functions[id] = sig; + if (m_supportsSeeking) { + m_callSigOffsets.insert(offset); + } + } else { + /* skip over the signature */ + skip_string(); /* name */ + int num_args = read_uint(); + for (unsigned i = 0; i < num_args; ++i) { + skip_string(); /*arg_name*/ + } } - sig->arg_names = arg_names; - functions[id] = sig; } assert(sig); Call *call = new Call(sig); + + call->no = next_call_no++; if (parse_call_details(call)) { @@ -322,14 +347,30 @@ Value *Parser::parse_string() { Value *Parser::parse_enum() { size_t id = read_uint(); EnumSig *sig = lookup(enums, id); - if (!sig) { - sig = new EnumSig; - sig->id = id; - sig->name = read_string(); - Value *value = parse_value(); - sig->value = value->toSInt(); - delete value; - enums[id] = sig; + File::Offset offset; + bool enumWithSig = false; + + if (m_supportsSeeking) { + offset = file->currentOffset(); + enumWithSig = enumWithSignature(offset); + } + + if (!sig || enumWithSig) { + if (!sig) { + sig = new EnumSig; + sig->id = id; + sig->name = read_string(); + Value *value = parse_value(); + sig->value = value->toSInt(); + delete value; + enums[id] = sig; + if (m_supportsSeeking) { + m_enumSigOffsets.insert(offset); + } + } else { + skip_string(); /*name*/ + scan_value(); + } } assert(sig); return new Enum(sig); @@ -339,20 +380,39 @@ Value *Parser::parse_enum() { Value *Parser::parse_bitmask() { size_t id = read_uint(); BitmaskSig *sig = lookup(bitmasks, id); - if (!sig) { - sig = new BitmaskSig; - sig->id = id; - sig->num_flags = read_uint(); - BitmaskFlag *flags = new BitmaskFlag[sig->num_flags]; - for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) { - it->name = read_string(); - it->value = read_uint(); - if (it->value == 0 && it != flags) { - std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n"; + File::Offset offset; + bool bitmaskWithSig = false; + + if (m_supportsSeeking) { + offset = file->currentOffset(); + bitmaskWithSig = bitmaskWithSignature(offset); + } + + if (!sig || bitmaskWithSig) { + if (!sig) { + sig = new BitmaskSig; + sig->id = id; + sig->num_flags = read_uint(); + BitmaskFlag *flags = new BitmaskFlag[sig->num_flags]; + for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) { + it->name = read_string(); + it->value = read_uint(); + if (it->value == 0 && it != flags) { + std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n"; + } + } + sig->flags = flags; + bitmasks[id] = sig; + if (m_supportsSeeking) { + m_bitmaskSigOffsets.insert(offset); + } + } else { + int num_flags = read_uint(); + for (int i = 0; i < num_flags; ++i) { + skip_string(); /*name */ + skip_uint(); /* value */ } } - sig->flags = flags; - bitmasks[id] = sig; } assert(sig); @@ -386,17 +446,36 @@ Value *Parser::parse_struct() { size_t id = read_uint(); StructSig *sig = lookup(structs, id); - if (!sig) { - sig = new StructSig; - sig->id = id; - sig->name = read_string(); - sig->num_members = read_uint(); - const char **member_names = new const char *[sig->num_members]; - for (unsigned i = 0; i < sig->num_members; ++i) { - member_names[i] = read_string(); + File::Offset offset; + bool structWithSig = false; + + if (m_supportsSeeking) { + offset = file->currentOffset(); + structWithSig = structWithSignature(offset); + } + + if (!sig || structWithSig) { + if (!sig) { + sig = new StructSig; + sig->id = id; + sig->name = read_string(); + sig->num_members = read_uint(); + const char **member_names = new const char *[sig->num_members]; + for (unsigned i = 0; i < sig->num_members; ++i) { + member_names[i] = read_string(); + } + sig->member_names = member_names; + structs[id] = sig; + if (m_supportsSeeking) { + m_structSigOffsets.insert(offset); + } + } else { + skip_string(); /* name */ + unsigned num_members = read_uint(); + for (unsigned i = 0; i < num_members; ++i) { + skip_string(); /* member_name */ + } } - sig->member_names = member_names; - structs[id] = sig; } assert(sig); @@ -462,4 +541,315 @@ inline int Parser::read_byte(void) { } +inline bool Parser::callWithSignature(const File::Offset &offset) const +{ + return m_callSigOffsets.find(offset) != m_callSigOffsets.end(); +} + +inline bool Parser::structWithSignature(const File::Offset &offset) const +{ + return m_structSigOffsets.find(offset) != m_structSigOffsets.end(); +} + +inline bool Parser::enumWithSignature(const File::Offset &offset) const +{ + return m_enumSigOffsets.find(offset) != m_enumSigOffsets.end(); +} + +inline bool Parser::bitmaskWithSignature(const File::Offset &offset) const +{ + return m_bitmaskSigOffsets.find(offset) != m_bitmaskSigOffsets.end(); +} + +Call * Parser::scan_call() +{ + assert(m_supportsSeeking); + do { + int c = read_byte(); + switch(c) { + case Trace::EVENT_ENTER: + scan_enter(); + break; + case Trace::EVENT_LEAVE: + return scan_leave(); + default: + std::cerr << "error: unknown event " << c << "\n"; + exit(1); + case -1: + for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { + std::cerr << "warning: incomplete call " << (*it)->name() << "\n"; + std::cerr << **it << "\n"; + } + return NULL; + } + } while (true); +} + +void Parser::scan_enter(void) { + size_t id = read_uint(); + + FunctionSig *sig = lookup(functions, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new FunctionSig; + sig->id = id; + sig->name = read_string(); + sig->num_args = read_uint(); + const char **arg_names = new const char *[sig->num_args]; + for (unsigned i = 0; i < sig->num_args; ++i) { + arg_names[i] = read_string(); + } + sig->arg_names = arg_names; + functions[id] = sig; + m_callSigOffsets.insert(offset); + } + assert(sig); + + Call *call = new Call(sig); + call->no = next_call_no++; + + if (scan_call_details(call)) { + calls.push_back(call); + } else { + delete call; + } +} + +Call *Parser::scan_leave(void) { + unsigned call_no = read_uint(); + Call *call = NULL; + for (CallList::iterator it = calls.begin(); it != calls.end(); ++it) { + if ((*it)->no == call_no) { + call = *it; + calls.erase(it); + break; + } + } + if (!call) { + return NULL; + } + + if (scan_call_details(call)) { + return call; + } else { + delete call; + return NULL; + } +} + +bool Parser::scan_call_details(Call *call) { + do { + int c = read_byte(); + switch(c) { + case Trace::CALL_END: + return true; + case Trace::CALL_ARG: + scan_arg(call); + break; + case Trace::CALL_RET: + scan_value(); + break; + default: + std::cerr << "error: ("<name()<< ") unknown call detail " + << c << "\n"; + exit(1); + case -1: + return false; + } + } while(true); +} + +void Parser::scan_arg(Call *call) { + skip_uint(); /* index */ + scan_value(); /* value */ +} + + +void Parser::scan_value(void) { + int c = read_byte(); + switch(c) { + case Trace::TYPE_NULL: + case Trace::TYPE_FALSE: + case Trace::TYPE_TRUE: + break; + case Trace::TYPE_SINT: + scan_sint(); + break; + case Trace::TYPE_UINT: + scan_uint(); + break; + case Trace::TYPE_FLOAT: + scan_float(); + break; + case Trace::TYPE_DOUBLE: + scan_double(); + break; + case Trace::TYPE_STRING: + scan_string(); + break; + case Trace::TYPE_ENUM: + scan_enum(); + break; + case Trace::TYPE_BITMASK: + scan_bitmask(); + break; + case Trace::TYPE_ARRAY: + scan_array(); + break; + case Trace::TYPE_STRUCT: + scan_struct(); + break; + case Trace::TYPE_BLOB: + scan_blob(); + break; + case Trace::TYPE_OPAQUE: + scan_opaque(); + break; + default: + std::cerr << "error: unknown type " << c << "\n"; + exit(1); + case -1: + break; + } +} + + +void Parser::scan_sint() { + skip_uint(); +} + + +void Parser::scan_uint() { + skip_uint(); +} + + +void Parser::scan_float() { + file->skip(sizeof(float)); +} + + +void Parser::scan_double() { + file->skip(sizeof(double)); +} + + +void Parser::scan_string() { + skip_string(); +} + + +void Parser::scan_enum() { + size_t id = read_uint(); + EnumSig *sig = lookup(enums, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new EnumSig; + sig->id = id; + sig->name = read_string(); + Value *value = parse_value(); + sig->value = value->toSInt(); + delete value; + enums[id] = sig; + m_enumSigOffsets.insert(offset); + } + assert(sig); +} + + +void Parser::scan_bitmask() { + size_t id = read_uint(); + BitmaskSig *sig = lookup(bitmasks, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new BitmaskSig; + sig->id = id; + sig->num_flags = read_uint(); + BitmaskFlag *flags = new BitmaskFlag[sig->num_flags]; + for (BitmaskFlag *it = flags; it != flags + sig->num_flags; ++it) { + it->name = read_string(); + it->value = read_uint(); + if (it->value == 0 && it != flags) { + std::cerr << "warning: bitmask " << it->name << " is zero but is not first flag\n"; + } + } + sig->flags = flags; + bitmasks[id] = sig; + m_bitmaskSigOffsets.insert(offset); + } + assert(sig); + + skip_uint(); /* value */ +} + + +void Parser::scan_array(void) { + size_t len = read_uint(); + for (size_t i = 0; i < len; ++i) { + scan_value(); + } +} + + +void Parser::scan_blob(void) { + size_t size = read_uint(); + if (size) { + file->skip((unsigned)size); + } +} + + +void Parser::scan_struct() { + size_t id = read_uint(); + + StructSig *sig = lookup(structs, id); + const File::Offset offset = file->currentOffset(); + if (!sig) { + sig = new StructSig; + sig->id = id; + sig->name = read_string(); + sig->num_members = read_uint(); + const char **member_names = new const char *[sig->num_members]; + for (unsigned i = 0; i < sig->num_members; ++i) { + member_names[i] = read_string(); + } + sig->member_names = member_names; + structs[id] = sig; + m_structSigOffsets.insert(offset); + } + assert(sig); + + for (size_t i = 0; i < sig->num_members; ++i) { + scan_value(); + } +} + + +void Parser::scan_opaque() { + skip_uint(); +} + + +void Parser::skip_string(void) { + size_t len = read_uint(); + file->skip((unsigned)len); +} + + +void Parser::skip_uint(void) { + int c; + do { + c = file->getc(); + if (c == -1) { + break; + } + } while(c & 0x80); +} + + +inline void Parser::skip_byte(void) { + file->skip(1); +} + + } /* namespace Trace */ diff --git a/trace_parser.hpp b/trace_parser.hpp index 4fff9ad..15b0ccb 100644 --- a/trace_parser.hpp +++ b/trace_parser.hpp @@ -29,15 +29,15 @@ #include #include +#include +#include "trace_file.hpp" #include "trace_format.hpp" #include "trace_model.hpp" namespace Trace { -class File; - class Parser { protected: @@ -58,6 +58,17 @@ protected: typedef std::vector BitmaskMap; BitmaskMap bitmasks; + typedef std::set TraceOffsets; + TraceOffsets m_callSigOffsets; + TraceOffsets m_structSigOffsets; + TraceOffsets m_enumSigOffsets; + TraceOffsets m_bitmaskSigOffsets; + + typedef std::map CallNumOffsets; + CallNumOffsets m_callNumOffsets; + + bool m_supportsSeeking; + unsigned next_call_no; public: @@ -73,6 +84,43 @@ public: Call *parse_call(void); + bool supportsOffsets() const + { + return file->supportsOffsets(); + } + + File::Offset currentOffset() + { + return file->currentOffset(); + } + + void setCurrentOffset(const File::Offset &offset) + { + file->setCurrentOffset(offset); + } + + bool callWithSignature(const File::Offset &offset) const; + bool structWithSignature(const File::Offset &offset) const; + bool enumWithSignature(const File::Offset &offset) const; + bool bitmaskWithSignature(const File::Offset &offset) const; + + unsigned currentCallNumber() const + { + return next_call_no; + } + + void setCurrentCallNumber(unsigned num) + { + next_call_no = num; + } + + int percentRead() + { + return file->percentRead(); + } + + Call *scan_call(); + protected: void parse_enter(void); @@ -111,6 +159,45 @@ protected: unsigned long long read_uint(void); inline int read_byte(void); + +protected: + void scan_enter(void); + + Call *scan_leave(void); + + bool scan_call_details(Call *call); + + void scan_arg(Call *call); + + void scan_value(void); + + void scan_sint(); + + void scan_uint(); + + void scan_float(); + + void scan_double(); + + void scan_string(); + + void scan_enum(); + + void scan_bitmask(); + + void scan_array(void); + + void scan_blob(void); + + void scan_struct(); + + void scan_opaque(); + + void skip_string(void); + + void skip_uint(void); + + inline void skip_byte(void); }; diff --git a/trace_snappyfile.cpp b/trace_snappyfile.cpp index 6a60441..4dbe42d 100644 --- a/trace_snappyfile.cpp +++ b/trace_snappyfile.cpp @@ -28,6 +28,8 @@ #include +#include + #include #include @@ -91,6 +93,10 @@ bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode) //read in the initial buffer if we're reading if (m_stream.is_open() && mode == File::Read) { + m_stream.seekg(0, std::ios::end); + m_endPos = m_stream.tellg(); + m_stream.seekg(0, std::ios::beg); + // read the snappy file identifier unsigned char byte1, byte2; m_stream >> byte1; @@ -209,9 +215,10 @@ void SnappyFile::flushWriteCache() assert(m_cachePtr == m_cache); } -void SnappyFile::flushReadCache() +void SnappyFile::flushReadCache(size_t skipLength) { //assert(m_cachePtr == m_cache + m_cacheSize); + m_currentOffset.chunk = m_stream.tellg(); size_t compressedLength; compressedLength = readCompressedLength(); @@ -220,8 +227,10 @@ void SnappyFile::flushReadCache() ::snappy::GetUncompressedLength(m_compressedCache, compressedLength, &m_cacheSize); createCache(m_cacheSize); - ::snappy::RawUncompress(m_compressedCache, compressedLength, - m_cache); + if (skipLength < m_cacheSize) { + ::snappy::RawUncompress(m_compressedCache, compressedLength, + m_cache); + } } else { createCache(0); } @@ -271,3 +280,59 @@ size_t SnappyFile::readCompressedLength() } return length; } + +bool SnappyFile::supportsOffsets() const +{ + return true; +} + +File::Offset SnappyFile::currentOffset() +{ + m_currentOffset.offsetInChunk = m_cachePtr - m_cache; + return m_currentOffset; +} + +void SnappyFile::setCurrentOffset(const File::Offset &offset) +{ + // to remove eof bit + m_stream.clear(); + // seek to the start of a chunk + m_stream.seekg(offset.chunk, std::ios::beg); + // load the chunk + flushReadCache(); + assert(m_cacheSize >= offset.offsetInChunk); + // seek within our cache to the correct location within the chunk + m_cachePtr = m_cache + offset.offsetInChunk; + +} + +bool SnappyFile::rawSkip(size_t length) +{ + if (endOfData()) { + return false; + } + + if (freeCacheSize() >= length) { + m_cachePtr += length; + } else { + size_t sizeToRead = length; + while (sizeToRead) { + size_t chunkSize = std::min(freeCacheSize(), sizeToRead); + m_cachePtr += chunkSize; + sizeToRead -= chunkSize; + if (sizeToRead > 0) { + flushReadCache(sizeToRead); + } + if (!m_cacheSize) { + break; + } + } + } + + return true; +} + +int SnappyFile::rawPercentRead() +{ + return 100 * (double(m_stream.tellg()) / double(m_endPos)); +} diff --git a/trace_snappyfile.hpp b/trace_snappyfile.hpp index b807bfb..33159ec 100644 --- a/trace_snappyfile.hpp +++ b/trace_snappyfile.hpp @@ -52,6 +52,9 @@ public: File::Mode mode = File::Read); virtual ~SnappyFile(); + virtual bool supportsOffsets() const; + virtual File::Offset currentOffset(); + virtual void setCurrentOffset(const File::Offset &offset); protected: virtual bool rawOpen(const std::string &filename, File::Mode mode); virtual bool rawWrite(const void *buffer, size_t length); @@ -59,6 +62,8 @@ protected: virtual int rawGetc(); virtual void rawClose(); virtual void rawFlush(); + virtual bool rawSkip(size_t length); + virtual int rawPercentRead(); private: inline size_t usedCacheSize() const @@ -80,7 +85,7 @@ private: return m_stream.eof() && freeCacheSize() == 0; } void flushWriteCache(); - void flushReadCache(); + void flushReadCache(size_t skipLength = 0); void createCache(size_t size); void writeCompressedLength(size_t length); size_t readCompressedLength(); @@ -91,6 +96,9 @@ private: size_t m_cacheSize; char *m_compressedCache; + + File::Offset m_currentOffset; + std::streampos m_endPos; }; }