summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-22 13:03:02 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2012-12-22 13:03:02 (GMT)
commitfa05389f050004a14787cd7b4ebb6e0b54e0e4af (patch)
treea5a97597cd48971540598e92ac14f15cd2ea6ef5
parent4b345063582d4ac89a68a053a27552a688e3a583 (diff)
downloaduscxml-fa05389f050004a14787cd7b4ebb6e0b54e0e4af.zip
uscxml-fa05389f050004a14787cd7b4ebb6e0b54e0e4af.tar.gz
uscxml-fa05389f050004a14787cd7b4ebb6e0b54e0e4af.tar.bz2
Got rid of xpath on critical path
Improves performance by a factor of 8!
-rw-r--r--src/uscxml/Interpreter.cpp55
-rw-r--r--src/uscxml/Interpreter.h171
-rw-r--r--test/samples/uscxml/test-performance.scxml16
3 files changed, 62 insertions, 180 deletions
diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp
index 0c4f98f..70ae623 100644
--- a/src/uscxml/Interpreter.cpp
+++ b/src/uscxml/Interpreter.cpp
@@ -856,6 +856,15 @@ Arabica::XPath::NodeSet<std::string> Interpreter::selectEventlessTransitions() {
NodeSet<std::string> ancestors = getProperAncestors(atomicStates[i], Arabica::DOM::Node<std::string>());
ancestors.push_back(atomicStates[i]);
for (unsigned int j = 0; j < ancestors.size(); j++) {
+ NodeSet<std::string> transitions = filterChildElements("transition", ancestors[j]);
+ for (unsigned int k = 0; k < transitions.size(); k++) {
+ if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) {
+ enabledTransitions.push_back(transitions[k]);
+ goto LOOP;
+ }
+ }
+
+#if 0
NodeSet<std::string> transitions = _xpath.evaluate("" + _nsPrefix + "transition", ancestors[j]).asNodeSet();
for (unsigned int k = 0; k < transitions.size(); k++) {
if (!((Arabica::DOM::Element<std::string>)transitions[k]).hasAttribute("event") && hasConditionMatch(transitions[k])) {
@@ -863,6 +872,7 @@ Arabica::XPath::NodeSet<std::string> Interpreter::selectEventlessTransitions() {
goto LOOP;
}
}
+#endif
}
LOOP:
;
@@ -1186,9 +1196,9 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabled
statesToExit.reverse();
for (int i = 0; i < statesToExit.size(); i++) {
- NodeSet<std::string> historyElems = _xpath.evaluate("" + _nsPrefix + "history", statesToExit[i]).asNodeSet();
- for (int j = 0; j < historyElems.size(); j++) {
- Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)historyElems[j];
+ NodeSet<std::string> histories = filterChildElements("history", statesToExit[i]);
+ for (int j = 0; j < histories.size(); j++) {
+ Arabica::DOM::Element<std::string> historyElem = (Arabica::DOM::Element<std::string>)histories[j];
std::string historyType = (historyElem.hasAttribute("type") ? historyElem.getAttribute("type") : "shallow");
NodeSet<std::string> historyNodes;
for (int k = 0; k < _configuration.size(); k++) {
@@ -1205,13 +1215,15 @@ void Interpreter::exitStates(const Arabica::XPath::NodeSet<std::string>& enabled
}
for (int i = 0; i < statesToExit.size(); i++) {
- Arabica::XPath::NodeSet<std::string> onExitElems = _xpath.evaluate("" + _nsPrefix + "onexit", statesToExit[i]).asNodeSet();
- for (int j = 0; j < onExitElems.size(); j++) {
- executeContent(onExitElems[j]);
+ NodeSet<std::string> onExits = filterChildElements("onExit", statesToExit[i]);
+ for (int j = 0; j < onExits.size(); j++) {
+ Arabica::DOM::Element<std::string> onExitElem = (Arabica::DOM::Element<std::string>)onExits[j];
+ executeContent(onExitElem);
}
- Arabica::XPath::NodeSet<std::string> invokeElems = _xpath.evaluate("" + _nsPrefix + "invoke", statesToExit[i]).asNodeSet();
- for (int j = 0; j < invokeElems.size(); j++) {
- cancelInvoke(invokeElems[j]);
+ NodeSet<std::string> invokes = filterChildElements("invoke", statesToExit[i]);
+ for (int j = 0; j < invokes.size(); j++) {
+ Arabica::DOM::Element<std::string> invokeElem = (Arabica::DOM::Element<std::string>)invokes[j];
+ cancelInvoke(invokeElem);
}
}
@@ -1299,9 +1311,9 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enable
_configuration.push_back(stateElem);
_statesToInvoke.push_back(stateElem);
if (_binding == LATE && stateElem.getAttribute("isFirstEntry").size() > 0) {
- Arabica::XPath::NodeSet<std::string> dataModelElems = _xpath.evaluate("" + _nsPrefix + "datamodel", stateElem).asNodeSet();
+ NodeSet<std::string> dataModelElems = filterChildElements("datamodel", stateElem);
if(dataModelElems.size() > 0 && _dataModel) {
- Arabica::XPath::NodeSet<std::string> dataElems = _xpath.evaluate("" + _nsPrefix + "data", dataModelElems[0]).asNodeSet();
+ Arabica::XPath::NodeSet<std::string> dataElems = filterChildElements("data", dataModelElems[0]);
for (int j = 0; j < dataElems.size(); j++) {
initializeData(dataElems[j]);
}
@@ -1309,7 +1321,7 @@ void Interpreter::enterStates(const Arabica::XPath::NodeSet<std::string>& enable
stateElem.setAttribute("isFirstEntry", "");
}
// execute onentry executable content
- Arabica::XPath::NodeSet<std::string> onEntryElems = _xpath.evaluate("" + _nsPrefix + "onentry", stateElem).asNodeSet();
+ NodeSet<std::string> onEntryElems = filterChildElements("onEntry", stateElem);
for (int j = 0; j < onEntryElems.size(); j++) {
executeContent(onEntryElems[j]);
}
@@ -1468,8 +1480,12 @@ NEXT_ANCESTOR:
}
Arabica::DOM::Node<std::string> Interpreter::getState(const std::string& stateId) {
+
+ if (_cachedStates.find(stateId) != _cachedStates.end()) {
+ return _cachedStates[stateId];
+ }
+
// first try atomic and compund states
-// std::cout << _nsPrefix << stateId << std::endl;
NodeSet<std::string> target = _xpath.evaluate("//" + _nsPrefix + "state[@id='" + stateId + "']", _doc).asNodeSet();
if (target.size() > 0)
goto FOUND;
@@ -1487,6 +1503,7 @@ Arabica::DOM::Node<std::string> Interpreter::getState(const std::string& stateId
FOUND:
if (target.size() > 0) {
assert(target.size() == 1);
+ _cachedStates[stateId] = target[0];
return target[0];
}
// return the empty node
@@ -1575,6 +1592,18 @@ std::vector<std::string> Interpreter::tokenizeIdRefs(const std::string& idRefs)
return ids;
}
+NodeSet<std::string> Interpreter::filterChildElements(const std::string& tagName, const Node<std::string>& node) {
+ NodeSet<std::string> filteredChildElems;
+ NodeList<std::string> childs = node.getChildNodes();
+ for (unsigned int i = 0; i < childs.getLength(); i++) {
+ if (childs.item(i).getNodeType() != Node_base::ELEMENT_NODE ||
+ !boost::iequals(TAGNAME(childs.item(i)), tagName))
+ continue;
+ filteredChildElems.push_back(childs.item(i));
+ }
+ return filteredChildElems;
+}
+
NodeSet<std::string> Interpreter::getProperAncestors(const Arabica::DOM::Node<std::string>& s1,
const Arabica::DOM::Node<std::string>& s2) {
NodeSet<std::string> ancestors;
diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h
index 58b2a51..b723b5f 100644
--- a/src/uscxml/Interpreter.h
+++ b/src/uscxml/Interpreter.h
@@ -188,7 +188,8 @@ protected:
bool parentIsScxmlState(Arabica::DOM::Node<std::string> state);
static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs);
-
+ static Arabica::XPath::NodeSet<std::string> filterChildElements(const std::string& tagname, const Arabica::DOM::Node<std::string>& node);
+
static boost::uuids::random_generator uuidGen;
static const std::string getUUID();
@@ -203,174 +204,10 @@ protected:
std::map<std::string, Invoker*> _invokerIds;
std::map<std::string, Invoker*> _invokers;
+ /// We need to remember to adapt them when the DOM is operated upon
+ std::map<std::string, Arabica::DOM::Node<std::string> > _cachedStates;
};
-#if 0
-class SCXMLParseHandler :
- public Arabica::SAX::EntityResolver<std::string>,
- public Arabica::SAX::DTDHandler<std::string>,
- public Arabica::SAX::ContentHandler<std::string>,
- public Arabica::SAX::CatchErrorHandler<std::string>,
- public Arabica::SAX::LexicalHandler<std::string>,
- public Arabica::SAX::DeclHandler<std::string> {
-public:
- SCXMLParseHandler() { }
- virtual ~SCXMLParseHandler() { }
-
- // EntityResolver
- virtual InputSourceT resolveEntity(const std::string& publicId , const std::string& systemId) {
- return InputSourceT();
- }
-
- // DTDHandler
- virtual void notationDecl(const std::string& name,
- const std::string& publicId,
- const std::string& systemId) {
- std::cout << "notationDecl" << std::endl;
- std::cout << " name:" << name << std::endl;
- std::cout << " publicId:" << publicId << std::endl;
- std::cout << " systemId:" << systemId << std::endl;
- }
- virtual void unparsedEntityDecl(const std::string& name,
- const std::string& publicId,
- const std::string& systemId,
- const std::string& notationName) {
- std::cout << "unparsedEntityDecl" << std::endl;
- std::cout << " name:" << name << std::endl;
- std::cout << " publicId:" << publicId << std::endl;
- std::cout << " systemId:" << systemId << std::endl;
- std::cout << " notationName:" << notationName << std::endl;
- }
-
- // ContentHandler
- virtual void setDocumentLocator(const LocatorT& locator) {
- std::cout << "setDocumentLocator" << std::endl;
- }
- virtual void startDocument() {
- std::cout << "startDocument" << std::endl;
- }
- virtual void endDocument() {
- std::cout << "endDocument" << std::endl;
- }
- virtual void startPrefixMapping(const std::string& prefix, const std::string& uri) {
- std::cout << "startPrefixMapping" << std::endl;
- std::cout << " prefix:" << prefix << std::endl;
- std::cout << " uri:" << uri << std::endl;
- }
- virtual void endPrefixMapping(const std::string& prefix) {
- std::cout << "endPrefixMapping" << std::endl;
- std::cout << " prefix:" << prefix << std::endl;
- }
- virtual void startElement(const std::string& namespaceURI, const std::string& localName,
- const std::string& qName, const AttributesT& atts) {
- std::cout << "startElement" << std::endl;
- std::cout << " namespaceURI:" << namespaceURI << std::endl;
- std::cout << " localName:" << localName << std::endl;
- std::cout << " qName:" << qName << std::endl;
- std::cout << " atts:" << atts.getLength() << std::endl;
- }
- virtual void endElement(const std::string& namespaceURI, const std::string& localName,
- const std::string& qName) {
- std::cout << "endElement" << std::endl;
- std::cout << " namespaceURI:" << namespaceURI << std::endl;
- std::cout << " localName:" << localName << std::endl;
- std::cout << " qName:" << qName << std::endl;
- }
- virtual void characters(const std::string& ch) {
- std::cout << "characters" << std::endl;
- std::cout << " ch:" << ch << std::endl;
- }
- virtual void ignorableWhitespace(const std::string& ch) {
- std::cout << "ignorableWhitespace" << std::endl;
- std::cout << " ch:" << ch << std::endl;
- }
- virtual void processingInstruction(const std::string& target, const std::string& data) {
- std::cout << "processingInstruction" << std::endl;
- std::cout << " target:" << target << std::endl;
- std::cout << " data:" << data << std::endl;
- }
- virtual void skippedEntity(const std::string& name) {
- std::cout << "skippedEntity" << std::endl;
- std::cout << " name:" << name << std::endl;
- }
-
- // ErrorHandler
- virtual void warning(const SAXParseExceptionT& e) {
- Arabica::SAX::CatchErrorHandler<std::string>::warning(e);
- }
- virtual void error(const SAXParseExceptionT& e) {
- Arabica::SAX::CatchErrorHandler<std::string>::error(e);
- }
- virtual void fatalError(const SAXParseExceptionT& e) {
- Arabica::SAX::CatchErrorHandler<std::string>::fatalError(e);
- }
-
- // LexicalHandler
- virtual void startDTD(const std::string& name,
- const std::string& publicId,
- const std::string& systemId) {
- std::cout << "startDTD" << std::endl;
- std::cout << " name:" << name << std::endl;
- std::cout << " publicId:" << publicId << std::endl;
- std::cout << " systemId:" << systemId << std::endl;
- }
-
- virtual void endDTD() {
- std::cout << "endDTD" << std::endl;
- }
- virtual void startEntity(const std::string& name) {
- std::cout << "startEntity" << std::endl;
- std::cout << " name:" << name << std::endl;
- }
- virtual void endEntity(const std::string& name) {
- std::cout << "endEntity" << std::endl;
- std::cout << " name:" << name << std::endl;
- }
- virtual void startCDATA() {
- std::cout << "startCDATA" << std::endl;
- }
- virtual void endCDATA() {
- std::cout << "endCDATA" << std::endl;
- }
- virtual void comment(const std::string& text) {
- std::cout << "comment" << std::endl;
- std::cout << " text:" << text << std::endl;
- }
-
- // DeclHandler
- virtual void elementDecl(const std::string& name, const std::string& model) {
- std::cout << "elementDecl" << std::endl;
- std::cout << " name:" << name << std::endl;
- std::cout << " model:" << model << std::endl;
- }
- virtual void attributeDecl(const std::string& elementName,
- const std::string& attributeName,
- const std::string& type,
- const std::string& valueDefault,
- const std::string& value) {
- std::cout << "attributeDecl" << std::endl;
- std::cout << " elementName:" << elementName << std::endl;
- std::cout << " attributeName:" << attributeName << std::endl;
- std::cout << " type:" << type << std::endl;
- std::cout << " valueDefault:" << valueDefault << std::endl;
- std::cout << " value:" << value << std::endl;
- }
- virtual void internalEntityDecl(const std::string& name, const std::string& value) {
- std::cout << "internalEntityDecl" << std::endl;
- std::cout << " name:" << name << std::endl;
- std::cout << " value:" << value << std::endl;
- }
- virtual void externalEntityDecl(const std::string& name,
- const std::string& publicId,
- const std::string& systemId) {
- std::cout << "externalEntityDecl" << std::endl;
- std::cout << " name:" << name << std::endl;
- std::cout << " publicId:" << publicId << std::endl;
- std::cout << " systemId:" << systemId << std::endl;
- }
-
-};
-#endif
}
#endif
diff --git a/test/samples/uscxml/test-performance.scxml b/test/samples/uscxml/test-performance.scxml
new file mode 100644
index 0000000..4d2d4c4
--- /dev/null
+++ b/test/samples/uscxml/test-performance.scxml
@@ -0,0 +1,16 @@
+<scxml datamodel="ecmascript">
+ <datamodel>
+ <data id="iterations">10000</data>
+ </datamodel>
+ <state id="start">
+ <transition target="loop" />
+ </state>
+ <state id="loop">
+ <onentry>
+ <script>iterations--;</script>
+ </onentry>
+ <transition cond="iterations > 0" target="start" />
+ <transition cond="iterations == 0" target="final" />
+ </state>
+ <final id="final" />
+</scxml> \ No newline at end of file