From eb64451efcd8100d02ec89ff2ae6ea2c78c7645b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Sun, 11 Dec 2011 10:33:55 +0000 Subject: [PATCH] Trace enum signatures as a whole. --- common/trace_format.hpp | 82 +++++++++++++++------------ common/trace_model.cpp | 14 +++-- common/trace_model.hpp | 19 ++++--- common/trace_parser.cpp | 101 +++++++++++++++++++++++++++++++--- common/trace_parser.hpp | 4 ++ common/trace_writer.cpp | 10 +++- common/trace_writer.hpp | 2 +- common/trace_writer_model.cpp | 2 +- gui/apitracecall.cpp | 39 ++++++++++--- gui/apitracecall.h | 17 +++--- trace.py | 29 +++------- 11 files changed, 215 insertions(+), 104 deletions(-) diff --git a/common/trace_format.hpp b/common/trace_format.hpp index 2a1150c..5aade00 100644 --- a/common/trace_format.hpp +++ b/common/trace_format.hpp @@ -26,6 +26,51 @@ /* * 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 @@ -57,7 +102,7 @@ * 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)+ @@ -67,41 +112,6 @@ * */ -#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, diff --git a/common/trace_model.cpp b/common/trace_model.cpp index 89a191d..2ceb810 100644 --- a/common/trace_model.cpp +++ b/common/trace_model.cpp @@ -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(value) >= 0); return static_cast(value); } signed long long Float ::toSInt(void) const { return static_cast(value); } signed long long Double ::toSInt(void) const { return static_cast(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(value); } unsigned long long Double ::toUInt(void) const { return static_cast(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(value); } float UInt ::toFloat(void) const { return static_cast(value); } float Float ::toFloat(void) const { return value; } float Double ::toFloat(void) const { return value; } -float Enum ::toFloat(void) const { return static_cast(sig->value); } // floating point cast @@ -130,7 +126,6 @@ double SInt ::toDouble(void) const { return static_cast(value); } double UInt ::toDouble(void) const { return static_cast(value); } double Float ::toDouble(void) const { return value; } double Double ::toDouble(void) const { return value; } -double Enum ::toDouble(void) const { return static_cast(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) { diff --git a/common/trace_model.hpp b/common/trace_model.hpp index f208032..1b2e1f2 100644 --- a/common/trace_model.hpp +++ b/common/trace_model.hpp @@ -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; diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp index 1a1139d..f3e623a 100644 --- a/common/trace_parser.cpp +++ b/common/trace_parser.cpp @@ -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; diff --git a/common/trace_parser.hpp b/common/trace_parser.hpp index 73bb776..d8c5915 100644 --- a/common/trace_parser.hpp +++ b/common/trace_parser.hpp @@ -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); diff --git a/common/trace_writer.cpp b/common/trace_writer.cpp index 897c7b1..1679989 100644 --- a/common/trace_writer.cpp +++ b/common/trace_writer.cpp @@ -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) { diff --git a/common/trace_writer.hpp b/common/trace_writer.hpp index 82c46b9..f89eb65 100644 --- a/common/trace_writer.hpp +++ b/common/trace_writer.hpp @@ -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); diff --git a/common/trace_writer_model.cpp b/common/trace_writer_model.cpp index 26ddc64..ccd7b22 100644 --- a/common/trace_writer_model.cpp +++ b/common/trace_writer_model.cpp @@ -69,7 +69,7 @@ public: } void visit(Enum *node) { - writer.writeEnum(node->sig); + writer.writeEnum(node->sig, node->value); } void visit(Bitmask *node) { diff --git a/gui/apitracecall.cpp b/gui/apitracecall.cpp index bc88c3b..57d2d86 100644 --- a/gui/apitracecall.cpp +++ b/gui/apitracecall.cpp @@ -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 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(); diff --git a/gui/apitracecall.h b/gui/apitracecall.h index 784834b..3a9faaf 100644 --- a/gui/apitracecall.h +++ b/gui/apitracecall.h @@ -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 > 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); diff --git a/trace.py b/trace.py index 4e9a28d..c1b4859 100644 --- 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) -- 2.43.0