PIE slowdowns due to additional levels streaming initialization

Described the issue in the steps to reprdouce.

Workaround - we implemented a modified check:

(bIsOwningWorldGameWorld && bIsMainWorldLevel) || OwningWorld->WorldType == EWorldType::Editor

as we observed through debugging that most of those “pulled-in” worlds have their WorldType as Inactive rather than Editor.

I am seeking advice on what consequences this change might have and also if this is a know issue and if there is a better workaround for this.

[Attachment Removed]

Steps to Reproduce
Steps:

  1. open a world partitioned level A for edit
    1. This level A should be included as level instance into another level B
  2. delete an actor
    1. if the A level opened in p.1 has other maps (e.g. B) referencing it, those are loaded to validate/update references
    2. ULevel::OnLevelLoaded() in Level.cpp, performs a series of checks, and when finding out that the loaded level has world partition subsystem, Initializes it for level B as well
  3. Start PIE
    1. We observe that now all levels(e.g. B) are pulled in when validating the delete are going through actor desc validation which costs CPU and log spam (we had some errors / warnings at the time)
      1. These errors are misleading as they have nothing to do with level being tested
    2. Eventually, none of these levels actually contribute to PIE world so it feels like the work done on PIE is unnecessary as it slows down PIE times and over time could slow down the editor by putting memory pressure on the log pane (due to log spam).
      [Attachment Removed]

Hello.

Can you provide more context on the proposed change? Which method do you modify and where?

Regards,

Martin

[Attachment Removed]

We have modified ULevel::OnLevelLoaded() in Level.cpp. We had to update it slightly to better support PLA.

original code:
if (bIsMainWorldLevel || bInitializeForEditor)
{
...
 
modified code: 
if ((bIsOwningWorldGameWorld && bIsMainWorldLevel) 
|| OwningWorld->WorldType == EWorldType::Editor 
|| OwningWorld->WorldType == EWorldType::EditorPreview)
{
...

(edit) here is this check https://github.com/EpicGames/UnrealEngine/blob/71fe36aac5a8df5ccd66c763ffc902b29b6a9c43/Engine/Source/Runtime/Engine/Private/Level.cpp\#L3514

[Attachment Removed]

Thanks for the clarification. After discussion with the team, we think there might be unforeseen side effects to skip the initialization. We are currently evaluating another avenue to reduce the unrequired work. In UWorldPartition::RegisterDelegates(), only register the first 4 delegates for EWorldType::Editor. This prevent the validation code to run on the extra levels.

void UWorldPartition::RegisterDelegates()
{
	check(World); 
 
#if WITH_EDITOR
	if (GEditor && !IsTemplate() && !World->IsGameWorld() && !IsRunningCookCommandlet())
	{
		if (IsMainWorldPartition())
		{
			// PIE lifecycle delegates are only relevant for the world PIE will duplicate from, i.e. the editor world.
			// Worlds that are incidentally loaded and initialized as Inactive (see UEditorEngine::InitializeNewlyCreatedInactiveWorld)
			// are never a PIE duplication source, so PrepareEditorGameWorld would run a full GenerateStreaming on every PIE
			// start and discard the result, while polluting the map check dialog with errors unrelated to the played level.
			if (World->WorldType == EWorldType::Editor)
			{
				FEditorDelegates::PreBeginPIE.AddUObject(this, &UWorldPartition::OnPreBeginPIE);
				FEditorDelegates::PrePIEEnded.AddUObject(this, &UWorldPartition::OnPrePIEEnded);
				FEditorDelegates::CancelPIE.AddUObject(this, &UWorldPartition::OnCancelPIE);
				FGameDelegates::Get().GetEndPlayMapDelegate().AddUObject(this, &UWorldPartition::ShutdownEditorGameWorld);
			}
 
			// Those are needed by any initialized world partition, whatever the world type, to keep the actor desc container consistent.
			GEditor->OnLevelActorDeleted().AddUObject(this, &UWorldPartition::OnLevelActorDeleted);
			GEditor->OnPostBugItGoCalled().AddUObject(this, &UWorldPartition::OnPostBugItGoCalled);
			GEditor->OnEditorClose().AddUObject(this, &UWorldPartition::SavePerUserSettings);
			FWorldDelegates::OnPostWorldRename.AddUObject(this, &UWorldPartition::OnWorldRenamed);
		}
 
...

[Attachment Removed]

Thanks a lot for your reply!

We’ll test this and provide an update.

[Attachment Removed]