From: david Date: Wed, 12 Dec 2001 02:28:28 +0000 (+0000) Subject: Added trace attributes to properties: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=6fa9f86d1c0adf7b1257b3873b6842a45948b1fb;p=simgear.git Added trace attributes to properties: TRACE_READ - log a message whenever the property is read. TRACE_WRITE - log a message whenever the property is written. The second one works only when the property value is changed through the property manager; tied variables and accessors are not polled for value changes because of the performance hit. These methods end up invoking private methods SGPropertyNode::trace_read and SGPropertyNode::trace_write. By setting breakpoints on these methods inside a debugger, it is possible to debug property access and find what parts of a program are reading or writing specific property values by doing a backtrace. In the XML property files, users can use the attributes 'trace-read' and 'trace-write' to control tracing; the value should be 'y' to enable tracing or 'n' to disable it (the default). --- diff --git a/simgear/misc/props.cxx b/simgear/misc/props.cxx index 7e911668..2a66fba5 100644 --- a/simgear/misc/props.cxx +++ b/simgear/misc/props.cxx @@ -7,6 +7,7 @@ // $Id$ #include +#include #include #include @@ -42,6 +43,9 @@ public: #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt #define TEST_WRITE if (!getAttribute(WRITE)) return false +#define DO_TRACE_READ(type) if(getAttribute(TRACE_READ)) trace_read(type) +#define DO_TRACE_WRITE(type) if (getAttribute(TRACE_WRITE)) trace_write(type) + #define GET_BOOL (_value.bool_val->getValue()) #define GET_INT (_value.int_val->getValue()) #define GET_LONG (_value.long_val->getValue()) @@ -406,6 +410,66 @@ SGPropertyNode::clear_value () } +/** + * Get the value as a string. + */ +string +SGPropertyNode::get_string () const +{ + TEST_READ(""); + char buf[128]; + + switch (_type) { + case ALIAS: + return _value.alias->getStringValue(); + case BOOL: + if (GET_BOOL) + return "true"; + else + return "false"; + case INT: + sprintf(buf, "%d", GET_INT); + return buf; + case LONG: + sprintf(buf, "%ld", GET_LONG); + return buf; + case FLOAT: + sprintf(buf, "%f", GET_FLOAT); + return buf; + case DOUBLE: + sprintf(buf, "%f", GET_DOUBLE); + return buf; + case STRING: + case UNSPECIFIED: + return GET_STRING; + } + + return ""; // if NONE +} + + +/** + * Trace a read access for a property. + */ +void +SGPropertyNode::trace_read (SGPropertyNode::Type accessType) const +{ + SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath() + << ", value \"" << get_string() << '"'); +} + + +/** + * Trace a write access for a property. + */ +void +SGPropertyNode::trace_write (SGPropertyNode::Type accessType) const +{ + SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath() + << ", value\"" << get_string() << '"'); +} + + /** * Alias to another node. */ @@ -586,6 +650,7 @@ SGPropertyNode::getType () const bool SGPropertyNode::getBoolValue () const { + DO_TRACE_READ(BOOL); TEST_READ(false); switch (_type) { case ALIAS: @@ -611,6 +676,7 @@ SGPropertyNode::getBoolValue () const int SGPropertyNode::getIntValue () const { + DO_TRACE_READ(INT); TEST_READ(0); switch (_type) { case ALIAS: @@ -636,6 +702,7 @@ SGPropertyNode::getIntValue () const long SGPropertyNode::getLongValue () const { + DO_TRACE_READ(LONG); TEST_READ(0L); switch (_type) { case ALIAS: @@ -661,6 +728,7 @@ SGPropertyNode::getLongValue () const float SGPropertyNode::getFloatValue () const { + DO_TRACE_READ(FLOAT); TEST_READ(0.0); switch (_type) { case ALIAS: @@ -686,6 +754,7 @@ SGPropertyNode::getFloatValue () const double SGPropertyNode::getDoubleValue () const { + DO_TRACE_READ(DOUBLE); TEST_READ(0.0L); switch (_type) { case ALIAS: @@ -711,40 +780,14 @@ SGPropertyNode::getDoubleValue () const string SGPropertyNode::getStringValue () const { - TEST_READ(""); - char buf[128]; - - switch (_type) { - case ALIAS: - return _value.alias->getStringValue(); - case BOOL: - if (GET_BOOL) - return "true"; - else - return "false"; - case INT: - sprintf(buf, "%d", GET_INT); - return buf; - case LONG: - sprintf(buf, "%ld", GET_LONG); - return buf; - case FLOAT: - sprintf(buf, "%f", GET_FLOAT); - return buf; - case DOUBLE: - sprintf(buf, "%f", GET_DOUBLE); - return buf; - case STRING: - case UNSPECIFIED: - return GET_STRING; - } - - return ""; // if NONE + DO_TRACE_READ(STRING); + return get_string(); } bool SGPropertyNode::setBoolValue (bool value) { + bool result = false; TEST_WRITE; if (_type == NONE || _type == UNSPECIFIED) { clear_value(); @@ -754,27 +797,36 @@ SGPropertyNode::setBoolValue (bool value) switch (_type) { case ALIAS: - return _value.alias->setBoolValue(value); + result = _value.alias->setBoolValue(value); + break; case BOOL: - return SET_BOOL(value); + result = SET_BOOL(value); + break; case INT: - return SET_INT(int(value)); + result = SET_INT(int(value)); + break; case LONG: - return SET_LONG(long(value)); + result = SET_LONG(long(value)); + break; case FLOAT: - return SET_FLOAT(float(value)); + result = SET_FLOAT(float(value)); + break; case DOUBLE: - return SET_DOUBLE(double(value)); + result = SET_DOUBLE(double(value)); + break; case STRING: - return SET_STRING(value ? "true" : "false"); + result = SET_STRING(value ? "true" : "false"); + break; } - return false; // should never happen + DO_TRACE_WRITE(BOOL); + return result; } bool SGPropertyNode::setIntValue (int value) { + bool result = false; TEST_WRITE; if (_type == NONE || _type == UNSPECIFIED) { clear_value(); @@ -784,30 +836,39 @@ SGPropertyNode::setIntValue (int value) switch (_type) { case ALIAS: - return _value.alias->setIntValue(value); + result = _value.alias->setIntValue(value); + break; case BOOL: - return SET_BOOL(value == 0 ? false : true); + result = SET_BOOL(value == 0 ? false : true); + break; case INT: - return SET_INT(value); + result = SET_INT(value); + break; case LONG: - return SET_LONG(long(value)); + result = SET_LONG(long(value)); + break; case FLOAT: - return SET_FLOAT(float(value)); + result = SET_FLOAT(float(value)); + break; case DOUBLE: - return SET_DOUBLE(double(value)); + result = SET_DOUBLE(double(value)); + break; case STRING: { char buf[128]; sprintf(buf, "%d", value); - return SET_STRING(buf); + result = SET_STRING(buf); + break; } } - return false; // should never happen + DO_TRACE_WRITE(INT); + return result; } bool SGPropertyNode::setLongValue (long value) { + bool result = false; TEST_WRITE; if (_type == NONE || _type == UNSPECIFIED) { clear_value(); @@ -817,30 +878,39 @@ SGPropertyNode::setLongValue (long value) switch (_type) { case ALIAS: - return _value.alias->setLongValue(value); + result = _value.alias->setLongValue(value); + break; case BOOL: - return SET_BOOL(value == 0L ? false : true); + result = SET_BOOL(value == 0L ? false : true); + break; case INT: - return SET_INT(int(value)); + result = SET_INT(int(value)); + break; case LONG: - return SET_LONG(value); + result = SET_LONG(value); + break; case FLOAT: - return SET_FLOAT(float(value)); + result = SET_FLOAT(float(value)); + break; case DOUBLE: - return SET_DOUBLE(double(value)); + result = SET_DOUBLE(double(value)); + break; case STRING: { char buf[128]; sprintf(buf, "%d", value); - return SET_STRING(buf); + result = SET_STRING(buf); + break; } } - return false; // should never happen + DO_TRACE_WRITE(LONG); + return result; } bool SGPropertyNode::setFloatValue (float value) { + bool result = false; TEST_WRITE; if (_type == NONE || _type == UNSPECIFIED) { clear_value(); @@ -850,30 +920,39 @@ SGPropertyNode::setFloatValue (float value) switch (_type) { case ALIAS: - return _value.alias->setFloatValue(value); + result = _value.alias->setFloatValue(value); + break; case BOOL: - return SET_BOOL(value == 0.0 ? false : true); + result = SET_BOOL(value == 0.0 ? false : true); + break; case INT: - return SET_INT(int(value)); + result = SET_INT(int(value)); + break; case LONG: - return SET_LONG(long(value)); + result = SET_LONG(long(value)); + break; case FLOAT: - return SET_FLOAT(value); + result = SET_FLOAT(value); + break; case DOUBLE: - return SET_DOUBLE(double(value)); + result = SET_DOUBLE(double(value)); + break; case STRING: { char buf[128]; sprintf(buf, "%f", value); - return SET_STRING(buf); + result = SET_STRING(buf); + break; } } - return false; // should never happen + DO_TRACE_WRITE(FLOAT); + return result; } bool SGPropertyNode::setDoubleValue (double value) { + bool result = false; TEST_WRITE; if (_type == NONE || _type == UNSPECIFIED) { clear_value(); @@ -883,30 +962,39 @@ SGPropertyNode::setDoubleValue (double value) switch (_type) { case ALIAS: - return _value.alias->setDoubleValue(value); + result = _value.alias->setDoubleValue(value); + break; case BOOL: - return SET_BOOL(value == 0.0L ? false : true); + result = SET_BOOL(value == 0.0L ? false : true); + break; case INT: - return SET_INT(int(value)); + result = SET_INT(int(value)); + break; case LONG: - return SET_LONG(long(value)); + result = SET_LONG(long(value)); + break; case FLOAT: - return SET_FLOAT(float(value)); + result = SET_FLOAT(float(value)); + break; case DOUBLE: - return SET_DOUBLE(value); + result = SET_DOUBLE(value); + break; case STRING: { char buf[128]; sprintf(buf, "%lf", value); - return SET_STRING(buf); + result = SET_STRING(buf); + break; } } - return false; // should never happen + DO_TRACE_WRITE(DOUBLE); + return result; } bool SGPropertyNode::setStringValue (string value) { + bool result = false; TEST_WRITE; if (_type == NONE || _type == UNSPECIFIED) { clear_value(); @@ -916,27 +1004,36 @@ SGPropertyNode::setStringValue (string value) switch (_type) { case ALIAS: - return _value.alias->setStringValue(value); + result = _value.alias->setStringValue(value); + break; case BOOL: - return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false); + result = SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false); + break; case INT: - return SET_INT(atoi(value.c_str())); + result = SET_INT(atoi(value.c_str())); + break; case LONG: - return SET_LONG(strtol(value.c_str(), 0, 0)); + result = SET_LONG(strtol(value.c_str(), 0, 0)); + break; case FLOAT: - return SET_FLOAT(atof(value.c_str())); + result = SET_FLOAT(atof(value.c_str())); + break; case DOUBLE: - return SET_DOUBLE(strtod(value.c_str(), 0)); + result = SET_DOUBLE(strtod(value.c_str(), 0)); + break; case STRING: - return SET_STRING(value); + result = SET_STRING(value); + break; } - return false; // should never happen + DO_TRACE_WRITE(STRING); + return result; } bool SGPropertyNode::setUnspecifiedValue (string value) { + bool result = false; TEST_WRITE; if (_type == NONE) { clear_value(); @@ -946,23 +1043,31 @@ SGPropertyNode::setUnspecifiedValue (string value) switch (_type) { case ALIAS: - return _value.alias->setUnspecifiedValue(value); + result = _value.alias->setUnspecifiedValue(value); + break; case BOOL: - return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false); + result = SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false); + break; case INT: - return SET_INT(atoi(value.c_str())); + result = SET_INT(atoi(value.c_str())); + break; case LONG: - return SET_LONG(strtol(value.c_str(), 0, 0)); + result = SET_LONG(strtol(value.c_str(), 0, 0)); + break; case FLOAT: - return SET_FLOAT(atof(value.c_str())); + result = SET_FLOAT(atof(value.c_str())); + break; case DOUBLE: - return SET_DOUBLE(strtod(value.c_str(), 0)); + result = SET_DOUBLE(strtod(value.c_str(), 0)); + break; case STRING: case UNSPECIFIED: - return SET_STRING(value); + result = SET_STRING(value); + break; } - return false; // should never happen + DO_TRACE_WRITE(UNSPECIFIED); + return result; } bool diff --git a/simgear/misc/props.hxx b/simgear/misc/props.hxx index df15d9d6..b9a0157a 100644 --- a/simgear/misc/props.hxx +++ b/simgear/misc/props.hxx @@ -511,7 +511,9 @@ public: enum Attribute { READ = 1, WRITE = 2, - ARCHIVE = 4 + ARCHIVE = 4, + TRACE_READ = 8, + TRACE_WRITE = 16 }; @@ -1038,6 +1040,24 @@ private: */ void clear_value (); + + /** + * Get the value as a string. + */ + string get_string () const; + + + /** + * Trace a read access. + */ + void trace_read (Type accessType) const; + + + /** + * Trace a write access. + */ + void trace_write (Type accessType) const; + string _name; int _index; SGPropertyNode * _parent; diff --git a/simgear/misc/props_io.cxx b/simgear/misc/props_io.cxx index 4f7dac93..160539ae 100644 --- a/simgear/misc/props_io.cxx +++ b/simgear/misc/props_io.cxx @@ -181,6 +181,12 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) attval = atts.getValue("archive"); if (checkFlag(attval, false)) mode |= SGPropertyNode::ARCHIVE; + attval = atts.getValue("trace-read"); + if (checkFlag(attval, false)) + mode |= SGPropertyNode::TRACE_READ; + attval = atts.getValue("trace-write"); + if (checkFlag(attval, false)) + mode |= SGPropertyNode::TRACE_WRITE; // Check for an alias. attval = atts.getValue("alias");