]> git.cworth.org Git - apitrace/commitdiff
Trace enum signatures as a whole.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Sun, 11 Dec 2011 10:33:55 +0000 (10:33 +0000)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Sun, 11 Dec 2011 10:33:55 +0000 (10:33 +0000)
common/trace_format.hpp
common/trace_model.cpp
common/trace_model.hpp
common/trace_parser.cpp
common/trace_parser.hpp
common/trace_writer.cpp
common/trace_writer.hpp
common/trace_writer_model.cpp
gui/apitracecall.cpp
gui/apitracecall.h
trace.py

index 2a1150c746a63e8fbf668c82918402f52014ecfa..5aade00361f4c70d6a6ddb814f30debc355cc271 100644 (file)
 /*
  * Trace binary format.
  *
+ * This file defines the trace binary stream, which is then compressed by
+ * snappy or gzip.
+ */
+
+#ifndef _TRACE_FORMAT_HPP_
+#define _TRACE_FORMAT_HPP_
+
+namespace trace {
+
+/*
+ * Trace file version number.
+ *
+ * We keep backwards compatability reading old traces, i.e., it should always be
+ * possible to parse and retrace old trace files.
+ *
+ * So the trace version number refers not only to changes in the binary format
+ * representation, but also semantic changes in the way certain functions
+ * should be retraced.
+ *
+ * Writing/editing old traces will not be supported however.  An older version
+ * of apitrace should be used in such circunstances.
+ *
+ * Changelog:
+ *
+ * - version 0:
+ *   - initial implementation
+ *
+ * - version 1:
+ *   - support for GL user arrays -- a blob is provided whenever an user memory
+ *   is referred (whereas before calls that operate wit user memory instead of
+ *   VBOs should be ignore)
+ *
+ * - version 2:
+ *   - malloc/free memory calls -- allow to pass user memory as malloc memory
+ *   as opposed to blobs
+ *   - glFlushMappedBufferRange will emit a memcpy only for the flushed range
+ *   (whereas previously it would emit a memcpy for the whole mapped range)
+ *
+ * - version 3:
+ *   - enums signatures are recorded for the a whole set of values (not as individual values)
+ */
+#define TRACE_VERSION 3
+
+
+/*
  * Grammar:
  *
  *   trace = event* EOF
  *   call_sig = id name arg_name*
  *            | id
  *
- *   enum_sig = id name value
+ *   enum_sig = id count (name value)+
  *            | id
  *
  *   bitmask_sig = id count (name value)+
  *
  */
 
-#ifndef _TRACE_FORMAT_HPP_
-#define _TRACE_FORMAT_HPP_
-
-namespace trace {
-
-/*
- * Trace file version number.
- *
- * We keep backwards compatability reading old traces, i.e., it should always be
- * possible to parse and retrace old trace files.
- *
- * So the trace version number refers not only to changes in the binary format
- * representation, but also semantic changes in the way certain functions
- * should be retraced.
- *
- * Writing/editing old traces will not be supported however.  An older version
- * of apitrace should be used in such circunstances.
- *
- * Changelog:
- *
- * - version 0:
- *   - initial implementation
- *
- * - version 1:
- *   - support for GL user arrays -- a blob is provided whenever an user memory
- *   is referred (whereas before calls that operate wit user memory instead of
- *   VBOs should be ignore)
- *
- * - version 2:
- *   - malloc/free memory calls -- allow to pass user memory as malloc memory
- *   as opposed to blobs
- *   - glFlushMappedBufferRange will emit a memcpy only for the flushed range
- *   (whereas previously it would emit a memcpy for the whole mapped range)
- */
-#define TRACE_VERSION 2
 
 enum Event {
     EVENT_ENTER = 0,
index 89a191d9a0168f4aac38dbe0041ff35741140203..2ceb81074a846ce494951b10918fb14f840aa034 100644 (file)
@@ -82,7 +82,6 @@ bool UInt   ::toBool(void) const { return value != 0; }
 bool Float  ::toBool(void) const { return value != 0; }
 bool Double ::toBool(void) const { return value != 0; }
 bool String ::toBool(void) const { return true; }
-bool Enum   ::toBool(void) const { return sig->value != 0; }
 bool Struct ::toBool(void) const { return true; }
 bool Array  ::toBool(void) const { return true; }
 bool Blob   ::toBool(void) const { return true; }
@@ -97,7 +96,6 @@ signed long long SInt   ::toSInt(void) const { return value; }
 signed long long UInt   ::toSInt(void) const { assert(static_cast<signed long long>(value) >= 0); return static_cast<signed long long>(value); }
 signed long long Float  ::toSInt(void) const { return static_cast<signed long long>(value); }
 signed long long Double ::toSInt(void) const { return static_cast<signed long long>(value); }
-signed long long Enum   ::toSInt(void) const { return sig->value; }
 
 
 // unsigned integer cast
@@ -108,7 +106,6 @@ unsigned long long SInt   ::toUInt(void) const { assert(value >= 0); return stat
 unsigned long long UInt   ::toUInt(void) const { return value; }
 unsigned long long Float  ::toUInt(void) const { return static_cast<unsigned long long>(value); }
 unsigned long long Double ::toUInt(void) const { return static_cast<unsigned long long>(value); }
-unsigned long long Enum   ::toUInt(void) const { assert(sig->value >= 0); return sig->value; }
 
 
 // floating point cast
@@ -119,7 +116,6 @@ float SInt   ::toFloat(void) const { return static_cast<float>(value); }
 float UInt   ::toFloat(void) const { return static_cast<float>(value); }
 float Float  ::toFloat(void) const { return value; }
 float Double ::toFloat(void) const { return value; }
-float Enum   ::toFloat(void) const { return static_cast<float>(sig->value); }
 
 
 // floating point cast
@@ -130,7 +126,6 @@ double SInt   ::toDouble(void) const { return static_cast<double>(value); }
 double UInt   ::toDouble(void) const { return static_cast<double>(value); }
 double Float  ::toDouble(void) const { return value; }
 double Double ::toDouble(void) const { return value; }
-double Enum   ::toDouble(void) const { return static_cast<double>(sig->value); }
 
 
 // pointer cast
@@ -281,7 +276,14 @@ public:
     }
 
     void visit(Enum *node) {
-        os << literal << node->sig->name << normal;
+        const EnumSig *sig = node->sig;
+        for (const EnumValue *it = sig->values; it != sig->values + sig->num_values; ++it) {
+            if (it->value == node->value) {
+                os << literal << it->name << normal;
+                return;
+            }
+        }
+        os << literal << node->value << normal;
     }
 
     void visit(Bitmask *bitmask) {
index f208032d371eeb1e38d4704c07dc342203b88931..1b2e1f2c45a48ede154195544ff271803e0f444a 100644 (file)
@@ -60,13 +60,19 @@ struct StructSig {
 };
 
 
-struct EnumSig {
-    Id id;
+struct EnumValue {
     const char *name;
     signed long long value;
 };
 
 
+struct EnumSig {
+    Id id;
+    unsigned num_values;
+    const EnumValue *values;
+};
+
+
 struct BitmaskFlag {
     const char *name;
     unsigned long long value;
@@ -216,16 +222,11 @@ public:
 };
 
 
-class Enum : public Value
+class Enum : public SInt
 {
 public:
-    Enum(const EnumSig *_sig) : sig(_sig) {}
+    Enum(const EnumSig *_sig, signed long long _value) : SInt(_value), sig(_sig) {}
 
-    bool toBool(void) const;
-    signed long long toSInt(void) const;
-    unsigned long long toUInt(void) const;
-    virtual float toFloat(void) const;
-    virtual double toDouble(void) const;
     void visit(Visitor &visitor);
 
     const EnumSig *sig;
index 1a1139d0f05a68a9253cfe900dd2a603caa4f652..f3e623a3ed2dc7a54bf6729e560d51406a389d7a 100644 (file)
@@ -128,7 +128,10 @@ void Parser::close(void) {
     for (EnumMap::iterator it = enums.begin(); it != enums.end(); ++it) {
         EnumSigState *sig = *it;
         if (sig) {
-            delete [] sig->name;
+            for (unsigned value = 0; value < sig->num_values; ++value) {
+                delete [] sig->values[value].name;
+            }
+            delete [] sig->values;
             delete sig;
         }
     }
@@ -286,7 +289,13 @@ StructSig *Parser::parse_struct_sig() {
 }
 
 
-EnumSig *Parser::parse_enum_sig() {
+/*
+ * Old enum signatures would cover a single name/value only:
+ *
+ *   enum_sig = id name value
+ *            | id
+ */
+EnumSig *Parser::parse_old_enum_sig() {
     size_t id = read_uint();
 
     EnumSigState *sig = lookup(enums, id);
@@ -295,10 +304,11 @@ EnumSig *Parser::parse_enum_sig() {
         /* parse the signature */
         sig = new EnumSigState;
         sig->id = id;
-        sig->name = read_string();
-        Value *value = parse_value();
-        sig->value = value->toSInt();
-        delete value;
+        sig->num_values = 1;
+        EnumValue *values = new EnumValue[sig->num_values];
+        values->name = read_string();
+        values->value = read_sint();
+        sig->values = values;
         sig->offset = file->currentOffset();
         enums[id] = sig;
     } else if (file->currentOffset() < sig->offset) {
@@ -312,6 +322,38 @@ EnumSig *Parser::parse_enum_sig() {
 }
 
 
+EnumSig *Parser::parse_enum_sig() {
+    size_t id = read_uint();
+
+    EnumSigState *sig = lookup(enums, id);
+
+    if (!sig) {
+        /* parse the signature */
+        sig = new EnumSigState;
+        sig->id = id;
+        sig->num_values = read_uint();
+        EnumValue *values = new EnumValue[sig->num_values];
+        for (EnumValue *it = values; it != values + sig->num_values; ++it) {
+            it->name = read_string();
+            it->value = read_sint();
+        }
+        sig->values = values;
+        sig->offset = file->currentOffset();
+        enums[id] = sig;
+    } else if (file->currentOffset() < sig->offset) {
+        /* skip over the signature */
+        int num_values = read_uint();
+        for (int i = 0; i < num_values; ++i) {
+            skip_string(); /*name */
+            skip_sint(); /* value */
+        }
+    }
+
+    assert(sig);
+    return sig;
+}
+
+
 BitmaskSig *Parser::parse_bitmask_sig() {
     size_t id = read_uint();
 
@@ -602,13 +644,27 @@ void Parser::scan_string() {
 
 
 Value *Parser::parse_enum() {
-    EnumSig *sig = parse_enum_sig();
-    return new Enum(sig);
+    EnumSig *sig;
+    signed long long value;
+    if (version >= 3) {
+        sig = parse_enum_sig();
+        value = read_sint();
+    } else {
+        sig = parse_old_enum_sig();
+        assert(sig->num_values == 1);
+        value = sig->values->value;
+    }
+    return new Enum(sig, value);
 }
 
 
 void Parser::scan_enum() {
-    parse_enum_sig();
+    if (version >= 3) {
+        parse_enum_sig();
+        skip_sint();
+    } else {
+        parse_old_enum_sig();
+    }
 }
 
 
@@ -715,6 +771,33 @@ void Parser::skip_string(void) {
 }
 
 
+/*
+ * For the time being, a signed int is encoded as any other value, but we here parse
+ * it without the extra baggage of the Value class.
+ */
+signed long long
+Parser::read_sint(void) {
+    int c;
+    c = read_byte();
+    switch (c) {
+    case trace::TYPE_SINT:
+        return -read_uint();
+    case trace::TYPE_UINT:
+        return read_uint();
+    default:
+        std::cerr << "error: unexpected type " << c << "\n";
+        exit(1);
+    case -1:
+        return 0;
+    }
+}
+
+void
+Parser::skip_sint(void) {
+    skip_byte();
+    skip_uint();
+}
+
 unsigned long long Parser::read_uint(void) {
     unsigned long long value = 0;
     int c;
index 73bb7764d6cd05195622bccd7312f4110b97133d..d8c5915ea3d8e3976c1b2d38e33d8e8f57a21d53 100644 (file)
@@ -130,6 +130,7 @@ protected:
 
     FunctionSigFlags *parse_function_sig(void);
     StructSig *parse_struct_sig();
+    EnumSig *parse_old_enum_sig();
     EnumSig *parse_enum_sig();
     BitmaskSig *parse_bitmask_sig();
     
@@ -195,6 +196,9 @@ protected:
     const char * read_string(void);
     void skip_string(void);
 
+    signed long long read_sint(void);
+    void skip_sint(void);
+
     unsigned long long read_uint(void);
     void skip_uint(void);
 
index 897c7b159f346423b46a79876981ebf465b7c97c..1679989d6b11f3eed7da17ca61a6af5c3ceaea40 100644 (file)
@@ -258,14 +258,18 @@ void Writer::writeBlob(const void *data, size_t size) {
     }
 }
 
-void Writer::writeEnum(const EnumSig *sig) {
+void Writer::writeEnum(const EnumSig *sig, signed long long value) {
     _writeByte(trace::TYPE_ENUM);
     _writeUInt(sig->id);
     if (!lookup(enums, sig->id)) {
-        _writeString(sig->name);
-        Writer::writeSInt(sig->value);
+        _writeUInt(sig->num_values);
+        for (unsigned i = 0; i < sig->num_values; ++i) {
+            _writeString(sig->values[i].name);
+            writeSInt(sig->values[i].value);
+        }
         enums[sig->id] = true;
     }
+    writeSInt(value);
 }
 
 void Writer::writeBitmask(const BitmaskSig *sig, unsigned long long value) {
index 82c46b91b2ce31eeb336e2ee9a4a073fad6a4106..f89eb65ee99982ec50cd9353038f65ccad9652e8 100644 (file)
@@ -88,7 +88,7 @@ namespace trace {
         void writeString(const char *str, size_t size);
         void writeWString(const wchar_t *str);
         void writeBlob(const void *data, size_t size);
-        void writeEnum(const EnumSig *sig);
+        void writeEnum(const EnumSig *sig, signed long long value);
         void writeBitmask(const BitmaskSig *sig, unsigned long long value);
         void writeNull(void);
         void writeOpaque(const void *ptr);
index 26ddc64d82f91d5512c5180a7a72ab47e20a00c3..ccd7b2266c39b0bc98d9c4e4eeb685636abc7501 100644 (file)
@@ -69,7 +69,7 @@ public:
     }
 
     void visit(Enum *node) {
-        writer.writeEnum(node->sig);
+        writer.writeEnum(node->sig, node->value);
     }
 
     void visit(Bitmask *node) {
index bc88c3b4f29bc2c40fb4e78a8467d986fae64aff..57d2d86eb23c48bc37f75bdbbc69c9ab7a5dc197 100644 (file)
@@ -192,15 +192,13 @@ void VariantVisitor::visit(trace::Enum *e)
         sig = m_loader->enumSignature(e->sig->id);
     }
     if (!sig) {
-        sig = new ApiTraceEnumSignature(
-            QString::fromStdString(e->sig->name),
-            QVariant(e->sig->value));
+        sig = new ApiTraceEnumSignature(e->sig);
         if (m_loader) {
             m_loader->addEnumSignature(e->sig->id, sig);
         }
     }
 
-    m_variant = QVariant::fromValue(ApiEnum(sig));
+    m_variant = QVariant::fromValue(ApiEnum(sig, e->value));
 }
 
 void VariantVisitor::visit(trace::Bitmask *bitmask)
@@ -229,16 +227,39 @@ void VariantVisitor::visit(trace::Pointer *ptr)
     m_variant = QVariant::fromValue(ApiPointer(ptr->value));
 }
 
+ApiTraceEnumSignature::ApiTraceEnumSignature(const trace::EnumSig *sig)
+{
+    for (const trace::EnumValue *it = sig->values;
+         it != sig->values + sig->num_values; ++it) {
+        QPair<QString, signed long long> pair;
+
+        pair.first = QString::fromStdString(it->name);
+        pair.second = it->value;
+
+        m_names.append(pair);
+    }
+}
+
+QString ApiTraceEnumSignature::name(signed long long value) const
+{
+    for (ValueList::const_iterator it = m_names.begin();
+         it != m_names.end(); ++it) {
+        if (value == it->second) {
+            return it->first;
+        }
+    }
+    return QString::fromLatin1("%1").arg(value);
+}
 
-ApiEnum::ApiEnum(ApiTraceEnumSignature *sig)
-    : m_sig(sig)
+ApiEnum::ApiEnum(ApiTraceEnumSignature *sig, signed long long value)
+    : m_sig(sig), m_value(value)
 {
 }
 
 QString ApiEnum::toString() const
 {
     if (m_sig) {
-        return m_sig->name();
+        return m_sig->name(m_value);
     }
     Q_ASSERT(!"should never happen");
     return QString();
@@ -247,7 +268,7 @@ QString ApiEnum::toString() const
 QVariant ApiEnum::value() const
 {
     if (m_sig) {
-        return m_sig->value();
+        return QVariant::fromValue(m_value);
     }
     Q_ASSERT(!"should never happen");
     return QVariant();
@@ -256,7 +277,7 @@ QVariant ApiEnum::value() const
 QString ApiEnum::name() const
 {
     if (m_sig) {
-        return m_sig->name();
+        return m_sig->name(m_value);
     }
     Q_ASSERT(!"should never happen");
     return QString();
index 784834b17a52764279acad5b64b9fed44241090f..3a9faafd495e851c281609d5c7c94e9431020c7d 100644 (file)
@@ -54,23 +54,19 @@ struct ApiTraceError
 class ApiTraceEnumSignature
 {
 public:
-    ApiTraceEnumSignature(const QString &name = QString(),
-                          const QVariant &val=QVariant())\
-        : m_name(name),
-          m_value(val)
-    {}
+    ApiTraceEnumSignature(const trace::EnumSig *sig);
+
+    QString name(signed long long value) const;
 
-    QVariant value() const { return m_value; }
-    QString name() const { return m_name; }
 private:
-    QString m_name;
-    QVariant m_value;
+    typedef QList<QPair<QString, signed long long> > ValueList;
+    ValueList m_names;
 };
 
 class ApiEnum
 {
 public:
-    ApiEnum(ApiTraceEnumSignature *sig=0);
+    ApiEnum(ApiTraceEnumSignature *sig=0, signed long long value = 0);
 
     QString toString() const;
 
@@ -78,6 +74,7 @@ public:
     QString name() const;
 private:
     ApiTraceEnumSignature *m_sig;
+    signed long long m_value;
 };
 Q_DECLARE_METATYPE(ApiEnum);
 
index 4e9a28d0b8ae8722c6c693c29246eadd59b45132..c1b48598f2501dd038d05132ab6a96a3689973e1 100644 (file)
--- a/trace.py
+++ b/trace.py
@@ -76,25 +76,14 @@ class DumpDeclarator(stdapi.OnceVisitor):
     __enum_id = 0
 
     def visit_enum(self, enum):
-        print 'static void _write__%s(const %s value) {' % (enum.tag, enum.expr)
-        n = len(enum.values)
-        for i in range(n):
-            value = enum.values[i]
-            print '    static const trace::EnumSig sig%u = {%u, "%s", %s};' % (i, DumpDeclarator.__enum_id, value, value)
-            DumpDeclarator.__enum_id += 1
-        print '    const trace::EnumSig *sig;'
-        print '    switch (value) {'
-        for i in range(n):
-            value = enum.values[i]
-            print '    case %s:' % value
-            print '        sig = &sig%u;' % i
-            print '        break;'
-        print '    default:'
-        print '        trace::localWriter.writeSInt(value);'
-        print '        return;'
-        print '    }'
-        print '    trace::localWriter.writeEnum(sig);'
-        print '}'
+        print 'static const trace::EnumValue __enum%s_values[] = {' % (enum.tag)
+        for value in enum.values:
+            print '   {"%s", %s},' % (value, value)
+        print '};'
+        print
+        print 'static const trace::EnumSig __enum%s_sig = {' % (enum.tag)
+        print '   %u, %u, __enum%s_values' % (enum.id, len(enum.values), enum.tag)
+        print '};'
         print
 
     def visit_bitmask(self, bitmask):
@@ -186,7 +175,7 @@ class DumpImplementer(stdapi.Visitor):
         print '    trace::localWriter.writeBlob(%s, %s);' % (instance, blob.size)
 
     def visit_enum(self, enum, instance):
-        print '    _write__%s(%s);' % (enum.tag, instance)
+        print '    trace::localWriter.writeEnum(&__enum%s_sig, %s);' % (enum.tag, instance)
 
     def visit_bitmask(self, bitmask, instance):
         print '    trace::localWriter.writeBitmask(&__bitmask%s_sig, %s);' % (bitmask.tag, instance)