-
Notifications
You must be signed in to change notification settings - Fork 435
Improving NodeGraph::getNodeDef performance #2933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -192,7 +192,7 @@ vector<PortElementPtr> Node::getDownstreamPorts() const | |
| } | ||
| } | ||
| std::sort(downstreamPorts.begin(), downstreamPorts.end(), [](const ConstElementPtr& a, const ConstElementPtr& b) | ||
| { | ||
| { | ||
| return a->getName() > b->getName(); | ||
| }); | ||
| return downstreamPorts; | ||
|
|
@@ -745,12 +745,10 @@ NodeDefPtr NodeGraph::getNodeDef() const | |
| // If not directly defined look for an implementation which has a nodedef association | ||
| if (!nodedef) | ||
| { | ||
| for (auto impl : getDocument()->getImplementations()) | ||
| ImplementationPtr impl = getDocument()->getImplementationForNodeGraph(getQualifiedName(getName())); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense that instead of caching the implementation reference and then getting the nodedef here, just store the nodedef reference as the lookup ? |
||
| if (impl) | ||
| { | ||
| if (impl->getNodeGraph() == getQualifiedName(getName())) | ||
| { | ||
| nodedef = impl->getNodeDef(); | ||
| } | ||
| nodedef = impl->getNodeDef(); | ||
| } | ||
| } | ||
| return nodedef; | ||
|
|
@@ -775,7 +773,7 @@ vector<PortElementPtr> NodeGraph::getDownstreamPorts() const | |
| } | ||
| } | ||
| std::sort(downstreamPorts.begin(), downstreamPorts.end(), [](const ConstElementPtr& a, const ConstElementPtr& b) | ||
| { | ||
| { | ||
| return a->getName() > b->getName(); | ||
| }); | ||
| return downstreamPorts; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,7 +153,7 @@ void Syntax::makeValidName(string& name) const | |
| { | ||
| std::replace_if(name.begin(), name.end(), isInvalidChar, '_'); | ||
| name = replaceSubstrings(name, _invalidTokens); | ||
| if (std::find(_reservedWords.begin(), _reservedWords.end(), name) != _reservedWords.end()) | ||
| if (_reservedWords.find(name) != _reservedWords.end()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like a nice improvement :) good catch |
||
| { | ||
| // We append "1" here because thats the prior behavior from makeIdentifier() below when | ||
| // the reservedWords were added to the identifiers list. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // | ||
| // Copyright Contributors to the MaterialX Project | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| #include <MaterialXTest/External/Catch/catch.hpp> | ||
|
|
||
| #ifdef CATCH_CONFIG_ENABLE_BENCHMARKING | ||
|
|
||
| #include <MaterialXCore/Definition.h> | ||
| #include <MaterialXCore/Document.h> | ||
| #include <MaterialXCore/Node.h> | ||
|
|
||
| namespace mx = MaterialX; | ||
|
|
||
| // Build a document that scales the two axes feeding NodeGraph::getNodeDef | ||
| // from PortElement::validate: | ||
| // * numImplStubs - document-root <implementation> elements; sizes the | ||
| // Document::Cache nodegraph -> implementation map. | ||
| // * numNodegraphRefs - inputs that resolve through a nodegraph; each one | ||
| // performs a cache lookup. | ||
| static mx::DocumentPtr buildScalingDocument(size_t numImplStubs, size_t numNodegraphRefs) | ||
| { | ||
| mx::DocumentPtr doc = mx::createDocument(); | ||
|
|
||
| // A nodegraph with one internal node and one output, so that | ||
| // PortElement::getConnectedNode() resolves transitively through the | ||
| // output (see Input::getConnectedNode in Interface.cpp). | ||
| mx::NodeGraphPtr ng = doc->addNodeGraph("ng"); | ||
| mx::NodePtr inner = ng->addNode("constant", "inner", "color3"); | ||
| mx::OutputPtr out = ng->addOutput("out", "color3"); | ||
| out->setNodeName(inner->getName()); | ||
|
|
||
| // A host node parenting many inputs that reference the nodegraph. | ||
| mx::NodePtr host = doc->addNode("surface", "host", "surfaceshader"); | ||
| for (size_t i = 0; i < numNodegraphRefs; ++i) | ||
| { | ||
| mx::InputPtr in = host->addInput("in" + std::to_string(i), "color3"); | ||
| in->setNodeGraphString("ng"); | ||
| in->setOutputString("out"); | ||
| } | ||
|
|
||
| for (size_t i = 0; i < numImplStubs; ++i) | ||
| { | ||
| mx::ImplementationPtr impl = doc->addImplementation("i" + std::to_string(i)); | ||
| impl->setNodeDefString("n" + std::to_string(i)); | ||
| } | ||
|
|
||
| return doc; | ||
| } | ||
|
|
||
| TEST_CASE("NodeGraph getNodeDef performance", "[node][performance]") | ||
| { | ||
| BENCHMARK("validate, stubs=200 refs=100") | ||
| { | ||
| mx::DocumentPtr doc = buildScalingDocument(200, 100); | ||
| return doc->validate(); | ||
| }; | ||
|
|
||
| BENCHMARK("validate, stubs=1000 refs=100") | ||
| { | ||
| mx::DocumentPtr doc = buildScalingDocument(1000, 100); | ||
| return doc->validate(); | ||
| }; | ||
|
|
||
| BENCHMARK("validate, stubs=10000 refs=100") | ||
| { | ||
| mx::DocumentPtr doc = buildScalingDocument(10000, 100); | ||
| return doc->validate(); | ||
| }; | ||
| } | ||
|
|
||
| #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think its possible for more than one Implementation element to use the same NodeGraph - so this might need to be
std::unordered_map<string, std::vector>
For standard surface (here) we have two different Implementation elements that have the same NodeGraph
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious if there are any metrics for the additional update cost especially if the cache updates frequently ? At most currently 1 or a few items will ever be found and it's mostly static during the lifetime of a document.