浏览代码

Prefab/propagation benchmarks with nested prefabs (#9183)

* Added benchmarks for adding and removing nested prefabs

Signed-off-by: srikappa-amzn <[email protected]>

* Removed assert_ macros, pauseTiming and resumetiming from propagation benchmarks

Signed-off-by: srikappa-amzn <[email protected]>

* Fixing copyright formatting to pass AR validation

Signed-off-by: srikappa-amzn <[email protected]>
srikappa-amzn 3 年之前
父节点
当前提交
eeeb16c3ab

+ 166 - 0
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.cpp

@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#if defined(HAVE_BENCHMARK)
+
+#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
+#include <AzToolsFramework/ToolsComponents/EditorInspectorComponent.h>
+#include <Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.h>
+
+namespace Benchmark
+{
+    void PropagationBenchmarkFixture::UpdateTemplate()
+    {
+        PrefabDom updatedPrefabDom;
+        PrefabDomUtils::StoreInstanceInPrefabDom(*m_instanceCreated, updatedPrefabDom);
+        PrefabDom& enclosingTemplatePrefabDom = m_prefabSystemComponent->FindTemplateDom(m_instanceCreated->GetTemplateId());
+        enclosingTemplatePrefabDom.CopyFrom(updatedPrefabDom, enclosingTemplatePrefabDom.GetAllocator());
+        m_instanceUpdateExecutorInterface->AddTemplateInstancesToQueue(m_instanceCreated->GetTemplateId(), *m_instanceCreated);
+    }
+
+    void PropagationBenchmarkFixture::UpdateComponent(benchmark::State& state)
+    {
+        for (auto _ : state)
+        {
+            float worldX = 0.0f;
+            AZ::TransformBus::EventResult(worldX, m_entityModify->GetId(), &AZ::TransformInterface::GetWorldX);
+
+            // Move the entity and update the template to capture this transform component change.
+            AZ::TransformBus::Event(m_entityModify->GetId(), &AZ::TransformInterface::SetWorldX, worldX + 1);
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+        }
+
+        state.SetComplexityN(state.range());
+    }
+
+    void PropagationBenchmarkFixture::AddComponent(benchmark::State& state)
+    {
+        m_entityModify->Deactivate();
+        for (auto _ : state)
+        {
+            // Add another component and update the template to capture this change.
+            AZ::Component* inspectorComponent = m_entityModify->CreateComponent<AzToolsFramework::Components::EditorInspectorComponent>();
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+
+            // Remove the second component added. This will make sure that when multiple iterations are done, we will always be going from
+            // one components to two components.
+            m_entityModify->RemoveComponent(inspectorComponent);
+            delete inspectorComponent;
+            inspectorComponent = nullptr;
+        }
+
+        state.SetComplexityN(state.range());
+    }
+
+    void PropagationBenchmarkFixture::RemoveComponent(benchmark::State& state)
+    {
+        m_entityModify->Deactivate();
+
+        for (auto _ : state)
+        {
+            const AZStd::vector<AZ::Component*>& components = m_entityModify->GetComponents();
+            AZ::Component* transformComponent = components.front();
+            m_entityModify->RemoveComponent(transformComponent);
+            delete transformComponent;
+            transformComponent = nullptr;
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+
+            // Add the component back. This will make sure that when multiple iterations are done, we will always be going from
+            // zero components to one component.
+            m_entityModify->CreateComponent(AZ::TransformComponentTypeId);
+        }
+
+        state.SetComplexityN(state.range());
+    }
+
+    void PropagationBenchmarkFixture::AddEntity(benchmark::State& state)
+    {
+        for (auto _ : state)
+        {
+            // Add an entity and update the template.
+            AZStd::unique_ptr<AZ::Entity> newEntity = AZStd::make_unique<AZ::Entity>("Added Entity");
+            AZ::EntityId newEntityId = newEntity->GetId();
+            m_instanceCreated->AddEntity(AZStd::move(newEntity));
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+
+            // Remove the entityadded. This will make sure that when multiple iterations are done, we will always be going from
+            // 'n' entities to 'n+1' entities.
+            newEntity = m_instanceCreated->DetachEntity(newEntityId);
+        }
+
+        state.SetComplexityN(state.range());
+    }
+
+    void PropagationBenchmarkFixture::RemoveEntity(benchmark::State& state)
+    {
+        for (auto _ : state)
+        {
+            // Add an entity and update the template.
+            AZStd::unique_ptr<AZ::Entity> detachedEntity = m_instanceCreated->DetachEntity(m_entityModify->GetId());
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+
+            // Add back the entity removed. This will make sure that when multiple iterations are done, we will always be going from
+            // 'n' entities to 'n-1' entities.
+            m_instanceCreated->AddEntity(AZStd::move(detachedEntity));
+        }
+
+        state.SetComplexityN(state.range());
+    }
+
+    void PropagationBenchmarkFixture::AddNestedInstance(benchmark::State& state, TemplateId nestedPrefabTemplateId)
+    {
+        for (auto _ : state)
+        {
+            // Add an entity and update the template.
+            AZStd::unique_ptr<Instance> nestedInstance = AZStd::make_unique<Instance>("Added nested instance");
+            Instance& addedInstance =
+                m_instanceCreated->AddInstance(AZStd::move(m_prefabSystemComponent->InstantiatePrefab(nestedPrefabTemplateId)));
+            const InstanceAlias& instanceAlias = addedInstance.GetInstanceAlias();
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+
+            // Remove the nested prefab added. This will make sure that when multiple iterations are done, we will always be going from
+            // 'n' nested prefabs to 'n+1' nested prefabs.
+            nestedInstance = m_instanceCreated->DetachNestedInstance(instanceAlias);
+        }
+
+        state.SetComplexityN(state.range());
+    }
+
+    void PropagationBenchmarkFixture::RemoveNestedInstance(benchmark::State& state, TemplateId nestedPrefabTemplateId)
+    {
+        for (auto _ : state)
+        {
+            AZStd::vector<InstanceAlias> nestedInstanceAliases = m_instanceCreated->GetNestedInstanceAliases(nestedPrefabTemplateId);
+            AZStd::unique_ptr<Instance> detachedNestedInstance = m_instanceCreated->DetachNestedInstance(nestedInstanceAliases.back());
+            UpdateTemplate();
+
+            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
+
+            // Add back the nested instance removed. This will make sure that when multiple iterations are done, we will always be going
+            // from 'n' nested instances to 'n-1' nested instances.
+            m_instanceCreated->AddInstance(AZStd::move(detachedNestedInstance));
+        }
+
+        // After the last iteration, the template should be updated to avoid link deletion failures.
+        UpdateTemplate();
+        state.SetComplexityN(state.range());
+    }
+} // namespace Benchmark
+
+#endif

+ 40 - 0
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#if defined(HAVE_BENCHMARK)
+
+#pragma once
+
+#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
+#include <AzToolsFramework/ToolsComponents/EditorInspectorComponent.h>
+#include <Prefab/Benchmark/PrefabBenchmarkFixture.h>
+
+namespace Benchmark
+{
+    using namespace AzToolsFramework::Prefab;
+
+    //! This class captures benchmarks for propagating changes to a single prefab instance with multiple entities that are side-by-side.
+    class PropagationBenchmarkFixture : public Benchmark::BM_Prefab
+    {
+    protected:
+        void UpdateTemplate();
+        void UpdateComponent(benchmark::State& state);
+        void AddComponent(benchmark::State& state);
+        void RemoveComponent(benchmark::State& state);
+        void AddEntity(benchmark::State& state);
+        void RemoveEntity(benchmark::State& state);
+        void AddNestedInstance(benchmark::State& state, TemplateId nestedPrefabTemplateId);
+        void RemoveNestedInstance(benchmark::State& state, TemplateId nestedPrefabTemplateId);
+
+        AZ::Entity* m_entityModify;
+        AZStd::unique_ptr<Instance> m_instanceCreated;
+        AZStd::unique_ptr<Instance> m_instanceToUseForPropagation;
+    };
+
+} // namespace Benchmark
+
+#endif

+ 42 - 187
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Propagation/SingleInstanceMultipleEntityBenchmarks.cpp

@@ -7,224 +7,79 @@
  */
 #if defined(HAVE_BENCHMARK)
 
-#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
-#include <AzToolsFramework/ToolsComponents/EditorInspectorComponent.h>
-#include <Prefab/Benchmark/PrefabBenchmarkFixture.h>
+#include <Prefab/Benchmark/Propagation/SingleInstanceMultipleEntityBenchmarks.h>
 
+#define REGISTER_MULTIPLE_ENTITY_BENCHMARK(BaseClass, Method)                                                                              \
+    BENCHMARK_REGISTER_F(BaseClass, Method)                                                                                                \
+        ->RangeMultiplier(10)                                                                                                              \
+        ->Range(100, 10000)                                                                                                                \
+        ->Unit(benchmark::kMillisecond)                                                                                                    \
+        ->Complexity();
 
 namespace Benchmark
 {
     using namespace AzToolsFramework::Prefab;
 
-    //! This class captures benchmarks for propagating changes to a single prefab instance with multiple entities that are side-by-side.
-    class SingleInstanceMultipleEntityBenchmarks : public Benchmark::BM_Prefab
+    void SingleInstanceMultipleEntityBenchmarks::SetupHarness(const benchmark::State& state)
     {
-    protected:
-        void SetupHarness(const benchmark::State& state) override
-        {
-            BM_Prefab::SetupHarness(state);
-            CreateFakePaths(1);
-            const auto& templatePath = m_paths.front();
-            const unsigned int numEntities = static_cast<unsigned int>(state.range());
-
-            AZStd::vector<AZ::Entity*> entities;
-            for (unsigned int i = 1; i < numEntities; i++)
-            {
-                entities.emplace_back(CreateEntity("Entity"));
-            }
-
-            m_entityModify= CreateEntity("Entity", AZ::EntityId());
-            entities.emplace_back(m_entityModify);
-
-            m_instanceCreated = m_prefabSystemComponent->CreatePrefab(entities, {}, templatePath);
-            TemplateId templateToInstantiateId = m_instanceCreated->GetTemplateId();
-
-            // We need 2 prefab instances: One to make the original change to; And one to propagate that change to.
-            m_instanceToUseForPropagation = m_prefabSystemComponent->InstantiatePrefab(templateToInstantiateId);
-        }
+        BM_Prefab::SetupHarness(state);
+        CreateFakePaths(1);
+        const auto& templatePath = m_paths.front();
+        const unsigned int numEntities = static_cast<unsigned int>(state.range());
 
-        void TeardownHarness(const benchmark::State& state) override
+        AZStd::vector<AZ::Entity*> entities;
+        for (unsigned int i = 1; i < numEntities; i++)
         {
-            m_instanceCreated.reset();
-            m_instanceToUseForPropagation.reset();
-            BM_Prefab::TeardownHarness(state);
+            entities.emplace_back(CreateEntity("Entity"));
         }
 
-    protected:
-        void UpdateTemplate()
-        {
-            PrefabDom updatedPrefabDom;
-            PrefabDomUtils::StoreInstanceInPrefabDom(*m_instanceCreated, updatedPrefabDom);
-            PrefabDom& enclosingTemplatePrefabDom = m_prefabSystemComponent->FindTemplateDom(m_instanceCreated->GetTemplateId());
-            enclosingTemplatePrefabDom.CopyFrom(updatedPrefabDom, enclosingTemplatePrefabDom.GetAllocator());
-            m_instanceUpdateExecutorInterface->AddTemplateInstancesToQueue(m_instanceCreated->GetTemplateId(), *m_instanceCreated);
-        }
-
-        AZ::Entity* m_entityModify;
-        AZStd::unique_ptr<Instance> m_instanceCreated;
-        AZStd::unique_ptr<Instance> m_instanceToUseForPropagation;
-    };
-
-    BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateUpdateComponentChange)(benchmark::State& state)
-    {
-        for (auto _ : state)
-        {
-            state.PauseTiming();
-            float worldX = 0.0f;
-            AZ::TransformBus::EventResult(worldX, m_entityModify->GetId(), &AZ::TransformInterface::GetWorldX);
+        m_entityModify = CreateEntity("Entity", AZ::EntityId());
+        entities.emplace_back(m_entityModify);
 
-            // Move the entity and update the template to capture this transform component change.
-            AZ::TransformBus::Event(m_entityModify->GetId(), &AZ::TransformInterface::SetWorldX, worldX + 1);
-            UpdateTemplate();
-            state.ResumeTiming();
+        m_instanceCreated = m_prefabSystemComponent->CreatePrefab(entities, {}, templatePath);
+        TemplateId templateToInstantiateId = m_instanceCreated->GetTemplateId();
 
-            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
-        }
+        // We need 2 prefab instances: One to make the original change to; And one to propagate that change to.
+        m_instanceToUseForPropagation = m_prefabSystemComponent->InstantiatePrefab(templateToInstantiateId);
+    }
 
-        state.SetComplexityN(state.range());
+    void SingleInstanceMultipleEntityBenchmarks::TeardownHarness(const benchmark::State& state)
+    {
+        m_instanceCreated.reset();
+        m_instanceToUseForPropagation.reset();
+        BM_Prefab::TeardownHarness(state);
     }
 
-    BENCHMARK_REGISTER_F(SingleInstanceMultipleEntityBenchmarks, PropagateUpdateComponentChange)
-        ->RangeMultiplier(10)
-        ->Range(100, 10000)
-        ->Unit(benchmark::kMillisecond)
-        ->Complexity();
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateUpdateComponentChange)(benchmark::State& state)
+    {
+        UpdateComponent(state);
+    }
+    REGISTER_MULTIPLE_ENTITY_BENCHMARK(SingleInstanceMultipleEntityBenchmarks, PropagateUpdateComponentChange);
+    
     
     BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateAddComponentChange)(benchmark::State& state)
     {
-        m_entityModify->Deactivate();
-        for (auto _ : state)
-        {
-            state.PauseTiming();
-            ASSERT_EQ(m_entityModify->GetComponents().size(), 1);
-
-            // Add another component and update the template to capture this change.
-            AZ::Component* inspectorComponent = m_entityModify->CreateComponent<AzToolsFramework::Components::EditorInspectorComponent>();
-            ASSERT_EQ(m_entityModify->GetComponents().size(), 2);
-            UpdateTemplate();
-            state.ResumeTiming();
-
-            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
-            state.PauseTiming();
-
-            // Remove the second component added. This will make sure that when multiple iterations are done, we will always be going from
-            // one components to two components.
-            m_entityModify->RemoveComponent(inspectorComponent);
-            ASSERT_EQ(m_entityModify->GetComponents().size(), 1);
-            delete inspectorComponent;
-            inspectorComponent = nullptr;
-            UpdateTemplate();
-        }
-
-        state.SetComplexityN(state.range());
+        AddComponent(state);
     }
-
-    BENCHMARK_REGISTER_F(SingleInstanceMultipleEntityBenchmarks, PropagateAddComponentChange)
-        ->RangeMultiplier(10)
-        ->Range(100, 10000)
-        ->Unit(benchmark::kMillisecond)
-        ->Complexity();
+    REGISTER_MULTIPLE_ENTITY_BENCHMARK(SingleInstanceMultipleEntityBenchmarks, PropagateAddComponentChange);
     
     BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateRemoveComponentChange)(benchmark::State& state)
     {
-        m_entityModify->Deactivate();
-
-        for (auto _ : state)
-        {
-            state.PauseTiming();
-            const AZStd::vector<AZ::Component*>& components = m_entityModify->GetComponents();
-            ASSERT_EQ(m_entityModify->GetComponents().size(), 1);
-            AZ::Component* transformComponent = components.front();
-            m_entityModify->RemoveComponent(transformComponent);
-            delete transformComponent;
-            transformComponent = nullptr;
-            ASSERT_EQ(m_entityModify->GetComponents().size(), 0);
-            UpdateTemplate();
-            state.ResumeTiming();
-
-            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
-            state.PauseTiming();
-
-            // Add the component back. This will make sure that when multiple iterations are done, we will always be going from
-            // zero components to one component.
-            m_entityModify->CreateComponent(AZ::TransformComponentTypeId);
-            ASSERT_EQ(m_entityModify->GetComponents().size(), 1);
-            UpdateTemplate();
-        }
-
-        state.SetComplexityN(state.range());
+        RemoveComponent(state);
     }
-
-    BENCHMARK_REGISTER_F(SingleInstanceMultipleEntityBenchmarks, PropagateRemoveComponentChange)
-        ->RangeMultiplier(10)
-        ->Range(100, 10000)
-        ->Unit(benchmark::kMillisecond)
-        ->Complexity();
+    REGISTER_MULTIPLE_ENTITY_BENCHMARK(SingleInstanceMultipleEntityBenchmarks, PropagateRemoveComponentChange);
 
     BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateAddEntityChange)(benchmark::State& state)
     {
-        for (auto _ : state)
-        {
-            state.PauseTiming();
-
-            // Add an entity and update the template.
-            AZStd::unique_ptr<AZ::Entity> newEntity = AZStd::make_unique<AZ::Entity>("Added Entity");
-            AZ::EntityId newEntityId = newEntity->GetId();
-            ASSERT_TRUE(newEntity != nullptr);
-            m_instanceCreated->AddEntity(AZStd::move(newEntity));
-            UpdateTemplate();
-            state.ResumeTiming();
-
-            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
-            state.PauseTiming();
-
-            // Remove the entityadded. This will make sure that when multiple iterations are done, we will always be going from
-            // 'n' entities to 'n+1' entities.
-            ASSERT_TRUE(newEntity == nullptr);
-            newEntity = m_instanceCreated->DetachEntity(newEntityId);
-            ASSERT_TRUE(newEntity != nullptr);
-            UpdateTemplate();
-        }
-
-        state.SetComplexityN(state.range());
+        AddEntity(state);
     }
+    REGISTER_MULTIPLE_ENTITY_BENCHMARK(SingleInstanceMultipleEntityBenchmarks, PropagateAddEntityChange);
 
-    BENCHMARK_REGISTER_F(SingleInstanceMultipleEntityBenchmarks, PropagateAddEntityChange)
-        ->RangeMultiplier(10)
-        ->Range(100, 10000)
-        ->Unit(benchmark::kMillisecond)
-        ->Complexity();
-
-    BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateDetachEntityChange)(benchmark::State& state)
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleEntityBenchmarks, PropagateRemoveEntityChange)(benchmark::State& state)
     {
-        for (auto _ : state)
-        {
-            state.PauseTiming();
-
-            // Add an entity and update the template.
-            AZStd::unique_ptr<AZ::Entity> detachedEntity = m_instanceCreated->DetachEntity(m_entityModify->GetId());
-            ASSERT_TRUE(detachedEntity != nullptr);
-            UpdateTemplate();
-            state.ResumeTiming();
-
-            m_instanceUpdateExecutorInterface->UpdateTemplateInstancesInQueue();
-            state.PauseTiming();
-
-            // Add back the entity removed. This will make sure that when multiple iterations are done, we will always be going from
-            // 'n' entities to 'n-1' entities.
-            m_instanceCreated->AddEntity(AZStd::move(detachedEntity));
-            UpdateTemplate();
-        }
-
-        state.SetComplexityN(state.range());
+        RemoveEntity(state);
     }
-
-    BENCHMARK_REGISTER_F(SingleInstanceMultipleEntityBenchmarks, PropagateDetachEntityChange)
-        ->RangeMultiplier(10)
-        ->Range(100, 10000)
-        ->Unit(benchmark::kMillisecond)
-        ->Complexity();
+    REGISTER_MULTIPLE_ENTITY_BENCHMARK(SingleInstanceMultipleEntityBenchmarks, PropagateRemoveEntityChange);
         
 } // namespace Benchmark
-
 #endif

+ 24 - 0
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Propagation/SingleInstanceMultipleEntityBenchmarks.h

@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#if defined(HAVE_BENCHMARK)
+
+#pragma once
+
+#include <Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.h>
+
+namespace Benchmark
+{
+    //! This class captures benchmarks for propagating changes to a single prefab instance with multiple entities that are side-by-side.
+    class SingleInstanceMultipleEntityBenchmarks : public PropagationBenchmarkFixture
+    {
+    protected:
+        void SetupHarness(const benchmark::State& state) override;
+        void TeardownHarness(const benchmark::State& state) override;
+    };
+} // namespace Benchmark
+#endif

+ 123 - 0
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Propagation/SingleInstanceMultipleNestedInstancesBenchmarks.cpp

@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#if defined(HAVE_BENCHMARK)
+
+#include <Prefab/Benchmark/Propagation/SingleInstanceMultipleNestedInstancesBenchmarks.h>
+
+#define REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(BaseClass, Method)                                                                    \
+    BENCHMARK_REGISTER_F(BaseClass, Method)                                                                                                \
+        ->Args({ 10, 100 })                                                                                                                \
+        ->Args({ 100, 10 })                                                                                                                \
+        ->Args({ 10, 1000 })                                                                                                               \
+        ->Args({ 1000, 10 })                                                                                                               \
+        ->Args({ 1, 10000 })                                                                                                               \
+        ->Args({ 10000, 1 })                                                                                                               \
+        ->ArgNames({ "NestedPrefabs", "EntitiesInEachNestedPrefab" })                                                                      \
+        ->Unit(benchmark::kMillisecond)                                                                                                    \
+        ->Complexity();
+
+namespace Benchmark
+{
+    using namespace AzToolsFramework::Prefab;
+
+    void SingleInstanceMultipleNestedInstancesBenchmarks::SetupHarness(const benchmark::State& state)
+    {
+        BM_Prefab::SetupHarness(state);
+        CreateFakePaths(2);
+        const auto& parentTemplatePath = m_paths.front();
+        const auto& nestedTemplatePath = m_paths.back();
+        const unsigned int nestedPrefabsCount = static_cast<unsigned int>(state.range(0));
+        const unsigned int entitiesCountInNestedPrefab = static_cast<unsigned int>(state.range(1));
+
+        AZStd::vector<AZ::Entity*> entitiesInParentInstance;
+
+        AZStd::vector<AZStd::unique_ptr<Instance>> nestedInstances;
+        nestedInstances.reserve(nestedPrefabsCount);
+
+        AZStd::vector<AZ::Entity*> entitiesInNestedInstance;
+        entitiesInNestedInstance.reserve(entitiesCountInNestedPrefab);
+        for (unsigned int entityCounter = 0; entityCounter < entitiesCountInNestedPrefab; entityCounter++)
+        {
+            entitiesInNestedInstance.emplace_back(CreateEntity("Entity"));
+        }
+        AZStd::unique_ptr<Instance> nestedInstance =
+            m_prefabSystemComponent->CreatePrefab(entitiesInNestedInstance, {}, nestedTemplatePath);
+        m_nestedPrefabTemplateId = nestedInstance->GetTemplateId();
+        nestedInstance.reset();
+
+        for (unsigned int nestedInstanceCounter = 0; nestedInstanceCounter < nestedPrefabsCount; nestedInstanceCounter++)
+        {
+            nestedInstances.emplace_back(AZStd::move(m_prefabSystemComponent->InstantiatePrefab(m_nestedPrefabTemplateId)));
+        }
+
+        m_entityModify = CreateEntity("Entity", AZ::EntityId());
+        entitiesInParentInstance.emplace_back(m_entityModify);
+
+        m_instanceCreated =
+            m_prefabSystemComponent->CreatePrefab(entitiesInParentInstance, AZStd::move(nestedInstances), parentTemplatePath);
+        TemplateId templateToInstantiateId = m_instanceCreated->GetTemplateId();
+
+        // We need 2 prefab instances: One to make the original change to; And one to propagate that change to.
+        m_instanceToUseForPropagation = m_prefabSystemComponent->InstantiatePrefab(templateToInstantiateId);
+    }
+
+    void SingleInstanceMultipleNestedInstancesBenchmarks::TeardownHarness(const benchmark::State& state)
+    {
+        m_instanceCreated.reset();
+        m_instanceToUseForPropagation.reset();
+        BM_Prefab::TeardownHarness(state);
+    }
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateUpdateComponentChange)(benchmark::State& state)
+    {
+        UpdateComponent(state);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(
+        SingleInstanceMultipleNestedInstancesBenchmarks, PropagateUpdateComponentChange);
+        
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateAddComponentChange)(benchmark::State& state)
+    {
+        AddComponent(state);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(
+        SingleInstanceMultipleNestedInstancesBenchmarks, PropagateAddComponentChange);
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateRemoveComponentChange)(benchmark::State& state)
+    {
+        RemoveComponent(state);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateRemoveComponentChange);
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateAddEntityChange)(benchmark::State& state)
+    {
+        AddEntity(state);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateAddEntityChange);
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateRemoveEntityChange)(benchmark::State& state)
+    {
+        RemoveEntity(state);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateRemoveEntityChange);
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateAddNestedPrefabChange)(benchmark::State& state)
+    {
+        AddNestedInstance(state, m_nestedPrefabTemplateId);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateAddNestedPrefabChange);
+
+    BENCHMARK_DEFINE_F(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateRemoveNestedPrefabChange)(benchmark::State& state)
+    {
+        RemoveNestedInstance(state, m_nestedPrefabTemplateId);
+    }
+    REGISTER_MULTIPLE_NESTED_INSTANCES_BENCHMARK(SingleInstanceMultipleNestedInstancesBenchmarks, PropagateRemoveNestedPrefabChange);
+
+} // namespace Benchmark
+#endif

+ 28 - 0
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Propagation/SingleInstanceMultipleNestedInstancesBenchmarks.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#if defined(HAVE_BENCHMARK)
+
+#pragma once
+
+#include <Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.h>
+
+namespace Benchmark
+{
+    using namespace AzToolsFramework::Prefab;
+
+    //! This class captures benchmarks for propagating changes to a single prefab instance with multiple nested instances that are siblings.
+    class SingleInstanceMultipleNestedInstancesBenchmarks : public PropagationBenchmarkFixture
+    {
+    protected:
+        void SetupHarness(const benchmark::State& state) override;
+        void TeardownHarness(const benchmark::State& state) override;
+
+        TemplateId m_nestedPrefabTemplateId = InvalidTemplateId;
+    };
+} // namespace Benchmark
+#endif

+ 5 - 0
Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake

@@ -65,7 +65,12 @@ set(FILES
     Prefab/Benchmark/PrefabInstantiateBenchmarks.cpp
     Prefab/Benchmark/PrefabLoadBenchmarks.cpp
     Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
+    Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.cpp
+    Prefab/Benchmark/Propagation/PropagationBenchmarkFixture.h
+    Prefab/Benchmark/Propagation/SingleInstanceMultipleNestedInstancesBenchmarks.cpp
+    Prefab/Benchmark/Propagation/SingleInstanceMultipleNestedInstancesBenchmarks.h
     Prefab/Benchmark/Propagation/SingleInstanceMultipleEntityBenchmarks.cpp
+    Prefab/Benchmark/Propagation/SingleInstanceMultipleEntityBenchmarks.h
     Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
     Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h
     Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp