trace_writer.cpp
trace_local_writer.cpp
trace_model_writer.cpp
+ trace_loader.cpp
image.cpp
image_bmp.cpp
image_pnm.cpp
add_executable (tracedump tracedump.cpp)
install (TARGETS tracedump RUNTIME DESTINATION bin)
+add_executable (loadertest loadertest.cpp)
+install (TARGETS loadertest RUNTIME DESTINATION bin)
##############################################################################
# API tracers
glsledit.cpp
imageviewer.cpp
jumpwidget.cpp
- loaderthread.cpp
mainwindow.cpp
main.cpp
retracer.cpp
settingsdialog.cpp
shaderssourcewidget.cpp
tracedialog.cpp
+ traceloader.cpp
traceprocess.cpp
vertexdatainterpreter.cpp
)
#include "apitrace.h"
-#include "loaderthread.h"
+#include "traceloader.h"
#include "saverthread.h"
#include <QDir>
+#include <QThread>
ApiTrace::ApiTrace()
: m_frameMarker(ApiTrace::FrameMarker_SwapBuffers),
m_needsSaving(false)
{
- m_loader = new LoaderThread(this);
- connect(m_loader, SIGNAL(parsedFrames(const QList<ApiTraceFrame*>)),
+ m_loader = new TraceLoader();
+ connect(this, SIGNAL(loadTrace(QString)),
+ m_loader, SLOT(loadTrace(QString)));
+ connect(m_loader, SIGNAL(framesLoaded(const QList<ApiTraceFrame*>)),
this, SLOT(addFrames(const QList<ApiTraceFrame*>)));
- connect(m_loader, SIGNAL(started()),
+ connect(m_loader, SIGNAL(frameLoaded(int,QVector<ApiTraceCall*>,quint64)),
+ this, SLOT(fillFrame(int,QVector<ApiTraceCall*>,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;
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();
m_needsSaving = false;
emit invalidated();
- m_loader->loadFile(m_fileName);
+// m_loader->loadTrace(m_fileName);
+ emit loadTrace(m_fileName);
}
}
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();
}
if (!currentFrame) {
currentFrame = new ApiTraceFrame(this);
currentFrame->number = m_frames.count();
+ currentFrame->setLoaded(true);
}
apiCall->setParentFrame(currentFrame);
currentFrame->addCall(apiCall);
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<ApiTraceCall *> &calls,
+ quint64 binaryDataSize)
{
- m_enumSignatures[id] = signature;
}
#include "apitrace.moc"
#include <QObject>
#include <QSet>
-class LoaderThread;
+class TraceLoader;
class SaverThread;
+class QThread;
class ApiTrace : public QObject
{
ApiTraceState defaultState() const;
- ApiTraceCallSignature *signature(unsigned id);
- void addSignature(unsigned id, ApiTraceCallSignature *signature);
-
- ApiTraceEnumSignature *enumSignature(unsigned id);
- void addEnumSignature(unsigned id, ApiTraceEnumSignature *signature);
-
-
QVector<ApiTraceCall*> calls() const;
ApiTraceCall *callAt(int idx) const;
ApiTraceCall *callWithIndex(int idx) const;
void save();
signals:
+ void loadTrace(const QString &name);
void startedLoadingTrace();
+ void loaded(int percent);
void finishedLoadingTrace();
void invalidated();
void framesInvalidated();
private slots:
void addFrames(const QList<ApiTraceFrame*> &frames);
+ void fillFrame(int frameIdx, const QVector<ApiTraceCall*> &calls,
+ quint64 binaryDataSize);
void slotSaved();
private:
void detectFrames();
FrameMarker m_frameMarker;
- LoaderThread *m_loader;
+ TraceLoader *m_loader;
+ QThread *m_loaderThread;
SaverThread *m_saver;
QSet<ApiTraceCall*> m_editedCalls;
bool m_needsSaving;
QSet<ApiTraceCall*> m_errors;
- QVector<ApiTraceCallSignature*> m_signatures;
- QVector<ApiTraceEnumSignature*> m_enumSignatures;
};
#endif
#include "apitracecall.h"
#include "apitrace.h"
+#include "traceloader.h"
#include "trace_model.hpp"
#include <QDebug>
{
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);
}
}
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);
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) {
ApiTraceFrame::ApiTraceFrame(ApiTrace *parentTrace)
: ApiTraceEvent(ApiTraceEvent::Frame),
m_parentTrace(parentTrace),
- m_binaryDataSize(0)
+ m_binaryDataSize(0),
+ m_loaded(false),
+ m_callsToLoad(0)
{
}
int ApiTraceFrame::numChildren() const
{
- return m_calls.count();
+ if (m_loaded) {
+ return m_calls.count();
+ } else {
+ return m_callsToLoad;
+ }
}
ApiTrace * ApiTraceFrame::parentTrace() const
{
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;
}
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);
return m_variant;
}
private:
- ApiTrace *m_trace;
+ TraceLoader *m_loader;
QVariant m_variant;
};
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;
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;
quint64 binaryDataSize);
int binaryDataSize() const;
+
+ bool loaded() const;
+ void setLoaded(bool l);
private:
ApiTrace *m_parentTrace;
quint64 m_binaryDataSize;
QVector<ApiTraceCall*> m_calls;
+ bool m_loaded;
+ unsigned m_callsToLoad;
};
Q_DECLARE_METATYPE(ApiTraceFrame*);
#include "apitracemodel.h"
#include "apitracecall.h"
-#include "loaderthread.h"
+#include "traceloader.h"
#include "trace_parser.hpp"
#include <QDebug>
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();
{
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()),
statusBar()->showMessage( tr("Saved '%1'").arg(fileName), 5000);
}
+void MainWindow::loadProgess(int percent)
+{
+ m_progressBar->setValue(percent);
+}
+
#include "mainwindow.moc"
void replayStateFound(ApiTraceState *state);
void replayError(const QString &msg);
void startedLoadingTrace();
+ void loadProgess(int percent);
void finishedLoadingTrace();
void lookupState();
void showSettings();
--- /dev/null
+#include "traceloader.h"
+
+#include <QDebug>
+#include <QFile>
+
+#define FRAMES_TO_CACHE 100
+
+static ApiTraceCall *
+apiCallFromTraceCall(const Trace::Call *call,
+ const QHash<QString, QUrl> &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 "<<filename;
+ emit startedParsing();
+
+ qDebug() <<"\t support offsets = "<<m_parser.supportsOffsets();
+ 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<Trace::Call*> 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 = "<<function<<", url = "<<url.toString();
+ m_helpHash.insert(function, url);
+ }
+ } else {
+ qWarning() << "Couldn't open reference file "
+ << file.fileName();
+ }
+ file.close();
+}
+
+void TraceLoader::scanTrace()
+{
+ QList<ApiTraceFrame*> 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<ApiTraceFrame*> frames;
+ ApiTraceFrame *currentFrame = 0;
+ int frameCount = 0;
+ QVector<ApiTraceCall*> 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"
--- /dev/null
+#ifndef TRACELOADER_H
+#define TRACELOADER_H
+
+
+#include "apitrace.h"
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <QObject>
+#include <QList>
+#include <QMap>
+
+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<ApiTraceFrame*> &frames);
+ void frameLoaded(int frameIdx,
+ const QVector<ApiTraceCall*> &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<int, FrameOffset> FrameOffsets;
+ FrameOffsets m_frameOffsets;
+
+ QHash<QString, QUrl> m_helpHash;
+
+ QVector<ApiTraceCallSignature*> m_signatures;
+ QVector<ApiTraceEnumSignature*> m_enumSignatures;
+};
+
+#endif
--- /dev/null
+#include "trace_loader.hpp"
+#include "os.hpp"
+
+#include <iostream>
+
+
+static const double msecsInSec = 1000000;
+
+static void timeFrameFetch(Trace::Loader &loader, unsigned frameIdx)
+{
+ long long t1, t2;
+ std::vector<Trace::Call*> 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 "<<std::endl;
+}
+
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; ++i) {
+ Trace::Loader loader;
+
+ long long t1 = OS::GetTime();
+ if (!loader.open(argv[i])) {
+ std::cerr << "error: failed to open " << argv[i] << "\n";
+ return 1;
+ }
+ long long t2 = OS::GetTime();
+ std::cout << "Time to scan file = "<< (t2 - t1)/msecsInSec
+ << " secs "<<std::endl;
+
+ std::cout << "Number of frames = "
+ << loader.numberOfFrames()
+ << std::endl;
+ std::cout << "Number of calls in frame 0 = "
+ << loader.numberOfCallsInFrame(0)
+ << std::endl;
+ int lastFrame = loader.numberOfFrames() - 1;
+ std::cout << "Number of calls in frame "
+ << lastFrame << " = "
+ << loader.numberOfCallsInFrame(lastFrame)
+ << std::endl;
+
+ unsigned biggestFrameIdx = 0;
+ unsigned maxFrameSize = 0;
+ for (unsigned i = 0; i < loader.numberOfFrames(); ++i) {
+ if (loader.numberOfCallsInFrame(i) > maxFrameSize) {
+ maxFrameSize = loader.numberOfCallsInFrame(i);
+ biggestFrameIdx = i;
+ }
+ }
+
+ timeFrameFetch(loader, loader.numberOfFrames()/2);
+ timeFrameFetch(loader, 0);
+ timeFrameFetch(loader, loader.numberOfFrames() - 1);
+ timeFrameFetch(loader, biggestFrameIdx);
+ }
+
+ return 0;
+}
+
close();
}
+
+File::Offset File::currentOffset()
+{
+ return File::Offset();
+}
+
+void File::setCurrentOffset(const File::Offset &offset)
+{
+}
+
bool File::isZLibCompressed(const std::string &filename)
{
std::fstream stream(filename.c_str(),
return (byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
}
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+} gz_dummy_stream;
ZLibFile::ZLibFile(const std::string &filename,
File::Mode mode)
{
m_gzFile = gzopen(filename.c_str(),
(mode == File::Write) ? "wb" : "rb");
+
+ if (mode == File::Read && m_gzFile) {
+ //XXX: unfortunately zlib doesn't support
+ // SEEK_END or we could've done:
+ //m_endOffset = gzseek(m_gzFile, 0, SEEK_END);
+ //gzrewind(m_gzFile);
+ gz_dummy_stream *stream = (gz_dummy_stream *)m_gzFile;
+ long loc = ftell(stream->file);
+ fseek(stream->file,0,SEEK_END);
+ m_endOffset = ftell(stream->file);
+ fseek(stream->file, loc, SEEK_SET);
+ }
+
return m_gzFile != NULL;
}
{
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);
+}
#include <string>
#include <fstream>
+#include <stdint.h>
namespace Trace {
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);
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;
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;
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) {
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);
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
--- /dev/null
+#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: " <<filename<< " doesn't support seeking "
+ << "\n";
+ return false;
+ }
+
+ Trace::Call *call;
+ 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)) {
+ File::Offset endOffset = m_parser.currentOffset();
+ FrameOffset frameOffset(startOffset);
+ frameOffset.numberOfCalls = numOfCalls;
+ frameOffset.callNumber = callNum;
+
+ m_frameOffsets[numOfFrames] = frameOffset;
+ ++numOfFrames;
+
+ if (m_parser.percentRead() - lastPercentReport >= 5) {
+ std::cerr << "\tPercent scanned = "
+ << m_parser.percentRead()
+ << "..."<<std::endl;
+ lastPercentReport = m_parser.percentRead();
+ }
+ startOffset = endOffset;
+ callNum = m_parser.currentCallNumber();
+ numOfCalls = 0;
+ }
+ //call->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<Trace::Call *> Loader::frame(int idx)
+{
+ int numOfCalls = numberOfCallsInFrame(idx);
+ if (numOfCalls) {
+ const FrameOffset &frameOffset = m_frameOffsets[idx];
+ std::vector<Trace::Call*> 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<Trace::Call*>();
+}
--- /dev/null
+#ifndef TRACE_LOADER_HPP
+#define TRACE_LOADER_HPP
+
+#include "trace_file.hpp"
+#include "trace_parser.hpp"
+
+#include <string>
+#include <map>
+#include <queue>
+#include <vector>
+
+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<Trace::Call*> 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<int, FrameOffset> FrameOffsets;
+ FrameOffsets m_frameOffsets;
+};
+
+}
+
+#endif // TRACE_LOADER_HPP
file = NULL;
next_call_no = 0;
version = 0;
+ m_supportsSeeking = false;
}
if (!file->open(filename, File::Read)) {
return false;
}
+ m_supportsSeeking = file->supportsOffsets();
version = read_uint();
if (version > TRACE_VERSION) {
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)) {
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);
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);
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);
}
+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: ("<<call->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 */
#include <iostream>
#include <list>
+#include <set>
+#include "trace_file.hpp"
#include "trace_format.hpp"
#include "trace_model.hpp"
namespace Trace {
-class File;
-
class Parser
{
protected:
typedef std::vector<BitmaskSig *> BitmaskMap;
BitmaskMap bitmasks;
+ typedef std::set<File::Offset> TraceOffsets;
+ TraceOffsets m_callSigOffsets;
+ TraceOffsets m_structSigOffsets;
+ TraceOffsets m_enumSigOffsets;
+ TraceOffsets m_bitmaskSigOffsets;
+
+ typedef std::map<File::Offset, unsigned> CallNumOffsets;
+ CallNumOffsets m_callNumOffsets;
+
+ bool m_supportsSeeking;
+
unsigned next_call_no;
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);
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);
};
#include <snappy.h>
+#include <iostream>
+
#include <assert.h>
#include <string.h>
//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;
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();
::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);
}
}
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));
+}
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);
virtual int rawGetc();
virtual void rawClose();
virtual void rawFlush();
+ virtual bool rawSkip(size_t length);
+ virtual int rawPercentRead();
private:
inline size_t usedCacheSize() const
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();
size_t m_cacheSize;
char *m_compressedCache;
+
+ File::Offset m_currentOffset;
+ std::streampos m_endPos;
};
}