Skip to content
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

Fix performance issues with graph edge iteration in ShaderGraph #2023

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

nadult
Copy link
Contributor

@nadult nadult commented Sep 20, 2024

In complex materials graph and shader graph edge iteration can be extremely slow, because some edges may be visited unnecessarily multiple times. This is especially noticable in two functions: ShaderGraph::addUpstreamDependencies and ShaderGraph::optimize() .

GraphIterator and ShaderGraphEdgeIterator classes iterate over DAGs without marking nodes as visited, which may lead to exponential traversal time for some DAGs: https://stackoverflow.com/a/69326676

This patch adds two functions which efficiently generate a unique list of (shader) graph edges and uses those lists instead of graph iterators.

For one especially complex material on which I tested this fix, shader code generation time decreased from 156.13 sec to 0.08 sec (almost 2000x speedup). Number of visited edges in ShaderGraph::optimize() decreased from 42M to ~600.

I'm not sure if the best approach is to add those two functions next to current graph iterators or maybe those iterators should be replaced altogether. Another solution which I see would be to fix the graph iterators, but IMO they add a lot of overhead and it's faster to simply use a function which returns a list of all edges in a given graph in std::vector.

@nadult nadult force-pushed the fix-edge-iteration-performance branch from 5de4d9f to 322ab92 Compare September 20, 2024 13:29
In complex materials graph and shader graph edge iteration can be
extremely slow, because some edges may be visited unnecessarily
multiple times. This is especially noticable in two functions:
ShaderGraph::addUpstreamDependencies and ShaderGraph::optimize() .

GraphIterator and ShaderGraphEdgeIterator classes iterate over DAGs
without marking nodes as visited, which may lead to exponential
traversal time for some DAGs:
https://stackoverflow.com/a/69326676

This patch adds two functions which efficiently generate a unique list
of (shader) graph edges and uses those lists instead of graph iterators.
@nadult nadult force-pushed the fix-edge-iteration-performance branch from 322ab92 to e8c8ccf Compare September 20, 2024 14:24
@jstone-lucasfilm
Copy link
Member

This is a really interesting proposal, @nadult, and my main concern is that we'd have two subtly different approaches for traversing graphs in MaterialX, each of which would need to be maintained, validated, and extended in the future.

Perhaps it would actually be better to upgrade the GraphIterator class (as in one of your suggestions above), storing the required visitation data directly in this class to avoid duplicate edges?

This would still allow the addition of a top-level uniqueGraphEdges convenience method, which would be defined as a simple wrapper around traverseGraph, and the traversal system would remain unified for future maintenance.

@nadult
Copy link
Contributor Author

nadult commented Sep 23, 2024

OK, makes sense. I will try to prepare a new solution this week with your suggestions included.

@kwokcb
Copy link
Contributor

kwokcb commented Sep 23, 2024

For this, I think it would be useful to have the traversal API have 2 extensions:

  1. Still allow for incremental traversal using the existing iterator but allow the option to avoid duplicates. Guess that could be the default on a version bump?
  2. Have the ability to get all unique edges via the uniqueGraphEdges which pre-traversses and returns all edges.

Item (1) I think is useful to preserve as an integration may iterate and want to perform some action during traversal, including extracting out additional information which may be hard to get afterwards since not all information during traversal is cached on an edge.

Of course I only looked at the changes briefly, so just my initial thoughts. Thoughts on this ? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants