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

Creating variants becomes slower when there are more referenced files in the scene #2010

Open
juergen3ds opened this issue Aug 24, 2022 · 9 comments

Comments

@juergen3ds
Copy link

Description of Issue

Creating the same number of variants becomes much slower when there are more referenced files in the scene (increase numFiles in code below). It does not change if they are added as payload or reference, the second for loop with AddVariantSet becomes slower.

For 50 files it takes 5 seconds to create the variants, for 500 it takes 35 seconds and for 1500 ~205 seconds.

Putting the second for loop in a scope with a SdfChangeBlock seems to improve the performance a lot. Is it save to use SdfChangeBlock for AddVariantSet?

Steps to Reproduce

void perfTest()
{
	using namespace pxr;

	constexpr int numSets = 500;
	constexpr int numFiles = 50;

	UsdStageRefPtr stage = pxr::UsdStage::CreateNew("C:\\temp\\usddemo\\test.usda");
	UsdPrim prim = stage->DefinePrim(pxr::SdfPath("/scene"));
	stage->SetDefaultPrim(prim);

	for (int i = 0; i < numFiles; ++i)
	{
		std::string name = "testFile_" + std::to_string(i) + ".usda";
		pxr::UsdStageRefPtr subStage = pxr::UsdStage::CreateNew("C:\\temp\\usddemo\\" + name);
		subStage->SetDefaultPrim(subStage->DefinePrim(pxr::SdfPath("/scene")));
		prim.GetPayloads().AddPayload(name);
		subStage->Save();
	}

	UsdVariantSets variantSets = prim.GetVariantSets();

	for (int i = 0; i < numSets; ++i)
	{
		variantSets.AddVariantSet("varSet_" + std::to_string(i));
	}

	stage->Save();
}

Package Versions

22.03

@sunyab
Copy link
Contributor

sunyab commented Aug 25, 2022

Filed as internal issue #USD-7585

@spiffmon
Copy link
Member

Hi @juergen3ds ,
This behavior is simply another aspect of the earlier Issue #1957 you filed. Just because the VariantSets you are creating are known by you to be empty, the composition engine cannot know that while "recomposing" the prim (which happens after you create each variantSet), and therefore does the expensive behavior I described of searching through every arc that affects the prim to attempt to locate a variant selection opinion for each variantSet. So the number of references/payloads/inherits/specializes you've authored on the prim prim affects that cost.

It is not, in general, safe to use an SdfChangeBlock with Usd-level API's, so again, as in the earlier Issue, we'd recommend using Sdf API's for doing large-scale authoring that would trigger recomposition (i.e. adding prims and/or composition arcs).

But if I may, do these queries come from experiments just to get the lay of the USD-authoring-performance landscape, or do you actually have scenarios in mind that actually seem to call for such broad fan-out of composition arcs? If the latter, are you able to describe them? It's not the kind of graph structure we encounter very often, and therefore is outside our usual performance optimization gaze.

@juergen3ds
Copy link
Author

Hi @spiffmon ,
I reported this one for the referenced files, because it is much slower with referenced files. If I create the same structure with 1500 prims instead of file references the variant set creation is much faster (~5 sec with prims, ~205 sec with referenced files).

The scenario from above is a simplified version of our actual scenes. We are working with car models which can contain hundreds of parts (each part is a separate file) and also hundreds of variant sets to configure these. With such a scene it takes for ever to create the variants, because the files contain actual data and are not empty like in the above example. When I save the same scene as a single USD file (all parts integrated), the variant set creation still takes some time, but is much faster than with file references.

@spiffmon
Copy link
Member

spiffmon commented Aug 25, 2022

Thanks for the context, @juergen3ds ! In time we might be able to find some gains in the underlying composition algorithms, but for now I have two possible suggestions:

  1. Go the Sdf-authoring route for the VariantSets, and you'll need to do that for creating the variants inside the VariantSets, as well, as in Issue Creating nested variant sets becomes exponentially slower when adding more variant sets #1957
  2. If you are able to restructure your setup so that the parts-references can be added to a child prim of the "configuration prim" (i.e. the one with all the VariantSets on it, then you won't incur behavior that is sensitive to numFiles. Your variantSets will still be able to override anything on any of the parts, though your hierarchy will be a little different. Would that be acceptable?

The advantage of the second approach is that it will also speed up the runtime, i.e. all the times you open the stage after it has been created.

@juergen3ds
Copy link
Author

Hi @spiffmon ,
I'm not sure, if I understood your second approach correctly.
You mean creating a child prim like this;
UsdPrim childPrim = stage->DefinePrim(pxr::SdfPath("/scene/child"));
and then add the parts there
childPrim.GetPayloads().AddPayload(name);

This improved the performance a little bit (19 sec to create the variants, instead of 35 sec before), but it is not really much faster.

In our real scenes the structure is more complex and the parts-references are in a lot of different prims, but it is still very slow to create the variants. I just added all parts-references in one prim here for a simple example.

@spiffmon
Copy link
Member

spiffmon commented Sep 1, 2022

Hi @juergen3ds ,
Your report generated some creative thought on the team. We have a fix that will improve composition time in all cases that involve large numbers of composition arcs of any flavor. It makes a noticeable, but not nearly total, improvement in your scenario, and it should be available in 22.11. There's another idea that is specific to variant sets/selections that might make a much more substantial improvement specifically in the ton-of-variantSets case. We're not sure when we'll be able to try that one yet, though - but we won't lose track of it.

In the meantime, if you are trying to stick to the Usd-level API's, I wanted to follow up on your observation that references and payloads had the same performance characteristics when authoring. To really benefit from using payloads, I think you would need to create your UsdStage using the UsdInitialLoadSet::LoadNone optional parameter. I'm not sure how far that workflow will scale, i.e. whether you will be able to easily create your variant overrides without having the payloads loaded, but you can play with it.

Thanks for reporting this - it's helping to improve USD's scalability in a new direction!

@juergen3ds
Copy link
Author

Hi @spiffmon ,
Thanks for looking into this.
Is there already a planned date when 22.11 will be a release version?

@spiffmon
Copy link
Member

spiffmon commented Sep 2, 2022 via email

@spiffmon
Copy link
Member

Another progress update on this and Issue #1957 ... while we're not closing them yet, some work just landed in time for 24.03 that makes significant progress in both cases. Would appreciate your re-evaluating when the release comes out, @juergen3ds !

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

No branches or pull requests

3 participants