]> git.cworth.org Git - apitrace/commitdiff
Merge remote-tracking branch 'origin/master' into on-demand-loading
authorZack Rusin <zack@kde.org>
Fri, 2 Sep 2011 20:02:59 +0000 (16:02 -0400)
committerZack Rusin <zack@kde.org>
Fri, 2 Sep 2011 20:02:59 +0000 (16:02 -0400)
CMakeLists.txt
loadertest.cpp [new file with mode: 0644]
trace_file.cpp
trace_file.hpp
trace_loader.cpp [new file with mode: 0644]
trace_loader.hpp [new file with mode: 0644]
trace_parser.cpp
trace_parser.hpp
trace_snappyfile.cpp
trace_snappyfile.hpp

index e840f21d193608b386d33edf84f72ea3511e1ea9..2ee433a51dd1814eb0f518f22139c0fba416b351 100755 (executable)
@@ -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/loadertest.cpp b/loadertest.cpp
new file mode 100644 (file)
index 0000000..1b560a3
--- /dev/null
@@ -0,0 +1,68 @@
+#include "trace_loader.hpp"
+#include "os.hpp"
+
+#include <iostream>
+
+int main(int argc, char **argv)
+{
+    int i;
+
+    for (i = 1; i < argc; ++i) {
+        Trace::Loader loader;
+        const double msecsInSec = 1000000;
+
+        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;
+
+        t1 = OS::GetTime();
+        std::vector<Trace::Call*> frame = loader.frame(
+            loader.numberOfFrames()/2);
+        t2 = OS::GetTime();
+        std::cout << "Time to fetch a frame size "
+                  << frame.size()
+                  << " is = "
+                  << (t2 - t1)/msecsInSec
+                  << " secs "<<std::endl;
+
+        t1 = OS::GetTime();
+        frame = loader.frame(
+            0);
+        t2 = OS::GetTime();
+        std::cout << "Time to fetch a frame size "
+                  << frame.size()
+                  << " is = "
+                  << (t2 - t1)/msecsInSec
+                  << " secs "<<std::endl;
+
+        t1 = OS::GetTime();
+        frame = loader.frame(loader.numberOfFrames() - 1);
+        t2 = OS::GetTime();
+        std::cout << "Time to fetch a frame size "
+                  << frame.size()
+                  << " is = "
+                  << (t2 - t1)/msecsInSec
+                  << " secs "<<std::endl;
+
+    }
+
+    return 0;
+}
+
index 81b5d03c1f3f273f972f7b8b3d9db8be22f53336..2d002868920feda1d7c2d48438bd8af5e88b8351 100644 (file)
@@ -56,6 +56,16 @@ File::~File()
     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(),
@@ -133,3 +143,14 @@ void ZLibFile::rawFlush()
 {
     gzflush(m_gzFile, Z_SYNC_FLUSH);
 }
+
+
+bool ZLibFile::supportsOffsets() const
+{
+    return false;
+}
+
+bool ZLibFile::rawSkip(unsigned)
+{
+    return false;
+}
index c709050d6ab96371a957a818bddffc52389951d4..487121187fdd9dad368fe631445b3ffea218a80e 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <string>
 #include <fstream>
+#include <stdint.h>
 
 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,11 @@ public:
     void close();
     void flush(void);
     int getc();
+    bool skip(unsigned length);
 
+    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 +79,7 @@ protected:
     virtual int rawGetc() = 0;
     virtual void rawClose() = 0;
     virtual void rawFlush() = 0;
+    virtual bool rawSkip(unsigned length) = 0;
 
 protected:
     std::string m_filename;
@@ -135,12 +150,22 @@ inline int File::getc()
     return rawGetc();
 }
 
+inline bool File::skip(unsigned 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);
@@ -148,10 +173,45 @@ protected:
     virtual int rawGetc();
     virtual void rawClose();
     virtual void rawFlush();
+    virtual bool rawSkip(unsigned length);
 private:
     void *m_gzFile;
 };
 
+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 (file)
index 0000000..08066a9
--- /dev/null
@@ -0,0 +1,139 @@
+#include "trace_loader.hpp"
+
+#include "trace_snappyfile.hpp"
+
+using namespace Trace;
+
+Loader::Loader()
+    : m_frameMarker(FrameMarker_SwapBuffers),
+      file(0)
+{
+}
+
+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;
+
+    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;
+
+            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*>();
+}
diff --git a/trace_loader.hpp b/trace_loader.hpp
new file mode 100644 (file)
index 0000000..2656700
--- /dev/null
@@ -0,0 +1,71 @@
+#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;
+
+    std::map<int, Trace::Frame*> m_frameCache;
+    std::queue<Trace::Frame*> m_loadedFrames;
+
+    typedef std::map<int, FrameOffset> FrameOffsets;
+    FrameOffsets m_frameOffsets;
+
+    Trace::File *file;
+};
+
+}
+
+#endif // TRACE_LOADER_HPP
index 44d1786ac207fe2fa576a88c9cfae90339013fdc..95dbec50d8da620e972d49663066f1277ccc5d73 100644 (file)
@@ -146,21 +146,35 @@ 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();
+    const File::Offset offset = file->currentOffset();
+    bool 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;
+            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 +336,22 @@ 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;
+    const File::Offset offset = file->currentOffset();
+    bool 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;
+            m_enumSigOffsets.insert(offset);
+        } else {
+            skip_string(); /*name*/
+            scan_value();
+        }
     }
     assert(sig);
     return new Enum(sig);
@@ -339,20 +361,31 @@ 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";
+    const File::Offset offset = file->currentOffset();
+    bool 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;
+            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 +419,28 @@ 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();
+    const File::Offset offset = file->currentOffset();
+    bool 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;
+            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 +506,314 @@ 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()
+{
+    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 */
index 4fff9ad1157129e0da8458f8cca87e68687197ec..1f87b6fed185c8959dd112a2aa4d2c3dce99f702 100644 (file)
 
 #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:
@@ -58,6 +58,15 @@ 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;
+
     unsigned next_call_no;
 
 public:
@@ -73,6 +82,38 @@ 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;
+    }
+
+    Call *scan_call();
+
 protected:
     void parse_enter(void);
 
@@ -111,6 +152,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);
 };
 
 
index 7e7072543426851c125257d2c9d0b5e0367e3e86..c350013d7f1acc7e7ff1546fa860019f94d47762 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <snappy.h>
 
+#include <iostream>
+
 #include <assert.h>
 #include <string.h>
 
@@ -205,6 +207,7 @@ void SnappyFile::flushCache()
         assert(m_cachePtr == m_cache);
     } else if (m_mode == File::Read) {
         //assert(m_cachePtr == m_cache + m_cacheSize);
+        m_currentOffset.chunk = m_stream.tellg();
         size_t compressedLength;
         compressedLength = readCompressedLength();
 
@@ -265,3 +268,52 @@ 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
+    flushCache();
+    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(unsigned length)
+{
+    if (endOfData()) {
+        return false;
+    }
+
+    if (freeCacheSize() >= length) {
+        m_cachePtr += length;
+    } else {
+        int sizeToRead = length;
+        while (sizeToRead) {
+            int chunkSize = std::min(freeCacheSize(), sizeToRead);
+            m_cachePtr += chunkSize;
+            sizeToRead -= chunkSize;
+            if (sizeToRead > 0)
+                flushCache();
+            if (!m_cacheSize)
+                break;
+        }
+    }
+
+    return true;
+}
index 61b7ab1b29435aeeb51c833a05958c82f3bcee32..398ff7900c335a4c7f3b55d8afe0e643c5651e49 100644 (file)
@@ -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,7 @@ protected:
     virtual int rawGetc();
     virtual void rawClose();
     virtual void rawFlush();
+    virtual bool rawSkip(unsigned length);
 
 private:
     inline size_t usedCacheSize() const
@@ -90,6 +94,8 @@ private:
     size_t m_cacheSize;
 
     char *m_compressedCache;
+
+    File::Offset m_currentOffset;
 };
 
 }