Merge branch 'development' into cmake/linux_fix_warn_unused
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> # Conflicts: # Code/Legacy/CrySystem/Log.cpp # Code/Tools/Standalone/Source/Driller/Annotations/AnnotationHeaderView.cpp # Code/Tools/Standalone/Source/Driller/AreaChart.cpp # Code/Tools/Standalone/Source/Driller/AreaChart.hxx # Code/Tools/Standalone/Source/Driller/ChannelDataView.cpp # Code/Tools/Standalone/Source/Driller/DrillerCaptureWindow.cpp # Code/Tools/Standalone/Source/Driller/Profiler/ProfilerDataView.cppmonroegm-disable-blank-issue-2
commit
6b96be82ea
@ -0,0 +1,9 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
ly_install_directory(DIRECTORIES .)
|
||||
@ -0,0 +1,349 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
|
||||
from ly_test_tools import LAUNCHERS
|
||||
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
|
||||
from .FileManagement import FileManagement as fm
|
||||
|
||||
# Custom test spec, it provides functionality to override files
|
||||
class EditorSingleTest_WithFileOverrides(EditorSingleTest):
|
||||
# Specify here what files to override, [(original, override), ...]
|
||||
files_to_override = [()]
|
||||
# Base directory of the files (Default path is {ProjectName})
|
||||
base_dir = None
|
||||
# True will will search sub-directories for the files in base
|
||||
search_subdirs = False
|
||||
|
||||
@classmethod
|
||||
def wrap_run(cls, instance, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
root_path = cls.base_dir
|
||||
if root_path is not None:
|
||||
root_path = os.path.join(workspace.paths.engine_root(), root_path)
|
||||
else:
|
||||
# Default to project folder
|
||||
root_path = workspace.paths.project()
|
||||
|
||||
# Try to locate both target and source files
|
||||
original_file_list, override_file_list = zip(*cls.files_to_override)
|
||||
try:
|
||||
file_list = fm._find_files(original_file_list + override_file_list, root_path, cls.search_subdirs)
|
||||
except RuntimeWarning as w:
|
||||
assert False, (
|
||||
w.message
|
||||
+ " Please check use of search_subdirs; make sure you are using the correct parent directory."
|
||||
)
|
||||
|
||||
for f in original_file_list:
|
||||
fm._restore_file(f, file_list[f])
|
||||
fm._backup_file(f, file_list[f])
|
||||
|
||||
for original, override in cls.files_to_override:
|
||||
fm._copy_file(override, file_list[override], original, file_list[override])
|
||||
|
||||
yield # Run Test
|
||||
for f in original_file_list:
|
||||
fm._restore_file(f, file_list[f])
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarly.")
|
||||
@pytest.mark.SUITE_main
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
@staticmethod
|
||||
def get_number_parallel_editors():
|
||||
return 16
|
||||
|
||||
#########################################
|
||||
# Non-atomic tests: These need to be run in a single editor because they have custom setup and teardown
|
||||
class C4044459_Material_DynamicFriction(EditorSingleTest_WithFileOverrides):
|
||||
from . import C4044459_Material_DynamicFriction as test_module
|
||||
files_to_override = [
|
||||
('physxsystemconfiguration.setreg', 'C4044459_Material_DynamicFriction.setreg_override')
|
||||
]
|
||||
base_dir = "AutomatedTesting/Registry"
|
||||
|
||||
class C4982593_PhysXCollider_CollisionLayerTest(EditorSingleTest_WithFileOverrides):
|
||||
from . import C4982593_PhysXCollider_CollisionLayerTest as test_module
|
||||
files_to_override = [
|
||||
('physxsystemconfiguration.setreg', 'C4982593_PhysXCollider_CollisionLayer.setreg_override')
|
||||
]
|
||||
base_dir = "AutomatedTesting/Registry"
|
||||
#########################################
|
||||
|
||||
class C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC(EditorSharedTest):
|
||||
from . import C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC as test_module
|
||||
|
||||
class C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies(EditorSharedTest):
|
||||
from . import C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies as test_module
|
||||
|
||||
class C15425929_Undo_Redo(EditorSharedTest):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
|
||||
class C4976243_Collision_SameCollisionGroupDiffCollisionLayers(EditorSharedTest):
|
||||
from . import C4976243_Collision_SameCollisionGroupDiffCollisionLayers as test_module
|
||||
|
||||
class C14654881_CharacterController_SwitchLevels(EditorSharedTest):
|
||||
from . import C14654881_CharacterController_SwitchLevels as test_module
|
||||
|
||||
class C17411467_AddPhysxRagdollComponent(EditorSharedTest):
|
||||
from . import C17411467_AddPhysxRagdollComponent as test_module
|
||||
|
||||
class C12712453_ScriptCanvas_MultipleRaycastNode(EditorSharedTest):
|
||||
from . import C12712453_ScriptCanvas_MultipleRaycastNode as test_module
|
||||
|
||||
class C18243586_Joints_HingeLeadFollowerCollide(EditorSharedTest):
|
||||
from . import C18243586_Joints_HingeLeadFollowerCollide as test_module
|
||||
|
||||
class C4982803_Enable_PxMesh_Option(EditorSharedTest):
|
||||
from . import C4982803_Enable_PxMesh_Option as test_module
|
||||
|
||||
class C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain(EditorSharedTest):
|
||||
from . import C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain as test_module
|
||||
|
||||
class C3510642_Terrain_NotCollideWithTerrain(EditorSharedTest):
|
||||
from . import C3510642_Terrain_NotCollideWithTerrain as test_module
|
||||
|
||||
class C4976195_RigidBodies_InitialLinearVelocity(EditorSharedTest):
|
||||
from . import C4976195_RigidBodies_InitialLinearVelocity as test_module
|
||||
|
||||
class C4976206_RigidBodies_GravityEnabledActive(EditorSharedTest):
|
||||
from . import C4976206_RigidBodies_GravityEnabledActive as test_module
|
||||
|
||||
class C4976207_PhysXRigidBodies_KinematicBehavior(EditorSharedTest):
|
||||
from . import C4976207_PhysXRigidBodies_KinematicBehavior as test_module
|
||||
|
||||
class C5932042_PhysXForceRegion_LinearDamping(EditorSharedTest):
|
||||
from . import C5932042_PhysXForceRegion_LinearDamping as test_module
|
||||
|
||||
class C5932043_ForceRegion_SimpleDragOnRigidBodies(EditorSharedTest):
|
||||
from . import C5932043_ForceRegion_SimpleDragOnRigidBodies as test_module
|
||||
|
||||
class C5959760_PhysXForceRegion_PointForceExertion(EditorSharedTest):
|
||||
from . import C5959760_PhysXForceRegion_PointForceExertion as test_module
|
||||
|
||||
class C5959764_ForceRegion_ForceRegionImpulsesCapsule(EditorSharedTest):
|
||||
from . import C5959764_ForceRegion_ForceRegionImpulsesCapsule as test_module
|
||||
|
||||
class C5340400_RigidBody_ManualMomentOfInertia(EditorSharedTest):
|
||||
from . import C5340400_RigidBody_ManualMomentOfInertia as test_module
|
||||
|
||||
class C4976210_COM_ManualSetting(EditorSharedTest):
|
||||
from . import C4976210_COM_ManualSetting as test_module
|
||||
|
||||
class C4976194_RigidBody_PhysXComponentIsValid(EditorSharedTest):
|
||||
from . import C4976194_RigidBody_PhysXComponentIsValid as test_module
|
||||
|
||||
class C5932045_ForceRegion_Spline(EditorSharedTest):
|
||||
from . import C5932045_ForceRegion_Spline as test_module
|
||||
|
||||
class C4982797_Collider_ColliderOffset(EditorSharedTest):
|
||||
from . import C4982797_Collider_ColliderOffset as test_module
|
||||
|
||||
class C4976200_RigidBody_AngularDampingObjectRotation(EditorSharedTest):
|
||||
from . import C4976200_RigidBody_AngularDampingObjectRotation as test_module
|
||||
|
||||
class C5689529_Verify_Terrain_RigidBody_Collider_Mesh(EditorSharedTest):
|
||||
from . import C5689529_Verify_Terrain_RigidBody_Collider_Mesh as test_module
|
||||
|
||||
class C5959810_ForceRegion_ForceRegionCombinesForces(EditorSharedTest):
|
||||
from . import C5959810_ForceRegion_ForceRegionCombinesForces as test_module
|
||||
|
||||
class C5959765_ForceRegion_AssetGetsImpulsed(EditorSharedTest):
|
||||
from . import C5959765_ForceRegion_AssetGetsImpulsed as test_module
|
||||
|
||||
class C6274125_ScriptCanvas_TriggerEvents(EditorSharedTest):
|
||||
from . import C6274125_ScriptCanvas_TriggerEvents as test_module
|
||||
# needs to be updated to log for unexpected lines
|
||||
# expected_lines = test_module.LogLines.expected_lines
|
||||
|
||||
class C6090554_ForceRegion_PointForceNegative(EditorSharedTest):
|
||||
from . import C6090554_ForceRegion_PointForceNegative as test_module
|
||||
|
||||
class C6090550_ForceRegion_WorldSpaceForceNegative(EditorSharedTest):
|
||||
from . import C6090550_ForceRegion_WorldSpaceForceNegative as test_module
|
||||
|
||||
class C6090552_ForceRegion_LinearDampingNegative(EditorSharedTest):
|
||||
from . import C6090552_ForceRegion_LinearDampingNegative as test_module
|
||||
|
||||
class C5968760_ForceRegion_CheckNetForceChange(EditorSharedTest):
|
||||
from . import C5968760_ForceRegion_CheckNetForceChange as test_module
|
||||
|
||||
class C12712452_ScriptCanvas_CollisionEvents(EditorSharedTest):
|
||||
from . import C12712452_ScriptCanvas_CollisionEvents as test_module
|
||||
|
||||
class C12868578_ForceRegion_DirectionHasNoAffectOnMagnitude(EditorSharedTest):
|
||||
from . import C12868578_ForceRegion_DirectionHasNoAffectOnMagnitude as test_module
|
||||
|
||||
class C4976204_Verify_Start_Asleep_Condition(EditorSharedTest):
|
||||
from . import C4976204_Verify_Start_Asleep_Condition as test_module
|
||||
|
||||
class C6090546_ForceRegion_SliceFileInstantiates(EditorSharedTest):
|
||||
from . import C6090546_ForceRegion_SliceFileInstantiates as test_module
|
||||
|
||||
class C6090551_ForceRegion_LocalSpaceForceNegative(EditorSharedTest):
|
||||
from . import C6090551_ForceRegion_LocalSpaceForceNegative as test_module
|
||||
|
||||
class C6090553_ForceRegion_SimpleDragForceOnRigidBodies(EditorSharedTest):
|
||||
from . import C6090553_ForceRegion_SimpleDragForceOnRigidBodies as test_module
|
||||
|
||||
class C4976209_RigidBody_ComputesCOM(EditorSharedTest):
|
||||
from . import C4976209_RigidBody_ComputesCOM as test_module
|
||||
|
||||
class C4976201_RigidBody_MassIsAssigned(EditorSharedTest):
|
||||
from . import C4976201_RigidBody_MassIsAssigned as test_module
|
||||
|
||||
class C12868580_ForceRegion_SplineModifiedTransform(EditorSharedTest):
|
||||
from . import C12868580_ForceRegion_SplineModifiedTransform as test_module
|
||||
|
||||
class C12712455_ScriptCanvas_ShapeCastVerification(EditorSharedTest):
|
||||
from . import C12712455_ScriptCanvas_ShapeCastVerification as test_module
|
||||
|
||||
class C4976197_RigidBodies_InitialAngularVelocity(EditorSharedTest):
|
||||
from . import C4976197_RigidBodies_InitialAngularVelocity as test_module
|
||||
|
||||
class C6090555_ForceRegion_SplineFollowOnRigidBodies(EditorSharedTest):
|
||||
from . import C6090555_ForceRegion_SplineFollowOnRigidBodies as test_module
|
||||
|
||||
class C6131473_StaticSlice_OnDynamicSliceSpawn(EditorSharedTest):
|
||||
from . import C6131473_StaticSlice_OnDynamicSliceSpawn as test_module
|
||||
|
||||
class C5959808_ForceRegion_PositionOffset(EditorSharedTest):
|
||||
from . import C5959808_ForceRegion_PositionOffset as test_module
|
||||
|
||||
@pytest.mark.xfail(reason="Something with the CryRenderer disabling is causing this test to fail now.")
|
||||
class C13895144_Ragdoll_ChangeLevel(EditorSharedTest):
|
||||
from . import C13895144_Ragdoll_ChangeLevel as test_module
|
||||
|
||||
class C5968759_ForceRegion_ExertsSeveralForcesOnRigidBody(EditorSharedTest):
|
||||
from . import C5968759_ForceRegion_ExertsSeveralForcesOnRigidBody as test_module
|
||||
|
||||
@pytest.mark.xfail(reason="This test will sometimes fail as the ball will continue to roll before the timeout is reached.")
|
||||
class C4976202_RigidBody_StopsWhenBelowKineticThreshold(EditorSharedTest):
|
||||
from . import C4976202_RigidBody_StopsWhenBelowKineticThreshold as test_module
|
||||
|
||||
class C13351703_COM_NotIncludeTriggerShapes(EditorSharedTest):
|
||||
from . import C13351703_COM_NotIncludeTriggerShapes as test_module
|
||||
|
||||
class C5296614_PhysXMaterial_ColliderShape(EditorSharedTest):
|
||||
from . import C5296614_PhysXMaterial_ColliderShape as test_module
|
||||
|
||||
class C4982595_Collider_TriggerDisablesCollision(EditorSharedTest):
|
||||
from . import C4982595_Collider_TriggerDisablesCollision as test_module
|
||||
|
||||
class C14976307_Gravity_SetGravityWorks(EditorSharedTest):
|
||||
from . import C14976307_Gravity_SetGravityWorks as test_module
|
||||
|
||||
class C4044694_Material_EmptyLibraryUsesDefault(EditorSharedTest):
|
||||
from . import C4044694_Material_EmptyLibraryUsesDefault as test_module
|
||||
|
||||
class C15845879_ForceRegion_HighLinearDampingForce(EditorSharedTest):
|
||||
from . import C15845879_ForceRegion_HighLinearDampingForce as test_module
|
||||
|
||||
class C4976218_RigidBodies_InertiaObjectsNotComputed(EditorSharedTest):
|
||||
from . import C4976218_RigidBodies_InertiaObjectsNotComputed as test_module
|
||||
|
||||
class C14902098_ScriptCanvas_PostPhysicsUpdate(EditorSharedTest):
|
||||
from . import C14902098_ScriptCanvas_PostPhysicsUpdate as test_module
|
||||
# Note: Test needs to be updated to log for unexpected lines
|
||||
# unexpected_lines = ["Assert"] + test_module.Lines.unexpected
|
||||
|
||||
class C5959761_ForceRegion_PhysAssetExertsPointForce(EditorSharedTest):
|
||||
from . import C5959761_ForceRegion_PhysAssetExertsPointForce as test_module
|
||||
|
||||
# Marking the Test as expected to fail using the xfail decorator due to sporadic failure on Automated Review: SPEC-3146
|
||||
# The test still runs, but a failure of the test doesn't result in the test run failing
|
||||
@pytest.mark.xfail(reason="Test Sporadically fails with message [ NOT FOUND ] Success: Bar1 : Expected angular velocity")
|
||||
class C13352089_RigidBodies_MaxAngularVelocity(EditorSharedTest):
|
||||
from . import C13352089_RigidBodies_MaxAngularVelocity as test_module
|
||||
|
||||
class C18243584_Joints_HingeSoftLimitsConstrained(EditorSharedTest):
|
||||
from . import C18243584_Joints_HingeSoftLimitsConstrained as test_module
|
||||
|
||||
class C18243589_Joints_BallSoftLimitsConstrained(EditorSharedTest):
|
||||
from . import C18243589_Joints_BallSoftLimitsConstrained as test_module
|
||||
|
||||
class C18243591_Joints_BallLeadFollowerCollide(EditorSharedTest):
|
||||
from . import C18243591_Joints_BallLeadFollowerCollide as test_module
|
||||
|
||||
class C19578018_ShapeColliderWithNoShapeComponent(EditorSharedTest):
|
||||
from . import C19578018_ShapeColliderWithNoShapeComponent as test_module
|
||||
|
||||
class C14861500_DefaultSetting_ColliderShape(EditorSharedTest):
|
||||
from . import C14861500_DefaultSetting_ColliderShape as test_module
|
||||
|
||||
class C19723164_ShapeCollider_WontCrashEditor(EditorSharedTest):
|
||||
from . import C19723164_ShapeColliders_WontCrashEditor as test_module
|
||||
|
||||
class C4982800_PhysXColliderShape_CanBeSelected(EditorSharedTest):
|
||||
from . import C4982800_PhysXColliderShape_CanBeSelected as test_module
|
||||
|
||||
class C4982801_PhysXColliderShape_CanBeSelected(EditorSharedTest):
|
||||
from . import C4982801_PhysXColliderShape_CanBeSelected as test_module
|
||||
|
||||
class C4982802_PhysXColliderShape_CanBeSelected(EditorSharedTest):
|
||||
from . import C4982802_PhysXColliderShape_CanBeSelected as test_module
|
||||
|
||||
class C12905528_ForceRegion_WithNonTriggerCollider(EditorSharedTest):
|
||||
from . import C12905528_ForceRegion_WithNonTriggerCollider as test_module
|
||||
# Fixme: expected_lines = ["[Warning] (PhysX Force Region) - Please ensure collider component marked as trigger exists in entity"]
|
||||
|
||||
class C5932040_ForceRegion_CubeExertsWorldForce(EditorSharedTest):
|
||||
from . import C5932040_ForceRegion_CubeExertsWorldForce as test_module
|
||||
|
||||
class C5932044_ForceRegion_PointForceOnRigidBody(EditorSharedTest):
|
||||
from . import C5932044_ForceRegion_PointForceOnRigidBody as test_module
|
||||
|
||||
class C5959759_RigidBody_ForceRegionSpherePointForce(EditorSharedTest):
|
||||
from . import C5959759_RigidBody_ForceRegionSpherePointForce as test_module
|
||||
|
||||
class C5959809_ForceRegion_RotationalOffset(EditorSharedTest):
|
||||
from . import C5959809_ForceRegion_RotationalOffset as test_module
|
||||
|
||||
class C15096740_Material_LibraryUpdatedCorrectly(EditorSharedTest):
|
||||
from . import C15096740_Material_LibraryUpdatedCorrectly as test_module
|
||||
|
||||
class C4976236_AddPhysxColliderComponent(EditorSharedTest):
|
||||
from . import C4976236_AddPhysxColliderComponent as test_module
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="This will fail due to this issue ATOM-15487.")
|
||||
class C14861502_PhysXCollider_AssetAutoAssigned(EditorSharedTest):
|
||||
from . import C14861502_PhysXCollider_AssetAutoAssigned as test_module
|
||||
|
||||
class C14861501_PhysXCollider_RenderMeshAutoAssigned(EditorSharedTest):
|
||||
from . import C14861501_PhysXCollider_RenderMeshAutoAssigned as test_module
|
||||
|
||||
class C4044695_PhysXCollider_AddMultipleSurfaceFbx(EditorSharedTest):
|
||||
from . import C4044695_PhysXCollider_AddMultipleSurfaceFbx as test_module
|
||||
|
||||
class C14861504_RenderMeshAsset_WithNoPxAsset(EditorSharedTest):
|
||||
from . import C14861504_RenderMeshAsset_WithNoPxAsset as test_module
|
||||
|
||||
class C100000_RigidBody_EnablingGravityWorksPoC(EditorSharedTest):
|
||||
from . import C100000_RigidBody_EnablingGravityWorksPoC as test_module
|
||||
|
||||
class C4982798_Collider_ColliderRotationOffset(EditorSharedTest):
|
||||
from . import C4982798_Collider_ColliderRotationOffset as test_module
|
||||
|
||||
class C15308217_NoCrash_LevelSwitch(EditorSharedTest):
|
||||
from . import C15308217_NoCrash_LevelSwitch as test_module
|
||||
|
||||
class C6090547_ForceRegion_ParentChildForceRegions(EditorSharedTest):
|
||||
from . import C6090547_ForceRegion_ParentChildForceRegions as test_module
|
||||
|
||||
class C19578021_ShapeCollider_CanBeAdded(EditorSharedTest):
|
||||
from . import C19578021_ShapeCollider_CanBeAdded as test_module
|
||||
|
||||
class C15425929_Undo_Redo(EditorSharedTest):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
@ -1,105 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
|
||||
from ly_test_tools import LAUNCHERS
|
||||
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
|
||||
from .FileManagement import FileManagement as fm
|
||||
|
||||
# Custom test spec, it provides functionality to override files
|
||||
class EditorSingleTest_WithFileOverrides(EditorSingleTest):
|
||||
# Specify here what files to override, [(original, override), ...]
|
||||
files_to_override = [()]
|
||||
# Base directory of the files (Default path is {ProjectName})
|
||||
base_dir = None
|
||||
# True will will search sub-directories for the files in base
|
||||
search_subdirs = False
|
||||
|
||||
@classmethod
|
||||
def wrap_run(cls, instance, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
root_path = cls.base_dir
|
||||
if root_path is not None:
|
||||
root_path = os.path.join(workspace.paths.engine_root(), root_path)
|
||||
else:
|
||||
# Default to project folder
|
||||
root_path = workspace.paths.project()
|
||||
|
||||
# Try to locate both target and source files
|
||||
original_file_list, override_file_list = zip(*cls.files_to_override)
|
||||
try:
|
||||
file_list = fm._find_files(original_file_list + override_file_list, root_path, cls.search_subdirs)
|
||||
except RuntimeWarning as w:
|
||||
assert False, (
|
||||
w.message
|
||||
+ " Please check use of search_subdirs; make sure you are using the correct parent directory."
|
||||
)
|
||||
|
||||
for f in original_file_list:
|
||||
fm._restore_file(f, file_list[f])
|
||||
fm._backup_file(f, file_list[f])
|
||||
|
||||
for original, override in cls.files_to_override:
|
||||
fm._copy_file(override, file_list[override], original, file_list[override])
|
||||
|
||||
yield # Run Test
|
||||
for f in original_file_list:
|
||||
fm._restore_file(f, file_list[f])
|
||||
|
||||
|
||||
@pytest.mark.SUITE_main
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
class C4044459_Material_DynamicFriction(EditorSingleTest_WithFileOverrides):
|
||||
from . import C4044459_Material_DynamicFriction as test_module
|
||||
files_to_override = [
|
||||
('physxsystemconfiguration.setreg', 'C4044459_Material_DynamicFriction.setreg_override')
|
||||
]
|
||||
base_dir = "AutomatedTesting/Registry"
|
||||
|
||||
class C4982593_PhysXCollider_CollisionLayerTest(EditorSingleTest_WithFileOverrides):
|
||||
from . import C4982593_PhysXCollider_CollisionLayerTest as test_module
|
||||
files_to_override = [
|
||||
('physxsystemconfiguration.setreg', 'C4982593_PhysXCollider_CollisionLayer.setreg_override')
|
||||
]
|
||||
base_dir = "AutomatedTesting/Registry"
|
||||
|
||||
class C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC(EditorSharedTest):
|
||||
from . import C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC as test_module
|
||||
|
||||
class C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies(EditorSharedTest):
|
||||
from . import C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies as test_module
|
||||
|
||||
class C15425929_Undo_Redo(EditorSharedTest):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
|
||||
class C4976243_Collision_SameCollisionGroupDiffCollisionLayers(EditorSharedTest):
|
||||
from . import C4976243_Collision_SameCollisionGroupDiffCollisionLayers as test_module
|
||||
|
||||
class C14654881_CharacterController_SwitchLevels(EditorSharedTest):
|
||||
from . import C14654881_CharacterController_SwitchLevels as test_module
|
||||
|
||||
class C17411467_AddPhysxRagdollComponent(EditorSharedTest):
|
||||
from . import C17411467_AddPhysxRagdollComponent as test_module
|
||||
|
||||
class C12712453_ScriptCanvas_MultipleRaycastNode(EditorSharedTest):
|
||||
from . import C12712453_ScriptCanvas_MultipleRaycastNode as test_module
|
||||
|
||||
class C18243586_Joints_HingeLeadFollowerCollide(EditorSharedTest):
|
||||
from . import C18243586_Joints_HingeLeadFollowerCollide as test_module
|
||||
|
||||
class C4982803_Enable_PxMesh_Option(EditorSharedTest):
|
||||
from . import C4982803_Enable_PxMesh_Option as test_module
|
||||
|
||||
class C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain(EditorSharedTest):
|
||||
from . import C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain as test_module
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Budget.h"
|
||||
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(Animation);
|
||||
AZ_DEFINE_BUDGET(Audio);
|
||||
AZ_DEFINE_BUDGET(AzCore);
|
||||
AZ_DEFINE_BUDGET(Editor);
|
||||
AZ_DEFINE_BUDGET(Entity);
|
||||
AZ_DEFINE_BUDGET(Game);
|
||||
AZ_DEFINE_BUDGET(System);
|
||||
AZ_DEFINE_BUDGET(Physics);
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
struct BudgetImpl
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(BudgetImpl, AZ::SystemAllocator, 0);
|
||||
// TODO: Budget implementation for tracking budget wall time per-core, memory, etc.
|
||||
};
|
||||
|
||||
Budget::Budget(const char* name)
|
||||
: m_name{ name }
|
||||
, m_crc{ Crc32(name) }
|
||||
{
|
||||
}
|
||||
|
||||
Budget::Budget(const char* name, uint32_t crc)
|
||||
: m_name{ name }
|
||||
, m_crc{ crc }
|
||||
{
|
||||
m_impl = aznew BudgetImpl;
|
||||
}
|
||||
|
||||
Budget::~Budget()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:Budgets Methods below are stubbed pending future work to both update budget data and visualize it
|
||||
|
||||
void Budget::PerFrameReset()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::BeginProfileRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::EndProfileRegion()
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::TrackAllocation(uint64_t)
|
||||
{
|
||||
}
|
||||
|
||||
void Budget::UntrackAllocation(uint64_t)
|
||||
{
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
// A budget collates per-frame resource utilization and memory for a particular category
|
||||
class Budget final
|
||||
{
|
||||
public:
|
||||
explicit Budget(const char* name);
|
||||
Budget(const char* name, uint32_t crc);
|
||||
~Budget();
|
||||
|
||||
void PerFrameReset();
|
||||
void BeginProfileRegion();
|
||||
void EndProfileRegion();
|
||||
void TrackAllocation(uint64_t bytes);
|
||||
void UntrackAllocation(uint64_t bytes);
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
uint32_t Crc() const
|
||||
{
|
||||
return m_crc;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* m_name;
|
||||
const uint32_t m_crc;
|
||||
struct BudgetImpl* m_impl = nullptr;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
|
||||
// The budget is usable in the same file it was defined without needing an additional declaration.
|
||||
// If you encounter a linker error complaining that this function is not defined, you have likely forgotten to either
|
||||
// define or declare the budget used in a profile or memory marker. See AZ_DEFINE_BUDGET and AZ_DECLARE_BUDGET below
|
||||
// for usage.
|
||||
#define AZ_BUDGET_GETTER(name) GetAzBudget##name
|
||||
|
||||
#if defined(_RELEASE)
|
||||
#define AZ_DEFINE_BUDGET(name) \
|
||||
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
|
||||
{ \
|
||||
return nullptr; \
|
||||
}
|
||||
#else
|
||||
// Usage example:
|
||||
// In a single C++ source file:
|
||||
// AZ_DEFINE_BUDGET(AzCore);
|
||||
//
|
||||
// Anywhere the budget is used, the budget must be declared (either in a header or in the source file itself)
|
||||
// AZ_DECLARE_BUDGET(AzCore);
|
||||
#define AZ_DEFINE_BUDGET(name) \
|
||||
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
|
||||
{ \
|
||||
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
|
||||
static ::AZ::Debug::Budget* budget = ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name, crc); \
|
||||
return budget; \
|
||||
}
|
||||
#endif
|
||||
|
||||
// If using a budget defined in a different C++ source file, add AZ_DECLARE_BUDGET(yourBudget); somewhere in your source file at namespace
|
||||
// scope Alternatively, AZ_DECLARE_BUDGET can be used in a header to declare the budget for use across any users of the header
|
||||
#define AZ_DECLARE_BUDGET(name) ::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)()
|
||||
|
||||
// Declare budgets that are core engine budgets, or may be shared/needed across multiple external gems
|
||||
// You should NOT need to declare user-space or budgets with isolated usage here. Prefer declaring them local to the module(s) that use
|
||||
// the budget and defining them within a single module to avoid needing to recompile the entire engine.
|
||||
AZ_DECLARE_BUDGET(Animation);
|
||||
AZ_DECLARE_BUDGET(Audio);
|
||||
AZ_DECLARE_BUDGET(AzCore);
|
||||
AZ_DECLARE_BUDGET(Editor);
|
||||
AZ_DECLARE_BUDGET(Entity);
|
||||
AZ_DECLARE_BUDGET(Game);
|
||||
AZ_DECLARE_BUDGET(System);
|
||||
AZ_DECLARE_BUDGET(Physics);
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/BudgetTracker.h>
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Budget.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/parallel/scoped_lock.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
constexpr static const char* BudgetTrackerEnvName = "budgetTrackerEnv";
|
||||
|
||||
struct BudgetTracker::BudgetTrackerImpl
|
||||
{
|
||||
AZStd::unordered_map<const char*, Budget> m_budgets;
|
||||
};
|
||||
|
||||
Budget* BudgetTracker::GetBudgetFromEnvironment(const char* budgetName, uint32_t crc)
|
||||
{
|
||||
BudgetTracker* tracker = Interface<BudgetTracker>::Get();
|
||||
if (tracker)
|
||||
{
|
||||
return &tracker->GetBudget(budgetName, crc);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BudgetTracker::~BudgetTracker()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool BudgetTracker::Init()
|
||||
{
|
||||
if (Interface<BudgetTracker>::Get())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Interface<BudgetTracker>::Register(this);
|
||||
m_impl = new BudgetTrackerImpl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BudgetTracker::Reset()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
Interface<BudgetTracker>::Unregister(this);
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Budget& BudgetTracker::GetBudget(const char* budgetName, uint32_t crc)
|
||||
{
|
||||
AZStd::scoped_lock lock{ m_mutex };
|
||||
|
||||
auto it = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
} // namespace AZ::Debug
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Module/Environment.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class Budget;
|
||||
|
||||
class BudgetTracker
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
|
||||
static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc);
|
||||
|
||||
~BudgetTracker();
|
||||
|
||||
// Returns false if the budget tracker was already present in the environment (initialized already elsewhere)
|
||||
bool Init();
|
||||
void Reset();
|
||||
|
||||
Budget& GetBudget(const char* budgetName, uint32_t crc);
|
||||
|
||||
private:
|
||||
struct BudgetTrackerImpl;
|
||||
|
||||
AZStd::mutex m_mutex;
|
||||
|
||||
// The BudgetTracker is likely included in proportionally high number of files throughout the
|
||||
// engine, so indirection is used here to avoid imposing excessive recompilation in periods
|
||||
// while the budget system is iterated on.
|
||||
BudgetTrackerImpl* m_impl = nullptr;
|
||||
};
|
||||
} // namespace AZ::Debug
|
||||
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_FRAME_PROFILER_H
|
||||
#define AZCORE_FRAME_PROFILER_H
|
||||
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
#include <AzCore/std/containers/ring_buffer.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/std/parallel/config.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
namespace FrameProfiler
|
||||
{
|
||||
/**
|
||||
* This structure is used for frame data history, make sure it's memory efficient.
|
||||
*/
|
||||
struct FrameData
|
||||
{
|
||||
unsigned int m_frameId; ///< Id of the frame this data belongs to.
|
||||
union
|
||||
{
|
||||
ProfilerRegister::TimeData m_timeData;
|
||||
ProfilerRegister::ValuesData m_userValues;
|
||||
};
|
||||
};
|
||||
|
||||
struct RegisterData
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Profile register snapshot
|
||||
/// data that doesn't change
|
||||
const char* m_name; ///< Name of the profiler register.
|
||||
const char* m_function; ///< Function name in the code.
|
||||
int m_line; ///< Line number if the code.
|
||||
AZ::u32 m_systemId; ///< Register system id.
|
||||
ProfilerRegister::Type m_type;
|
||||
RegisterData* m_lastParent; ///< Pointer to the last parent register data.
|
||||
AZStd::ring_buffer<FrameData> m_frames; ///< History of all frame deltas (basically the data you want to display)
|
||||
};
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
typedef AZStd::unordered_map<const ProfilerRegister*, RegisterData> RegistersMap;
|
||||
AZStd::thread_id m_id; ///< Thread id (same as AZStd::thread::id)
|
||||
RegistersMap m_registers; ///< Map with all the registers (with history)
|
||||
};
|
||||
|
||||
typedef AZStd::fixed_vector<ThreadData, Profiler::m_maxNumberOfThreads> ThreadDataArray; ///< Array with samplers for all threads
|
||||
} // namespace FrameProfiler
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_FRAME_PROFILER_H
|
||||
#pragma once
|
||||
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_FRAME_PROFILER_BUS_H
|
||||
#define AZCORE_FRAME_PROFILER_BUS_H
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Debug/FrameProfiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class FrameProfilerComponent;
|
||||
|
||||
/**
|
||||
* Interface class for frame profiler events.
|
||||
*/
|
||||
class FrameProfilerEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~FrameProfilerEvents() {}
|
||||
|
||||
/// Called when the frame profiler has computed a new frame (even is there is no new data).
|
||||
virtual void OnFrameProfilerData(const FrameProfiler::ThreadDataArray& data) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<FrameProfilerEvents> FrameProfilerBus;
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_FRAME_PROFILER_BUS_H
|
||||
#pragma once
|
||||
@ -1,250 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/FrameProfilerComponent.h>
|
||||
#include <AzCore/Debug/FrameProfilerBus.h>
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
//=========================================================================
|
||||
// FrameProfilerComponent
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
FrameProfilerComponent::FrameProfilerComponent()
|
||||
: m_numFramesStored(2)
|
||||
, m_frameId(0)
|
||||
, m_pauseOnFrame(0)
|
||||
, m_currentThreadData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~FrameProfilerComponent
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
FrameProfilerComponent::~FrameProfilerComponent()
|
||||
{
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Activate
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::Activate()
|
||||
{
|
||||
if (!Profiler::IsReady())
|
||||
{
|
||||
Profiler::Create();
|
||||
}
|
||||
|
||||
Profiler::AddReference();
|
||||
|
||||
TickBus::Handler::BusConnect();
|
||||
AZ_Assert(m_numFramesStored >= 1, "We must have at least one frame to store, otherwise this component is useless!");
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Deactivate
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::Deactivate()
|
||||
{
|
||||
TickBus::Handler::BusDisconnect();
|
||||
|
||||
Profiler::ReleaseReference();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnTick
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::OnTick(float deltaTime, ScriptTimePoint time)
|
||||
{
|
||||
(void)deltaTime;
|
||||
(void)time;
|
||||
++m_frameId;
|
||||
AZ_Error("Profiler", m_frameId != m_pauseOnFrame, "Triggered user pause/error on this frame! Check FrameProfilerComponent pauseOnFrame value!");
|
||||
|
||||
if (!Profiler::IsReady())
|
||||
{
|
||||
return; // we can't sample registers without profiler
|
||||
}
|
||||
// collect data from the profiler
|
||||
m_currentThreadData = NULL;
|
||||
Profiler::Instance().ReadRegisterValues(AZStd::bind(&FrameProfilerComponent::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2));
|
||||
|
||||
// process all the resulting data here, not while reading the registers
|
||||
for (size_t iThread = 0; iThread < m_threads.size(); ++iThread)
|
||||
{
|
||||
FrameProfiler::ThreadData& td = m_threads[iThread];
|
||||
FrameProfiler::ThreadData::RegistersMap::iterator it = td.m_registers.begin();
|
||||
FrameProfiler::ThreadData::RegistersMap::iterator last = td.m_registers.end();
|
||||
for (; it != last; ++it)
|
||||
{
|
||||
// fix up parents
|
||||
FrameProfiler::RegisterData& rd = it->second;
|
||||
if (rd.m_type == ProfilerRegister::PRT_TIME)
|
||||
{
|
||||
const FrameProfiler::FrameData& fd = rd.m_frames.back();
|
||||
if (fd.m_timeData.m_lastParent != nullptr)
|
||||
{
|
||||
FrameProfiler::ThreadData::RegistersMap::iterator parentIt = td.m_registers.find(fd.m_timeData.m_lastParent);
|
||||
AZ_Assert(parentIt != td.m_registers.end(), "We have a parent register that is not in our register map. This should not happen!");
|
||||
rd.m_lastParent = &parentIt->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
rd.m_lastParent = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send an even to whomever cares
|
||||
EBUS_EVENT(FrameProfilerBus, OnFrameProfilerData, m_threads);
|
||||
}
|
||||
|
||||
int FrameProfilerComponent::GetTickOrder()
|
||||
{
|
||||
// Even it's not critical we should tick last to capture the current frame
|
||||
// so TICK_LAST (since it's not the last int +1 is a valid assumption)
|
||||
return TICK_LAST + 1;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReadRegisterCallback
|
||||
// [12/5/2012]
|
||||
//=========================================================================
|
||||
bool FrameProfilerComponent::ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id)
|
||||
{
|
||||
if (m_currentThreadData == NULL || m_currentThreadData->m_id != id)
|
||||
{
|
||||
m_currentThreadData = NULL;
|
||||
|
||||
// find the thread and cache it, as we will received registers thread by thread... so we don't search.
|
||||
for (size_t i = 0; i < m_threads.size(); ++i)
|
||||
{
|
||||
FrameProfiler::ThreadData* td = &m_threads[i];
|
||||
if (td->m_id == id)
|
||||
{
|
||||
m_currentThreadData = td;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_currentThreadData == NULL)
|
||||
{
|
||||
m_threads.push_back();
|
||||
m_currentThreadData = &m_threads.back();
|
||||
m_currentThreadData->m_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
const ProfilerRegister* profReg = ®
|
||||
FrameProfiler::ThreadData::RegistersMap::pair_iter_bool pairIterBool = m_currentThreadData->m_registers.insert_key(profReg);
|
||||
FrameProfiler::RegisterData& regData = pairIterBool.first->second;
|
||||
|
||||
// now update dynamic data with as little as possible computation (we must be fast)
|
||||
FrameProfiler::FrameData fd; // we can actually move this computation (FrameData and push) for later but we will need to use more memory
|
||||
fd.m_frameId = m_frameId;
|
||||
|
||||
if (pairIterBool.second)
|
||||
{
|
||||
// when insert copy the static data only once
|
||||
regData.m_name = profReg->m_name;
|
||||
regData.m_function = profReg->m_function;
|
||||
regData.m_line = profReg->m_line;
|
||||
regData.m_systemId = profReg->m_systemId;
|
||||
regData.m_frames.set_capacity(m_numFramesStored);
|
||||
regData.m_type = static_cast<ProfilerRegister::Type>(profReg->m_type);
|
||||
}
|
||||
|
||||
switch (regData.m_type)
|
||||
{
|
||||
case ProfilerRegister::PRT_TIME:
|
||||
{
|
||||
fd.m_timeData.m_time = profReg->m_timeData.m_time;
|
||||
fd.m_timeData.m_childrenTime = profReg->m_timeData.m_childrenTime;
|
||||
fd.m_timeData.m_calls = profReg->m_timeData.m_calls;
|
||||
fd.m_timeData.m_childrenCalls = profReg->m_timeData.m_childrenCalls;
|
||||
fd.m_timeData.m_lastParent = profReg->m_timeData.m_lastParent;
|
||||
} break;
|
||||
case ProfilerRegister::PRT_VALUE:
|
||||
{
|
||||
fd.m_userValues.m_value1 = profReg->m_userValues.m_value1;
|
||||
fd.m_userValues.m_value2 = profReg->m_userValues.m_value2;
|
||||
fd.m_userValues.m_value3 = profReg->m_userValues.m_value3;
|
||||
fd.m_userValues.m_value4 = profReg->m_userValues.m_value4;
|
||||
fd.m_userValues.m_value5 = profReg->m_userValues.m_value5;
|
||||
} break;
|
||||
}
|
||||
|
||||
regData.m_frames.push_back(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetProvidedServices
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("FrameProfilerService", 0x05d1bb90));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetIncompatibleServices
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("FrameProfilerService", 0x05d1bb90));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// GetDependentServices
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
dependent.push_back(AZ_CRC("MemoryService", 0x5c4d473c));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Reflect
|
||||
//=========================================================================
|
||||
void FrameProfilerComponent::Reflect(ReflectContext* context)
|
||||
{
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<FrameProfilerComponent, AZ::Component>()
|
||||
->Version(1)
|
||||
->Field("numFramesStored", &FrameProfilerComponent::m_numFramesStored)
|
||||
->Field("pauseOnFrame", &FrameProfilerComponent::m_pauseOnFrame)
|
||||
;
|
||||
|
||||
if (EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<FrameProfilerComponent>(
|
||||
"Frame Profiler", "Performs per frame profiling (FPS counter, registers, etc.)")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
->DataElement(AZ::Edit::UIHandlers::SpinBox, &FrameProfilerComponent::m_numFramesStored, "Number of Frames", "How many frames we will keep with the RUNTIME buffers.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 1)
|
||||
->DataElement(AZ::Edit::UIHandlers::SpinBox, &FrameProfilerComponent::m_pauseOnFrame, "Pause on frame", "Paused the engine (debug break) on a specific frame. 0 means no pause!")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_FRAME_PROFILER_COMPONENT_H
|
||||
#define AZCORE_FRAME_PROFILER_COMPONENT_H
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Debug/FrameProfiler.h>
|
||||
#include <AzCore/std/parallel/threadbus.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
/**
|
||||
* Frame profiler component provides a frame profiling information
|
||||
* (from FPS counter to profiler registers manipulation and so on).
|
||||
* It's a debug system so it should not be active in release
|
||||
*/
|
||||
class FrameProfilerComponent
|
||||
: public Component
|
||||
, public AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AZ::Debug::FrameProfilerComponent, "{B81739EF-ED77-4F67-9D05-6ADF94F0431A}")
|
||||
|
||||
FrameProfilerComponent();
|
||||
virtual ~FrameProfilerComponent();
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Component base
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Tick bus
|
||||
void OnTick(float deltaTime, ScriptTimePoint time) override;
|
||||
int GetTickOrder() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// \ref ComponentDescriptor::GetProvidedServices
|
||||
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
|
||||
/// \ref ComponentDescriptor::GetIncompatibleServices
|
||||
static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
/// \ref ComponentDescriptor::GetDependentServices
|
||||
static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent);
|
||||
/// \red ComponentDescriptor::Reflect
|
||||
static void Reflect(ReflectContext* reflection);
|
||||
|
||||
/// callback for reading profiler registers
|
||||
bool ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id);
|
||||
|
||||
// Keep in mind memory usage, increases quickly. Prefer remote tools (where the history is kept on the PC) instead of keeping long history
|
||||
unsigned int m_numFramesStored; ///< Number of frames that we will store in history buffers. >= 1
|
||||
unsigned int m_frameId; ///< Frame id (it's just counted from the start).
|
||||
|
||||
unsigned int m_pauseOnFrame; ///< Allows you to specify a frame the code will pause onto.
|
||||
|
||||
|
||||
FrameProfiler::ThreadDataArray m_threads; ///< Array with samplers for all threads
|
||||
FrameProfiler::ThreadData* m_currentThreadData; ///< Cached pointer to the last accessed thread data.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AZCORE_FRAME_PROFILER_COMPONENT_H
|
||||
#pragma once
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
template<typename... T>
|
||||
void ProfileScope::BeginRegion(
|
||||
[[maybe_unused]] Budget* budget, [[maybe_unused]] const char* eventName, [[maybe_unused]] T const&... args)
|
||||
{
|
||||
if (!budget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !defined(_RELEASE)
|
||||
// TODO: Verification that the supplied system name corresponds to a known budget
|
||||
#if defined(USE_PIX)
|
||||
PIXBeginEvent(PIX_COLOR_INDEX(budget->Crc() & 0xff), eventName, args...);
|
||||
#endif
|
||||
budget->BeginProfileRegion();
|
||||
// TODO: injecting instrumentation for other profilers
|
||||
// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
|
||||
// will be introduced in a future PR
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ProfileScope::EndRegion([[maybe_unused]] Budget* budget)
|
||||
{
|
||||
if (!budget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !defined(_RELEASE)
|
||||
budget->EndProfileRegion();
|
||||
#if defined(USE_PIX)
|
||||
PIXEndEvent();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
ProfileScope::ProfileScope(Budget* budget, char const* eventName, T const&... args)
|
||||
: m_budget{ budget }
|
||||
{
|
||||
BeginRegion(budget, eventName, args...);
|
||||
}
|
||||
|
||||
inline ProfileScope::~ProfileScope()
|
||||
{
|
||||
EndRegion(m_budget);
|
||||
}
|
||||
|
||||
} // namespace AZ::Debug
|
||||
@ -1,310 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Debug/ProfilerDriller.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/bind/bind.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
//=========================================================================
|
||||
// ProfilerDriller
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
ProfilerDriller::ProfilerDriller()
|
||||
{
|
||||
AZStd::ThreadDrillerEventBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ~ProfilerDriller
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
ProfilerDriller::~ProfilerDriller()
|
||||
{
|
||||
AZStd::ThreadDrillerEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Start
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::Start(const Param* params, int numParams)
|
||||
{
|
||||
for (int i = 0; i < m_numberOfSystemFilters; ++i)
|
||||
{
|
||||
m_systemFilters[i].desc = "SystemID of the system which counters we are interested in";
|
||||
m_systemFilters[i].type = Param::PT_INT;
|
||||
m_systemFilters[i].value = 0;
|
||||
}
|
||||
|
||||
// Copy valid filters.
|
||||
m_numberOfValidFilters = 0;
|
||||
if (params)
|
||||
{
|
||||
for (int i = 0; i < numParams; ++i)
|
||||
{
|
||||
if (params[i].type == Param::PT_INT && params[i].value != 0)
|
||||
{
|
||||
m_systemFilters[m_numberOfValidFilters++].value = params[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// output current threads
|
||||
for (ThreadArrayType::iterator it = m_threads.begin(); it != m_threads.end(); ++it)
|
||||
{
|
||||
OutputThreadEnter(*it);
|
||||
}
|
||||
|
||||
ProfilerDrillerBus::Handler::BusConnect();
|
||||
|
||||
if (!Profiler::IsReady())
|
||||
{
|
||||
Profiler::Create();
|
||||
}
|
||||
|
||||
Profiler::AddReference();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Stop
|
||||
// [5/24/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::Stop()
|
||||
{
|
||||
Profiler::ReleaseReference();
|
||||
ProfilerDrillerBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnError
|
||||
// [2/8/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::Update()
|
||||
{
|
||||
// \note We could add thread_id in addition to the System ID, but I can't foresee many cases where we would like to profile only a specific thread.
|
||||
if (m_numberOfValidFilters)
|
||||
{
|
||||
for (int iFilter = 0; iFilter < m_numberOfValidFilters; ++iFilter)
|
||||
{
|
||||
AZ::u32 systemFilter = *reinterpret_cast<AZ::u32*>(&m_systemFilters[iFilter].value);
|
||||
Profiler::Instance().ReadRegisterValues(AZStd::bind(&ProfilerDriller::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2), systemFilter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Profiler::Instance().ReadRegisterValues(AZStd::bind(&ProfilerDriller::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2), 0);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ReadProfilerRegisters
|
||||
// [2/11/2013]
|
||||
//=========================================================================
|
||||
bool ProfilerDriller::ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id)
|
||||
{
|
||||
(void)id;
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("UpdateRegister", 0x6c00b890));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), ®);
|
||||
// Send only the data which is changing
|
||||
switch (reg.m_type)
|
||||
{
|
||||
case ProfilerRegister::PRT_TIME:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Time", 0x6f949845), reg.m_timeData.m_time);
|
||||
m_output->Write(AZ_CRC("ChildrenTime", 0x46162d3f), reg.m_timeData.m_childrenTime);
|
||||
m_output->Write(AZ_CRC("Calls", 0xdaa35c8f), reg.m_timeData.m_calls);
|
||||
m_output->Write(AZ_CRC("ChildrenCalls", 0x6a5a4618), reg.m_timeData.m_childrenCalls);
|
||||
m_output->Write(AZ_CRC("ParentId", 0x856a684c), reg.m_timeData.m_lastParent);
|
||||
} break;
|
||||
case ProfilerRegister::PRT_VALUE:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Value1", 0xa2756c5a), reg.m_userValues.m_value1);
|
||||
m_output->Write(AZ_CRC("Value2", 0x3b7c3de0), reg.m_userValues.m_value2);
|
||||
m_output->Write(AZ_CRC("Value3", 0x4c7b0d76), reg.m_userValues.m_value3);
|
||||
m_output->Write(AZ_CRC("Value4", 0xd21f98d5), reg.m_userValues.m_value4);
|
||||
m_output->Write(AZ_CRC("Value5", 0xa518a843), reg.m_userValues.m_value5);
|
||||
} break;
|
||||
}
|
||||
m_output->EndTag(AZ_CRC("UpdateRegister", 0x6c00b890));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnThreadEnter
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnThreadEnter(const AZStd::thread_id& id, const AZStd::thread_desc* desc)
|
||||
{
|
||||
m_threads.push_back();
|
||||
ThreadInfo& info = m_threads.back();
|
||||
info.m_id = (size_t)id.m_id;
|
||||
if (desc)
|
||||
{
|
||||
info.m_name = desc->m_name;
|
||||
info.m_cpuId = desc->m_cpuId;
|
||||
info.m_priority = desc->m_priority;
|
||||
info.m_stackSize = desc->m_stackSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.m_name = nullptr;
|
||||
info.m_cpuId = -1;
|
||||
info.m_priority = -100000;
|
||||
info.m_stackSize = 0;
|
||||
}
|
||||
|
||||
if (m_output)
|
||||
{
|
||||
OutputThreadEnter(info);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnThreadExit
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnThreadExit(const AZStd::thread_id& id)
|
||||
{
|
||||
ThreadArrayType::iterator it = m_threads.begin();
|
||||
while (it != m_threads.end())
|
||||
{
|
||||
if (it->m_id == (size_t)id.m_id)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != m_threads.end())
|
||||
{
|
||||
if (m_output)
|
||||
{
|
||||
OutputThreadExit(*it);
|
||||
}
|
||||
|
||||
m_threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OutputThreadEnter
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OutputThreadEnter(const ThreadInfo& threadInfo)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("ThreadEnter", 0x60e4acfb));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), threadInfo.m_id);
|
||||
if (threadInfo.m_name)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), threadInfo.m_name);
|
||||
}
|
||||
m_output->Write(AZ_CRC("CpuId", 0xdf558508), threadInfo.m_cpuId);
|
||||
m_output->Write(AZ_CRC("Priority", 0x62a6dc27), threadInfo.m_priority);
|
||||
m_output->Write(AZ_CRC("StackSize", 0x9cfaf35b), threadInfo.m_stackSize);
|
||||
m_output->EndTag(AZ_CRC("ThreadEnter", 0x60e4acfb));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OutputThreadExit
|
||||
// [7/9/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OutputThreadExit(const ThreadInfo& threadInfo)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("OnThreadExit", 0x16042db9));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), threadInfo.m_id);
|
||||
m_output->EndTag(AZ_CRC("OnThreadExit", 0x16042db9));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnRegisterSystem
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnRegisterSystem(AZ::u32 id, const char* name)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("RegisterSystem", 0x957739ef));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), id);
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), name);
|
||||
m_output->EndTag(AZ_CRC("RegisterSystem", 0x957739ef));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnUnregisterSystem
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnUnregisterSystem(AZ::u32 id)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("UnregisterSystem", 0xa20538e4));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), id);
|
||||
m_output->EndTag(AZ_CRC("UnregisterSystem", 0xa20538e4));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// OnNewRegister
|
||||
// [5/31/2013]
|
||||
//=========================================================================
|
||||
void ProfilerDriller::OnNewRegister(const ProfilerRegister& reg, const AZStd::thread_id& threadId)
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
m_output->BeginTag(AZ_CRC("NewRegister", 0xf0f2f287));
|
||||
m_output->Write(AZ_CRC("Id", 0xbf396750), ®);
|
||||
m_output->Write(AZ_CRC("ThreadId", 0xd0fd9043), threadId.m_id);
|
||||
if (reg.m_name)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Name", 0x5e237e06), reg.m_name);
|
||||
}
|
||||
if (reg.m_function)
|
||||
{
|
||||
m_output->Write(AZ_CRC("Function", 0xcaae163d), reg.m_function);
|
||||
}
|
||||
m_output->Write(AZ_CRC("Line", 0xd114b4f6), reg.m_line);
|
||||
m_output->Write(AZ_CRC("SystemId", 0x0dfecf6f), reg.m_systemId);
|
||||
m_output->Write(AZ_CRC("Type", 0x8cde5729), reg.m_type);
|
||||
|
||||
switch (reg.m_type)
|
||||
{
|
||||
case ProfilerRegister::PRT_TIME:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Time", 0x6f949845), reg.m_timeData.m_time);
|
||||
m_output->Write(AZ_CRC("ChildrenTime", 0x46162d3f), reg.m_timeData.m_childrenTime);
|
||||
m_output->Write(AZ_CRC("Calls", 0xdaa35c8f), reg.m_timeData.m_calls);
|
||||
m_output->Write(AZ_CRC("ChildrenCalls", 0x6a5a4618), reg.m_timeData.m_childrenCalls);
|
||||
m_output->Write(AZ_CRC("ParentId", 0x856a684c), reg.m_timeData.m_lastParent);
|
||||
} break;
|
||||
case ProfilerRegister::PRT_VALUE:
|
||||
{
|
||||
m_output->Write(AZ_CRC("Value1", 0xa2756c5a), reg.m_userValues.m_value1);
|
||||
m_output->Write(AZ_CRC("Value2", 0x3b7c3de0), reg.m_userValues.m_value2);
|
||||
m_output->Write(AZ_CRC("Value3", 0x4c7b0d76), reg.m_userValues.m_value3);
|
||||
m_output->Write(AZ_CRC("Value4", 0xd21f98d5), reg.m_userValues.m_value4);
|
||||
m_output->Write(AZ_CRC("Value5", 0xa518a843), reg.m_userValues.m_value5);
|
||||
} break;
|
||||
}
|
||||
m_output->EndTag(AZ_CRC("NewRegister", 0xf0f2f287));
|
||||
m_output->EndTag(AZ_CRC("ProfilerDriller", 0x172c5268));
|
||||
}
|
||||
} // namespace Debug
|
||||
} // namespace AZ
|
||||
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_PROFILER_DRILLER_H
|
||||
#define AZCORE_PROFILER_DRILLER_H 1
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Debug/ProfilerDrillerBus.h>
|
||||
#include <AzCore/std/parallel/threadbus.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
struct thread_id;
|
||||
struct thread_desc;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
struct ProfilerSystemData;
|
||||
class ProfilerRegister;
|
||||
|
||||
/**
|
||||
* ProfilerDriller or we can just make a Profiler driller and read the registers ourself.
|
||||
*/
|
||||
class ProfilerDriller
|
||||
: public Driller
|
||||
, public ProfilerDrillerBus::Handler
|
||||
, public AZStd::ThreadDrillerEventBus::Handler
|
||||
{
|
||||
struct ThreadInfo
|
||||
{
|
||||
AZ::u64 m_id;
|
||||
AZ::u32 m_stackSize;
|
||||
AZ::s32 m_priority;
|
||||
AZ::s32 m_cpuId;
|
||||
const char* m_name;
|
||||
};
|
||||
typedef vector<ThreadInfo>::type ThreadArrayType;
|
||||
|
||||
public:
|
||||
|
||||
AZ_CLASS_ALLOCATOR(ProfilerDriller, OSAllocator, 0)
|
||||
|
||||
ProfilerDriller();
|
||||
virtual ~ProfilerDriller();
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Driller
|
||||
virtual const char* GroupName() const { return "SystemDrillers"; }
|
||||
virtual const char* GetName() const { return "ProfilerDriller"; }
|
||||
virtual const char* GetDescription() const { return "Collects data from all available profile registers."; }
|
||||
virtual int GetNumParams() const { return m_numberOfSystemFilters; }
|
||||
virtual const Param* GetParam(int index) const { AZ_Assert(index >= 0 && index < m_numberOfSystemFilters, "Invalid index"); return &m_systemFilters[index]; }
|
||||
virtual void Start(const Param* params = NULL, int numParams = 0);
|
||||
virtual void Stop();
|
||||
virtual void Update();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Thread driller event bus
|
||||
/// Called when we enter a thread, optional thread_desc is provided when the use provides one.
|
||||
virtual void OnThreadEnter(const AZStd::thread_id& id, const AZStd::thread_desc* desc);
|
||||
/// Called when we exit a thread.
|
||||
virtual void OnThreadExit(const AZStd::thread_id& id);
|
||||
|
||||
/// Output thread enter to stream.
|
||||
void OutputThreadEnter(const ThreadInfo& threadInfo);
|
||||
/// Output thread exit to stream.
|
||||
void OutputThreadExit(const ThreadInfo& threadInfo);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Profiler Driller bus
|
||||
virtual void OnRegisterSystem(AZ::u32 id, const char* name);
|
||||
|
||||
virtual void OnUnregisterSystem(AZ::u32 id);
|
||||
|
||||
virtual void OnNewRegister(const ProfilerRegister& reg, const AZStd::thread_id& threadId);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Read profile registers callback.
|
||||
bool ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id);
|
||||
|
||||
|
||||
|
||||
static const int m_numberOfSystemFilters = 16;
|
||||
int m_numberOfValidFilters = 0 ; ///< Number of valid filter set when the driller was created.
|
||||
Param m_systemFilters[m_numberOfSystemFilters]; ///< If != 0, it's a ID of specific System we would like to drill.
|
||||
ThreadArrayType m_threads;
|
||||
};
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
#endif // AZCORE_PROFILER_DRILLER_H
|
||||
#pragma once
|
||||
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_PROFILER_DRILLER_BUS_H
|
||||
#define AZCORE_PROFILER_DRILLER_BUS_H
|
||||
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
struct thread_id;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
class ProfilerRegister;
|
||||
|
||||
/**
|
||||
* ProfilerDrillerInterface driller profiler event interface, that records events from the profiler system.
|
||||
*/
|
||||
class ProfilerDrillerInterface
|
||||
: public DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~ProfilerDrillerInterface() {}
|
||||
|
||||
virtual void OnRegisterSystem(AZ::u32 id, const char* name) = 0;
|
||||
|
||||
virtual void OnUnregisterSystem(AZ::u32 id) = 0;
|
||||
|
||||
virtual void OnNewRegister(const ProfilerRegister& reg, const AZStd::thread_id& threadId) = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<ProfilerDrillerInterface> ProfilerDrillerBus;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AZCORE_PROFILER_DRILLER_BUS_H
|
||||
#pragma once
|
||||
@ -1,698 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#include <time.h>
|
||||
|
||||
#include <AzCore/IO/FileIOEventBus.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/DrillerBus.h>
|
||||
#include <AzCore/Driller/DrillerRootHandler.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/MemoryComponent.h>
|
||||
#include <AzCore/IO/Streamer/StreamerComponent.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
//#define AZ_CORE_DRILLER_COMPARE_TEST
|
||||
#if defined(AZ_CORE_DRILLER_COMPARE_TEST)
|
||||
# include <AzCore/IO/GenericStreams.h>
|
||||
# include <AzCore/Serialization/ObjectStream.h>
|
||||
# include <AzCore/Serialization/SerializeContext.h>
|
||||
#endif
|
||||
|
||||
#include <AZTestShared/Utils/Utils.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace AZ::Debug;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
/**
|
||||
* MyDriller event bus...
|
||||
*/
|
||||
class MyDrillerInterface
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MyDrillerInterface() {}
|
||||
// define one event X
|
||||
virtual void OnEventX(int data) = 0;
|
||||
// define a string event
|
||||
virtual void OnStringEvent() = 0;
|
||||
};
|
||||
|
||||
class MyDrillerCommandInterface
|
||||
: public AZ::Debug::DrillerEBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~MyDrillerCommandInterface() {}
|
||||
|
||||
virtual class MyDrilledObject* RequestDrilledObject() = 0;
|
||||
};
|
||||
|
||||
typedef AZ::EBus<MyDrillerInterface> MyDrillerBus;
|
||||
typedef AZ::EBus<MyDrillerCommandInterface> MyDrillerCommandBus;
|
||||
|
||||
class MyDrilledObject
|
||||
: public MyDrillerCommandBus::Handler
|
||||
{
|
||||
int i;
|
||||
public:
|
||||
MyDrilledObject()
|
||||
: i(0)
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
~MyDrilledObject() override
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// MyDrillerCommandBus
|
||||
MyDrilledObject* RequestDrilledObject() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void OnEventX()
|
||||
{
|
||||
EBUS_EVENT(MyDrillerBus, OnEventX, i);
|
||||
++i;
|
||||
}
|
||||
|
||||
void OnStringEvent()
|
||||
{
|
||||
EBUS_DBG_EVENT(MyDrillerBus, OnStringEvent);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* My driller implements the driller interface and an handles the MyDrillerBus events...
|
||||
*/
|
||||
class MyDriller
|
||||
: public Driller
|
||||
, public MyDrillerBus::Handler
|
||||
{
|
||||
bool m_isDetailedCapture;
|
||||
class MyDrilledObject* drilledObject;
|
||||
typedef vector<Param>::type ParamArrayType;
|
||||
ParamArrayType m_params;
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MyDriller, OSAllocator, 0);
|
||||
|
||||
const char* GroupName() const override { return "TestDrillers"; }
|
||||
const char* GetName() const override { return "MyTestDriller"; }
|
||||
const char* GetDescription() const override { return "MyTestDriller description...."; }
|
||||
int GetNumParams() const override { return static_cast<int>(m_params.size()); }
|
||||
const Param* GetParam(int index) const override { return &m_params[index]; }
|
||||
|
||||
MyDriller()
|
||||
: m_isDetailedCapture(false)
|
||||
, drilledObject(NULL)
|
||||
{
|
||||
Param isDetailed;
|
||||
isDetailed.desc = "IsDetailedDrill";
|
||||
isDetailed.name = AZ_CRC("IsDetailedDrill", 0x2155cef2);
|
||||
isDetailed.type = Param::PT_BOOL;
|
||||
isDetailed.value = 0;
|
||||
m_params.push_back(isDetailed);
|
||||
}
|
||||
|
||||
void Start(const Param* params = NULL, int numParams = 0) override
|
||||
{
|
||||
m_isDetailedCapture = m_params[0].value != 0;
|
||||
if (params)
|
||||
{
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
if (params[i].name == m_params[0].name)
|
||||
{
|
||||
m_isDetailedCapture = params[i].value != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EBUS_EVENT_RESULT(drilledObject, MyDrillerCommandBus, RequestDrilledObject);
|
||||
AZ_TEST_ASSERT(drilledObject != NULL); /// Make sure we have our object by the time we started the driller
|
||||
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("OnStart", 0x8b372fca), m_isDetailedCapture);
|
||||
// write drilled object initial state
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
|
||||
BusConnect();
|
||||
}
|
||||
void Stop() override
|
||||
{
|
||||
drilledObject = NULL;
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("OnStop", 0xf6701caa), m_isDetailedCapture);
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
void OnEventX(int data) override
|
||||
{
|
||||
void* ptr = AZ_INVALID_POINTER;
|
||||
float f = 3.2f;
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->Write(AZ_CRC("EventX", 0xc4558ec2), data);
|
||||
m_output->Write(AZ_CRC("Pointer", 0x320468a8), ptr);
|
||||
m_output->Write(AZ_CRC("Float", 0xc9a55e95), f);
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
}
|
||||
|
||||
void OnStringEvent() override
|
||||
{
|
||||
m_output->BeginTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
m_output->BeginTag(AZ_CRC("StringEvent", 0xd1e005df));
|
||||
m_output->Write(AZ_CRC("StringOne", 0x56efb231), "This is copied string");
|
||||
m_output->Write(AZ_CRC("StringTwo", 0x3d49bea6), "This is referenced string", false); // don't copy the string if we use string pool, this will be faster as we don't delete the string
|
||||
m_output->EndTag(AZ_CRC("StringEvent", 0xd1e005df));
|
||||
m_output->EndTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FileStreamDrillerTest
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
DrillerManager* m_drillerManager = nullptr;
|
||||
MyDriller* m_driller = nullptr;
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_drillerManager = DrillerManager::Create();
|
||||
m_driller = aznew MyDriller;
|
||||
// Register driller descriptor
|
||||
m_drillerManager->Register(m_driller);
|
||||
// check that our driller descriptor is registered
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// remove our driller descriptor
|
||||
m_drillerManager->Unregister(m_driller);
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 0);
|
||||
DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* My Driller data handler.
|
||||
*/
|
||||
class MyDrillerHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
static const bool s_isWarnOnMissingDrillers = true;
|
||||
int m_lastData;
|
||||
|
||||
MyDrillerHandler()
|
||||
: m_lastData(-1) {}
|
||||
|
||||
// From the template query
|
||||
DrillerHandlerParser* FindDrillerHandler(u32 drillerId)
|
||||
{
|
||||
if (drillerId == AZ_CRC("MyDriller", 0xc3b7dceb))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* OnEnterTag(u32 tagName) override
|
||||
{
|
||||
(void)tagName;
|
||||
return NULL;
|
||||
}
|
||||
void OnData(const DrillerSAXParser::Data& dataNode) override
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("OnStart", 0x8b372fca) || dataNode.m_name == AZ_CRC("OnStop", 0xf6701caa))
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataNode.Read(isDetailedCapture);
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("EventX", 0xc4558ec2))
|
||||
{
|
||||
int data;
|
||||
dataNode.Read(data);
|
||||
AZ_TEST_ASSERT(data > m_lastData);
|
||||
m_lastData = data;
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Pointer", 0x320468a8))
|
||||
{
|
||||
AZ::u64 pointer = 0; //< read pointers in u64 to cover all platforms
|
||||
dataNode.Read(pointer);
|
||||
AZ_TEST_ASSERT(pointer == 0x0badf00dul);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("Float", 0xc9a55e95))
|
||||
{
|
||||
float f;
|
||||
dataNode.Read(f);
|
||||
AZ_TEST_ASSERT(f == 3.2f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void run()
|
||||
{
|
||||
// get our driller descriptor
|
||||
Driller* driller = m_drillerManager->GetDriller(0);
|
||||
AZ_TEST_ASSERT(driller != NULL);
|
||||
AZ_TEST_ASSERT(strcmp(driller->GetName(), "MyTestDriller") == 0);
|
||||
AZ_TEST_ASSERT(driller->GetNumParams() == 1);
|
||||
|
||||
// read the default params and make a copy...
|
||||
Driller::Param param = *driller->GetParam(0);
|
||||
AZ_TEST_ASSERT(strcmp(param.desc, "IsDetailedDrill") == 0);
|
||||
AZ_TEST_ASSERT(param.name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(param.type == Driller::Param::PT_BOOL);
|
||||
// tweak the default params by enabling detailed drilling
|
||||
param.value = 1;
|
||||
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType dillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = driller->GetId(); // set driller id
|
||||
di.params.push_back(param); // set driller custom params
|
||||
dillersToDrill.push_back(di);
|
||||
|
||||
// open a driller output file stream
|
||||
// open a driller output file stream
|
||||
AZStd::string testFileName = GetTestFolderPath() + "drilltest.dat";
|
||||
DrillerOutputFileStream drillerOutputStream;
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object
|
||||
MyDrilledObject myDrilledObject;
|
||||
clock_t st = clock();
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
DrillerSession* drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
// trigger event X that we want to drill...
|
||||
myDrilledObject.OnEventX();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
AZ_Printf("Driller", "Compression time %.09f seconds\n", (double)(clock() - st) / CLOCKS_PER_SEC);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// try to load the drill data
|
||||
DrillerInputFileStream drillerInputStream;
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
DrillerDOMParser dp;
|
||||
AZ_TEST_ASSERT(dp.CanParse() == true);
|
||||
dp.ProcessStream(drillerInputStream);
|
||||
AZ_TEST_ASSERT(dp.CanParse() == true);
|
||||
drillerInputStream.Close();
|
||||
|
||||
u32 startDataId = AZ_CRC("StartData", 0xecf3f53f);
|
||||
u32 frameId = AZ_CRC("Frame", 0xb5f83ccd);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// read all data
|
||||
const DrillerDOMParser::Node* root = dp.GetRootNode();
|
||||
int lastFrame = -1;
|
||||
int lastData = -1;
|
||||
for (DrillerDOMParser::Node::NodeListType::const_iterator iter = root->m_tags.begin(); iter != root->m_tags.end(); ++iter)
|
||||
{
|
||||
const DrillerDOMParser::Node* node = &*iter;
|
||||
u32 name = node->m_name;
|
||||
AZ_TEST_ASSERT(name == startDataId || name == frameId);
|
||||
if (name == startDataId)
|
||||
{
|
||||
unsigned int currentPlatform;
|
||||
node->GetDataRequired(AZ_CRC("Platform", 0x3952d0cb))->Read(currentPlatform);
|
||||
AZ_TEST_ASSERT(currentPlatform == static_cast<int>(AZ::g_currentPlatform));
|
||||
const DrillerDOMParser::Node* drillerNode = node->GetTag(AZ_CRC("Driller", 0xa6e1fb73));
|
||||
AZ_TEST_ASSERT(drillerNode != NULL);
|
||||
AZ::u32 drillerName;
|
||||
drillerNode->GetDataRequired(AZ_CRC("Name", 0x5e237e06))->Read(drillerName);
|
||||
AZ_TEST_ASSERT(drillerName == m_driller->GetId());
|
||||
const DrillerDOMParser::Node* paramNode = drillerNode->GetTag(AZ_CRC("Param", 0xa4fa7c89));
|
||||
AZ_TEST_ASSERT(paramNode != NULL);
|
||||
u32 paramName;
|
||||
char paramDesc[128];
|
||||
int paramType;
|
||||
int paramValue;
|
||||
paramNode->GetDataRequired(AZ_CRC("Name", 0x5e237e06))->Read(paramName);
|
||||
AZ_TEST_ASSERT(paramName == param.name);
|
||||
paramNode->GetDataRequired(AZ_CRC("Description", 0x6de44026))->Read(paramDesc, AZ_ARRAY_SIZE(paramDesc));
|
||||
AZ_TEST_ASSERT(strcmp(paramDesc, param.desc) == 0);
|
||||
paramNode->GetDataRequired(AZ_CRC("Type", 0x8cde5729))->Read(paramType);
|
||||
AZ_TEST_ASSERT(paramType == param.type);
|
||||
paramNode->GetDataRequired(AZ_CRC("Value", 0x1d775834))->Read(paramValue);
|
||||
AZ_TEST_ASSERT(paramValue == param.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
int curFrame;
|
||||
node->GetDataRequired(AZ_CRC("FrameNum", 0x85a1a919))->Read(curFrame);
|
||||
AZ_TEST_ASSERT(curFrame > lastFrame); // check order
|
||||
lastFrame = curFrame;
|
||||
const DrillerDOMParser::Node* myDrillerNode = node->GetTag(AZ_CRC("MyDriller", 0xc3b7dceb));
|
||||
AZ_TEST_ASSERT(myDrillerNode != NULL);
|
||||
const DrillerDOMParser::Data* dataEntry;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("EventX", 0xc4558ec2));
|
||||
if (dataEntry)
|
||||
{
|
||||
int data;
|
||||
dataEntry->Read(data);
|
||||
AZ_TEST_ASSERT(data > lastData);
|
||||
lastData = data;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("Pointer", 0x320468a8));
|
||||
AZ_TEST_ASSERT(dataEntry);
|
||||
unsigned int ptr;
|
||||
dataEntry->Read(ptr);
|
||||
AZ_TEST_ASSERT(static_cast<size_t>(ptr) == reinterpret_cast<size_t>(AZ_INVALID_POINTER));
|
||||
float f;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("Float", 0xc9a55e95));
|
||||
AZ_TEST_ASSERT(dataEntry);
|
||||
dataEntry->Read(f);
|
||||
AZ_TEST_ASSERT(f == 3.2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataEntry = myDrillerNode->GetData(AZ_CRC("OnStart", 0x8b372fca));
|
||||
if (dataEntry)
|
||||
{
|
||||
dataEntry->Read(isDetailedCapture);
|
||||
}
|
||||
else
|
||||
{
|
||||
myDrillerNode->GetDataRequired(AZ_CRC("OnStop", 0xf6701caa))->Read(isDetailedCapture);
|
||||
}
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read that with Tag Handlers
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
|
||||
DrillerRootHandler<MyDrillerHandler> rootHandler;
|
||||
DrillerSAXParserHandler dhp(&rootHandler);
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
// Verify that Default templates forked fine...
|
||||
AZ_TEST_ASSERT(rootHandler.m_drillerSessionInfo.m_platform == static_cast<uint32_t>(AZ::g_currentPlatform));
|
||||
AZ_TEST_ASSERT(rootHandler.m_drillerSessionInfo.m_drillers.size() == 1);
|
||||
{
|
||||
const DrillerManager::DrillerInfo& dinfo = rootHandler.m_drillerSessionInfo.m_drillers.front();
|
||||
AZ_TEST_ASSERT(dinfo.id == AZ_CRC("MyTestDriller", 0x5cc4edf5));
|
||||
AZ_TEST_ASSERT(dinfo.params.size() == 1);
|
||||
AZ_TEST_ASSERT(strcmp(param.desc, "IsDetailedDrill") == 0);
|
||||
AZ_TEST_ASSERT(param.name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(param.type == Driller::Param::PT_BOOL);
|
||||
// tweak the default params by enabling detailed drilling
|
||||
param.value = 1;
|
||||
AZ_TEST_ASSERT(dinfo.params[0].name == AZ_CRC("IsDetailedDrill", 0x2155cef2));
|
||||
AZ_TEST_ASSERT(dinfo.params[0].desc == NULL); // ignored for now
|
||||
AZ_TEST_ASSERT(dinfo.params[0].type == Driller::Param::PT_BOOL);
|
||||
AZ_TEST_ASSERT(dinfo.params[0].value == 1);
|
||||
}
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FileStreamDrillerTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class StringPoolDrillerTest
|
||||
: public AllocatorsFixture
|
||||
{
|
||||
DrillerManager* m_drillerManager = nullptr;
|
||||
MyDriller* m_driller = nullptr;
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
|
||||
m_drillerManager = DrillerManager::Create();
|
||||
m_driller = aznew MyDriller;
|
||||
// Register driller descriptor
|
||||
m_drillerManager->Register(m_driller);
|
||||
// check that our driller descriptor is registered
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 1);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// remove our driller descriptor
|
||||
m_drillerManager->Unregister(m_driller);
|
||||
AZ_TEST_ASSERT(m_drillerManager->GetNumDrillers() == 0);
|
||||
DrillerManager::Destroy(m_drillerManager);
|
||||
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* My Driller data handler.
|
||||
*/
|
||||
class MyDrillerHandler
|
||||
: public DrillerHandlerParser
|
||||
{
|
||||
public:
|
||||
static const bool s_isWarnOnMissingDrillers = true;
|
||||
|
||||
MyDrillerHandler() {}
|
||||
|
||||
// From the template query
|
||||
DrillerHandlerParser* FindDrillerHandler(u32 drillerId)
|
||||
{
|
||||
if (drillerId == AZ_CRC("MyDriller", 0xc3b7dceb))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DrillerHandlerParser* OnEnterTag(u32 tagName) override
|
||||
{
|
||||
if (tagName == AZ_CRC("StringEvent", 0xd1e005df))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void OnData(const DrillerSAXParser::Data& dataNode) override
|
||||
{
|
||||
if (dataNode.m_name == AZ_CRC("OnStart", 0x8b372fca) || dataNode.m_name == AZ_CRC("OnStop", 0xf6701caa))
|
||||
{
|
||||
bool isDetailedCapture;
|
||||
dataNode.Read(isDetailedCapture);
|
||||
AZ_TEST_ASSERT(isDetailedCapture == true);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("StringOne", 0x56efb231))
|
||||
{
|
||||
// read string as a copy
|
||||
char stringCopy[256];
|
||||
dataNode.Read(stringCopy, AZ_ARRAY_SIZE(stringCopy));
|
||||
AZ_TEST_ASSERT(strcmp(stringCopy, "This is copied string") == 0);
|
||||
}
|
||||
else if (dataNode.m_name == AZ_CRC("StringTwo", 0x3d49bea6))
|
||||
{
|
||||
// read string as reference if possible, otherwise read it as a copy
|
||||
const char* stringRef = dataNode.ReadPooledString();
|
||||
AZ_TEST_ASSERT(strcmp(stringRef, "This is referenced string") == 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void run()
|
||||
{
|
||||
// get our driller descriptor
|
||||
Driller* driller = m_drillerManager->GetDriller(0);
|
||||
Driller::Param param = *driller->GetParam(0);
|
||||
param.value = 1;
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType dillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = driller->GetId(); // set driller id
|
||||
di.params.push_back(param); // set driller custom params
|
||||
dillersToDrill.push_back(di);
|
||||
|
||||
MyDrilledObject myDrilledObject;
|
||||
|
||||
// open a driller output file stream
|
||||
AZStd::string testFileName = GetTestFolderPath() + "stringpooldrilltest.dat";
|
||||
DrillerOutputFileStream drillerOutputStream;
|
||||
DrillerInputFileStream drillerInputStream;
|
||||
DrillerDefaultStringPool stringPool;
|
||||
DrillerSession* drillerSession;
|
||||
DrillerRootHandler<MyDrillerHandler> rootHandler;
|
||||
DrillerSAXParserHandler dhp(&rootHandler);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object without string pools
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
myDrilledObject.OnStringEvent();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read all data that was written without string pool, in a stream that uses one.
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
drillerInputStream.SetStringPool(&stringPool);
|
||||
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Drill an object without string pools
|
||||
drillerOutputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
stringPool.Reset();
|
||||
drillerOutputStream.SetStringPool(&stringPool); // set the string pool on save
|
||||
|
||||
// start a driller session with the file stream and the list of drillers
|
||||
drillerSession = m_drillerManager->Start(drillerOutputStream, dillersToDrill);
|
||||
// update for N frames
|
||||
for (int i = 0; i < AZ_TRAIT_UNIT_TEST_DILLER_TRIGGER_EVENT_COUNT; ++i)
|
||||
{
|
||||
myDrilledObject.OnStringEvent();
|
||||
m_drillerManager->FrameUpdate();
|
||||
}
|
||||
// stop the drillers
|
||||
m_drillerManager->Stop(drillerSession);
|
||||
// Stop writing and flush all data
|
||||
drillerOutputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read all data that was written without string pool, in a stream that uses one.
|
||||
stringPool.Reset();
|
||||
drillerInputStream.Open(testFileName.c_str(), IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
drillerInputStream.SetStringPool(&stringPool);
|
||||
|
||||
dhp.ProcessStream(drillerInputStream);
|
||||
drillerInputStream.Close();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(StringPoolDrillerTest, Test)
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class DrillFileStreamCheck
|
||||
{
|
||||
public:
|
||||
void run()
|
||||
{
|
||||
// open and read drilled file
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Driller application test
|
||||
*/
|
||||
TEST(DrillerApplication, Test)
|
||||
{
|
||||
ComponentApplication app;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Create application environment code driven
|
||||
ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024;
|
||||
appDesc.m_enableDrilling = true;
|
||||
Entity* systemEntity = app.Create(appDesc);
|
||||
|
||||
systemEntity->CreateComponent<MemoryComponent>();
|
||||
systemEntity->CreateComponent<StreamerComponent>(); // note that this component is what registers the streamer driller
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->Activate();
|
||||
|
||||
{
|
||||
// open a driller output file stream
|
||||
char testFileName[AZ_MAX_PATH_LEN];
|
||||
MakePathFromTestFolder(testFileName, AZ_MAX_PATH_LEN, "drillapptest.dat");
|
||||
DrillerOutputFileStream fs;
|
||||
fs.Open(testFileName, IO::SystemFile::SF_OPEN_CREATE | IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
|
||||
// create a list of driller we what to drill
|
||||
DrillerManager::DrillerListType drillersToDrill;
|
||||
DrillerManager::DrillerInfo di;
|
||||
di.id = AZ_CRC("TraceMessagesDriller", 0xa61d1b00);
|
||||
drillersToDrill.push_back(di);
|
||||
di.id = AZ_CRC("MemoryDriller", 0x1b31269d);
|
||||
drillersToDrill.push_back(di);
|
||||
|
||||
ASSERT_NE(nullptr, app.GetDrillerManager());
|
||||
DrillerSession* drillerSession = app.GetDrillerManager()->Start(fs, drillersToDrill);
|
||||
ASSERT_NE(nullptr, drillerSession);
|
||||
|
||||
const int numOfFrames = 10000;
|
||||
void* memory = NULL;
|
||||
for (int i = 0; i < numOfFrames; ++i)
|
||||
{
|
||||
memory = azmalloc(rand() % 2048 + 1);
|
||||
azfree(memory);
|
||||
app.Tick();
|
||||
}
|
||||
|
||||
app.GetDrillerManager()->Stop(drillerSession); // stop session manually
|
||||
fs.Close(); // close the file with driller info
|
||||
}
|
||||
|
||||
app.Destroy();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
}
|
||||
@ -1,208 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/UnitTest/UnitTest.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/parallel/thread.h>
|
||||
|
||||
#include <AzCore/Statistics/TimeDataStatisticsManager.h>
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Component/EntityUtils.h>
|
||||
#include <AzCore/Debug/FrameProfilerBus.h>
|
||||
#include <AzCore/Debug/FrameProfilerComponent.h>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace Debug;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
/**
|
||||
* Validate functionality of the convenience class TimeDataStatisticsManager.
|
||||
* It is a specialized version of RunningStatisticsManager that works with Timer type
|
||||
* of registers that can be captured with the FrameProfilerBus::OnFrameProfilerData()
|
||||
*/
|
||||
class TimeDataStatisticsManagerTest
|
||||
: public AllocatorsFixture
|
||||
, public FrameProfilerBus::Handler
|
||||
{
|
||||
static constexpr const char* PARENT_TIMER_STAT = "ParentStat";
|
||||
static constexpr const char* CHILD_TIMER_STAT0 = "ChildStat0";
|
||||
static constexpr const char* CHILD_TIMER_STAT1 = "ChildStat1";
|
||||
|
||||
public:
|
||||
TimeDataStatisticsManagerTest()
|
||||
: AllocatorsFixture()
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
m_statsManager = AZStd::make_unique<Statistics::TimeDataStatisticsManager>();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_statsManager = nullptr;
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// FrameProfilerBus
|
||||
virtual void OnFrameProfilerData(const FrameProfiler::ThreadDataArray& data)
|
||||
{
|
||||
for (size_t iThread = 0; iThread < data.size(); ++iThread)
|
||||
{
|
||||
const FrameProfiler::ThreadData& td = data[iThread];
|
||||
FrameProfiler::ThreadData::RegistersMap::const_iterator regIt = td.m_registers.begin();
|
||||
for (; regIt != td.m_registers.end(); ++regIt)
|
||||
{
|
||||
const FrameProfiler::RegisterData& rd = regIt->second;
|
||||
u32 unitTestCrc = AZ_CRC("UnitTest", 0x8089cea8);
|
||||
if (unitTestCrc != rd.m_systemId)
|
||||
{
|
||||
continue; //Not for us.
|
||||
}
|
||||
ASSERT_EQ(ProfilerRegister::PRT_TIME, rd.m_type);
|
||||
const FrameProfiler::FrameData& fd = rd.m_frames.back();
|
||||
m_statsManager->PushTimeDataSample(rd.m_name, fd.m_timeData);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ChildFunction0(int numIterations, int sleepTimeMilliseconds)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(UnitTest, CHILD_TIMER_STAT0);
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
|
||||
int result = 5;
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
result += i % 3;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ChildFunction1(int numIterations, int sleepTimeMilliseconds)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(UnitTest, CHILD_TIMER_STAT1);
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
|
||||
int result = 5;
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
result += i % 3;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ParentFunction(int numIterations, int sleepTimeMilliseconds)
|
||||
{
|
||||
AZ_PROFILE_SCOPE(UnitTest, PARENT_TIMER_STAT);
|
||||
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(sleepTimeMilliseconds));
|
||||
int result = 0;
|
||||
result += ChildFunction0(numIterations, sleepTimeMilliseconds);
|
||||
result += ChildFunction1(numIterations, sleepTimeMilliseconds);
|
||||
return result;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
Debug::FrameProfilerBus::Handler::BusConnect();
|
||||
|
||||
ComponentApplication app;
|
||||
ComponentApplication::Descriptor desc;
|
||||
desc.m_useExistingAllocator = true;
|
||||
desc.m_enableDrilling = false; // we already created a memory driller for the test (AllocatorsFixture)
|
||||
ComponentApplication::StartupParameters startupParams;
|
||||
startupParams.m_allocator = &AllocatorInstance<SystemAllocator>::Get();
|
||||
Entity* systemEntity = app.Create(desc, startupParams);
|
||||
systemEntity->CreateComponent<FrameProfilerComponent>();
|
||||
|
||||
systemEntity->Init();
|
||||
systemEntity->Activate(); // start frame component
|
||||
|
||||
const int sleepTimeAllFuncsMillis = 1;
|
||||
const int numIterations = 10;
|
||||
for (int iterationCounter = 0; iterationCounter < numIterations; ++iterationCounter)
|
||||
{
|
||||
ParentFunction(numIterations, sleepTimeAllFuncsMillis);
|
||||
//Collect all samples.
|
||||
app.Tick();
|
||||
}
|
||||
|
||||
//Verify we have three running stats.
|
||||
{
|
||||
AZStd::vector<Statistics::NamedRunningStatistic*> allStats;
|
||||
m_statsManager->GetAllStatistics(allStats);
|
||||
EXPECT_EQ(allStats.size(), 3);
|
||||
}
|
||||
|
||||
AZStd::string parentStatName(PARENT_TIMER_STAT);
|
||||
AZStd::string child0StatName(CHILD_TIMER_STAT0);
|
||||
AZStd::string child1StatName(CHILD_TIMER_STAT1);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(parentStatName) != nullptr);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child0StatName) != nullptr);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child1StatName) != nullptr);
|
||||
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(parentStatName)->GetNumSamples(), numIterations);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child0StatName)->GetNumSamples(), numIterations);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName)->GetNumSamples(), numIterations);
|
||||
|
||||
const double minimumExpectDurationOfChildFunctionMicros = 1;
|
||||
const double minimumExpectDurationOfParentFunctionMicros = 1;
|
||||
|
||||
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetMinimum(), minimumExpectDurationOfParentFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetAverage(), minimumExpectDurationOfParentFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(parentStatName)->GetMaximum(), minimumExpectDurationOfParentFunctionMicros);
|
||||
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetMinimum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetAverage(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child0StatName)->GetMaximum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetMinimum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetAverage(), minimumExpectDurationOfChildFunctionMicros);
|
||||
EXPECT_GE(m_statsManager->GetStatistic(child1StatName)->GetMaximum(), minimumExpectDurationOfChildFunctionMicros);
|
||||
|
||||
//Let's validate TimeDataStatisticsManager::RemoveStatistics()
|
||||
m_statsManager->RemoveStatistic(child1StatName);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(parentStatName) != nullptr);
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child0StatName) != nullptr);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName), nullptr);
|
||||
|
||||
//Let's store the sample count for both parentStatName and child0StatName.
|
||||
const AZ::u64 numSamplesParent = m_statsManager->GetStatistic(parentStatName)->GetNumSamples();
|
||||
const AZ::u64 numSamplesChild0 = m_statsManager->GetStatistic(child0StatName)->GetNumSamples();
|
||||
|
||||
//Let's call child1 function again and call app.Tick(). child1StatName should be readded to m_statsManager.
|
||||
ChildFunction1(numIterations, sleepTimeAllFuncsMillis);
|
||||
app.Tick();
|
||||
ASSERT_TRUE(m_statsManager->GetStatistic(child1StatName) != nullptr);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(parentStatName)->GetNumSamples(), numSamplesParent);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child0StatName)->GetNumSamples(), numSamplesChild0);
|
||||
EXPECT_EQ(m_statsManager->GetStatistic(child1StatName)->GetNumSamples(), 1);
|
||||
|
||||
Debug::FrameProfilerBus::Handler::BusDisconnect();
|
||||
app.Destroy();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<Statistics::TimeDataStatisticsManager> m_statsManager;
|
||||
};//class TimeDataStatisticsManagerTest
|
||||
|
||||
// TODO:BUDGETS disabled until profiler budgets system comes online
|
||||
// TEST_F(TimeDataStatisticsManagerTest, Test)
|
||||
// {
|
||||
// run();
|
||||
// }
|
||||
//End of all Tests of TimeDataStatisticsManagerTest
|
||||
|
||||
}//namespace UnitTest
|
||||
@ -1,197 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Driller/DrillToFileComponent.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void DrillToFileComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<DrillToFileComponent, AZ::Component>()
|
||||
;
|
||||
|
||||
if (serialize->FindClassData(DrillerInfo::RTTI_Type()) == nullptr)
|
||||
{
|
||||
serialize->Class<DrillerInfo>()
|
||||
->Field("Id", &DrillerInfo::m_id)
|
||||
->Field("GroupName", &DrillerInfo::m_groupName)
|
||||
->Field("Name", &DrillerInfo::m_name)
|
||||
->Field("Description", &DrillerInfo::m_description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrillToFileComponent::Activate()
|
||||
{
|
||||
m_drillerSession = nullptr;
|
||||
DrillerConsoleCommandBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void DrillToFileComponent::Deactivate()
|
||||
{
|
||||
DrillerConsoleCommandBus::Handler::BusDisconnect();
|
||||
StopDrillerSession(reinterpret_cast<AZ::u64>(this));
|
||||
}
|
||||
|
||||
void DrillToFileComponent::WriteBinary(const void* data, unsigned int dataSize)
|
||||
{
|
||||
if (dataSize > 0)
|
||||
{
|
||||
m_frameBuffer.insert(m_frameBuffer.end(), reinterpret_cast<const AZ::u8*>(data), reinterpret_cast<const AZ::u8*>(data) + dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
void DrillToFileComponent::OnEndOfFrame()
|
||||
{
|
||||
AZStd::lock_guard<AZStd::mutex> lock(m_writerMutex);
|
||||
m_writeQueue.push_back();
|
||||
m_writeQueue.back().swap(m_frameBuffer);
|
||||
m_signal.notify_all();
|
||||
}
|
||||
|
||||
void DrillToFileComponent::EnumerateAvailableDrillers()
|
||||
{
|
||||
DrillerInfoListType availableDrillers;
|
||||
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
for (int i = 0; i < mgr->GetNumDrillers(); ++i)
|
||||
{
|
||||
AZ::Debug::Driller* driller = mgr->GetDriller(i);
|
||||
AZ_Assert(driller, "DrillerManager returned a NULL driller. This is not legal!");
|
||||
availableDrillers.push_back();
|
||||
availableDrillers.back().m_id = driller->GetId();
|
||||
availableDrillers.back().m_groupName = driller->GroupName();
|
||||
availableDrillers.back().m_name = driller->GetName();
|
||||
availableDrillers.back().m_description = driller->GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
EBUS_EVENT(DrillerConsoleEventBus, OnDrillersEnumerated, availableDrillers);
|
||||
}
|
||||
|
||||
void DrillToFileComponent::StartDrillerSession(const AZ::Debug::DrillerManager::DrillerListType& requestedDrillers, AZ::u64 sessionId)
|
||||
{
|
||||
if (!m_drillerSession)
|
||||
{
|
||||
AZ_Assert(m_writeQueue.empty(), "write queue is not empty!");
|
||||
|
||||
m_sessionId = sessionId;
|
||||
AZ::Debug::DrillerManager* mgr = nullptr;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
SetStringPool(&m_stringPool);;
|
||||
m_drillerSession = mgr->Start(*this, requestedDrillers);
|
||||
|
||||
AZStd::unique_lock<AZStd::mutex> signalLock(m_writerMutex);
|
||||
m_isWriterEnabled = true;
|
||||
AZStd::thread_desc td;
|
||||
td.m_name = "DrillToFileComponent Writer Thread";
|
||||
m_writerThread = AZStd::thread(AZStd::bind(&DrillToFileComponent::AsyncWritePump, this), &td);
|
||||
m_signal.wait(signalLock);
|
||||
|
||||
EBUS_EVENT(DrillerConsoleEventBus, OnDrillerSessionStarted, sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrillToFileComponent::StopDrillerSession(AZ::u64 sessionId)
|
||||
{
|
||||
if (sessionId == m_sessionId)
|
||||
{
|
||||
if (m_drillerSession)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop(m_drillerSession);
|
||||
}
|
||||
m_drillerSession = nullptr;
|
||||
EBUS_EVENT(DrillerConsoleEventBus, OnDrillerSessionStopped, reinterpret_cast<AZ::u64>(this));
|
||||
}
|
||||
|
||||
m_isWriterEnabled = false;
|
||||
if (m_writerThread.joinable())
|
||||
{
|
||||
m_writerMutex.lock();
|
||||
m_signal.notify_all();
|
||||
m_writerMutex.unlock();
|
||||
m_writerThread.join();
|
||||
}
|
||||
SetStringPool(nullptr);
|
||||
m_stringPool.Reset();
|
||||
m_frameBuffer.clear(); // there may be pending data but we don't want to write it because it's an incomplete frame.
|
||||
}
|
||||
}
|
||||
void DrillToFileComponent::AsyncWritePump()
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> signalLock(m_writerMutex);
|
||||
|
||||
AZStd::basic_string<char, AZStd::char_traits<char>, AZ::OSStdAllocator> drillerOutputPath;
|
||||
|
||||
// Try the log path first
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
if (fileIO)
|
||||
{
|
||||
const char* logLocation = fileIO->GetAlias("@log@");
|
||||
if (logLocation)
|
||||
{
|
||||
drillerOutputPath = logLocation;
|
||||
drillerOutputPath.append("/");
|
||||
}
|
||||
}
|
||||
|
||||
// Try the executable path
|
||||
if (drillerOutputPath.empty())
|
||||
{
|
||||
EBUS_EVENT_RESULT(drillerOutputPath, AZ::ComponentApplicationBus, GetExecutableFolder);
|
||||
drillerOutputPath.append("/");
|
||||
}
|
||||
|
||||
drillerOutputPath.append("drillerdata.drl");
|
||||
AZ::IO::SystemFile output;
|
||||
output.Open(drillerOutputPath.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
AZ_Assert(output.IsOpen(), "Failed to open driller output file!");
|
||||
|
||||
m_signal.notify_all();
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (!m_writeQueue.empty())
|
||||
{
|
||||
AZStd::vector<AZ::u8, AZ::OSStdAllocator> outBuffer;
|
||||
outBuffer.swap(m_writeQueue.front());
|
||||
m_writeQueue.pop_front();
|
||||
signalLock.unlock();
|
||||
|
||||
output.Write(outBuffer.data(), outBuffer.size());
|
||||
output.Flush();
|
||||
|
||||
signalLock.lock();
|
||||
}
|
||||
if (!m_isWriterEnabled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_signal.wait(signalLock);
|
||||
}
|
||||
|
||||
output.Close();
|
||||
}
|
||||
} // namespace AzFramework
|
||||
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Driller/DrillerConsoleAPI.h>
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
#include <AzCore/std/parallel/condition_variable.h>
|
||||
|
||||
//#define ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
struct ClassDataReflection;
|
||||
}
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/**
|
||||
* Runs on the machine being drilled and is responsible for communications
|
||||
* with the DrillerNetworkConsole running on the tool side as well as
|
||||
* creating DrillerNetSessionStreams for each driller session being started.
|
||||
*/
|
||||
class DrillToFileComponent
|
||||
: public AZ::Component
|
||||
, public AZ::Debug::DrillerOutputStream
|
||||
, public DrillerConsoleCommandBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(DrillToFileComponent, "{42BAA25D-7CEB-4A37-8BD4-4A1FE2253894}")
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerOutputStream
|
||||
void WriteBinary(const void* data, unsigned int dataSize) override;
|
||||
void OnEndOfFrame() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerConsoleCommandBus
|
||||
void EnumerateAvailableDrillers() override;
|
||||
void StartDrillerSession(const AZ::Debug::DrillerManager::DrillerListType& requestedDrillers, AZ::u64 sessionId) override;
|
||||
void StopDrillerSession(AZ::u64 sessionId) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
void AsyncWritePump();
|
||||
|
||||
AZ::u64 m_sessionId;
|
||||
AZ::Debug::DrillerSession* m_drillerSession;
|
||||
AZ::Debug::DrillerDefaultStringPool m_stringPool;
|
||||
AZStd::vector<AZ::u8, AZ::OSStdAllocator> m_frameBuffer;
|
||||
AZStd::deque<AZStd::vector<AZ::u8, AZ::OSStdAllocator>, AZ::OSStdAllocator> m_writeQueue;
|
||||
AZStd::mutex m_writerMutex;
|
||||
AZStd::condition_variable m_signal;
|
||||
AZStd::thread m_writerThread;
|
||||
bool m_isWriterEnabled;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/*
|
||||
* Descriptors for drillers available on the target machine.
|
||||
*/
|
||||
struct DrillerInfo final
|
||||
{
|
||||
AZ_RTTI(DrillerInfo, "{197AC318-B65C-4B36-A109-BD25422BF7D0}");
|
||||
AZ::u32 m_id;
|
||||
AZStd::string m_groupName;
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_description;
|
||||
};
|
||||
|
||||
typedef AZStd::vector<DrillerInfo> DrillerInfoListType;
|
||||
typedef AZStd::vector<AZ::u32> DrillerListType;
|
||||
|
||||
/**
|
||||
* Driller clients interested in receiving notification events from the
|
||||
* console should implement this interface.
|
||||
*/
|
||||
class DrillerConsoleEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerConsoleEvents() {}
|
||||
|
||||
// A list of available drillers has been received from the target machine.
|
||||
virtual void OnDrillersEnumerated(const DrillerInfoListType& availableDrillers) = 0;
|
||||
virtual void OnDrillerSessionStarted(AZ::u64 sessionId) = 0;
|
||||
virtual void OnDrillerSessionStopped(AZ::u64 sessionId) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerConsoleEvents> DrillerConsoleEventBus;
|
||||
|
||||
/**
|
||||
* Commands can be sent to the driller through this interface.
|
||||
*/
|
||||
class DrillerConsoleCommands
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
|
||||
// there's only one driller console instance allowed
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerConsoleCommands() {}
|
||||
|
||||
// Request an enumeration of available drillers from the target machine
|
||||
virtual void EnumerateAvailableDrillers() = 0;
|
||||
// Start a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StartDrillerSession(const AZ::Debug::DrillerManager::DrillerListType& requestedDrillers, AZ::u64 sessionId) = 0;
|
||||
// Stop a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StopDrillerSession(AZ::u64 sessionId) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerConsoleCommands> DrillerConsoleCommandBus;
|
||||
} // namespace AzFramework
|
||||
@ -1,740 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzFramework/Driller/RemoteDrillerInterface.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Driller/Stream.h>
|
||||
#include <AzCore/Driller/DefaultStringPool.h>
|
||||
#include <AzCore/std/containers/fixed_vector.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
//---------------------------------------------------------------------
|
||||
// TEMP FOR DEBUGGING ONLY!!!
|
||||
//---------------------------------------------------------------------
|
||||
class DebugDrillerRemoteSession
|
||||
: public DrillerRemoteSession
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DebugDrillerRemoteSession, AZ::OSAllocator, 0);
|
||||
|
||||
DebugDrillerRemoteSession()
|
||||
{
|
||||
AZStd::string filename = AZStd::string::format("remotedrill_%llu", static_cast<AZ::u64>(reinterpret_cast<size_t>(static_cast<DrillerRemoteSession*>(this))));
|
||||
m_file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE);
|
||||
}
|
||||
|
||||
~DebugDrillerRemoteSession()
|
||||
{
|
||||
m_file.Close();
|
||||
}
|
||||
|
||||
virtual void ProcessIncomingDrillerData(const char* streamIdentifier, const void* data, size_t dataSize)
|
||||
{
|
||||
(void)streamIdentifier;
|
||||
|
||||
m_file.Write(data, dataSize);
|
||||
}
|
||||
|
||||
virtual void OnDrillerConnectionLost()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
AZ::IO::SystemFile m_file;
|
||||
};
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* These are the different synchronization messages that are used.
|
||||
*/
|
||||
namespace NetworkDrillerSyncMsgId
|
||||
{
|
||||
static const AZ::Crc32 NetDrillMsg_RequestDrillerEnum = AZ_CRC("NetDrillMsg_RequestEnum", 0x517cca25);
|
||||
static const AZ::Crc32 NetDrillMsg_RequestStartSession = AZ_CRC("NetDrillMsg_RequestStartSession", 0x5238b5fe);
|
||||
static const AZ::Crc32 NetDrillMsg_RequestStopSession = AZ_CRC("NetDrillMsg_RequestStopSession", 0x1abe6888);
|
||||
static const AZ::Crc32 NetDrillMsg_DrillerEnum = AZ_CRC("NetDrillMsg_Enum", 0x3d0a0f76);
|
||||
};
|
||||
|
||||
struct NetDrillerStartSessionRequest
|
||||
: public TmMsg
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(NetDrillerStartSessionRequest, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(NetDrillerStartSessionRequest, "{FF899D61-A445-44B5-9B67-8319ACC8BB06}");
|
||||
|
||||
NetDrillerStartSessionRequest()
|
||||
: TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStartSession) {}
|
||||
|
||||
// TODO: Replace this with the DrillerListType from driller.h
|
||||
DrillerListType m_drillerIds;
|
||||
AZ::u64 m_sessionId;
|
||||
};
|
||||
|
||||
struct NetDrillerStopSessionRequest
|
||||
: public TmMsg
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(NetDrillerStopSessionRequest, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(NetDrillerStopSessionRequest, "{BCC6524F-287F-48D2-A21A-029215DB24DD}");
|
||||
|
||||
NetDrillerStopSessionRequest(AZ::u64 sessionId = 0)
|
||||
: TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStopSession)
|
||||
, m_sessionId(sessionId) {}
|
||||
|
||||
AZ::u64 m_sessionId;
|
||||
};
|
||||
|
||||
struct NetDrillerEnumeration
|
||||
: public TmMsg
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR(NetDrillerEnumeration, AZ::OSAllocator, 0);
|
||||
AZ_RTTI(NetDrillerEnumeration, "{60E5BED2-F492-4A55-8EF6-2628CD390991}");
|
||||
|
||||
NetDrillerEnumeration()
|
||||
: TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_DrillerEnum) {}
|
||||
|
||||
DrillerInfoListType m_enumeration;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerRemoteSession
|
||||
//---------------------------------------------------------------------
|
||||
DrillerRemoteSession::DrillerRemoteSession()
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
: m_decompressor(&AZ::AllocatorInstance<AZ::OSAllocator>::Get())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
DrillerRemoteSession::~DrillerRemoteSession()
|
||||
{
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::StartDrilling(const DrillerListType& drillers, const char* captureFile)
|
||||
{
|
||||
if (captureFile)
|
||||
{
|
||||
m_captureFile.Open(captureFile, AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
|
||||
AZ_Warning("DrillerRemoteSession", m_captureFile.IsOpen(), "Failed to open %s. Driller data will not be saved.", captureFile);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_decompressor.StartDecompressor();
|
||||
#endif
|
||||
BusConnect(static_cast<AZ::u64>(reinterpret_cast<size_t>(this)));
|
||||
EBUS_EVENT(DrillerNetworkConsoleCommandBus, StartRemoteDrillerSession, drillers, this);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::StopDrilling()
|
||||
{
|
||||
EBUS_EVENT(DrillerNetworkConsoleCommandBus, StopRemoteDrillerSession, static_cast<AZ::u64>(reinterpret_cast<size_t>(this)));
|
||||
BusDisconnect();
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
if (m_decompressor.IsDecompressorStarted())
|
||||
{
|
||||
m_decompressor.StopDecompressor();
|
||||
}
|
||||
#endif
|
||||
|
||||
m_captureFile.Close();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::LoadCaptureData(const char* fileName)
|
||||
{
|
||||
m_captureFile.Open(fileName, AZ::IO::SystemFile::SF_OPEN_READ_ONLY);
|
||||
AZ_Warning("DrillerRemoteSession", m_captureFile.IsOpen(), "Failed to open %s. No driller data could be loaded.", fileName);
|
||||
if (m_captureFile.IsOpen())
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_decompressor.StartDecompressor();
|
||||
#endif
|
||||
AZ::IO::SystemFile::SizeType bytesRemaining = m_captureFile.Length();
|
||||
AZ::IO::SystemFile::SizeType maxReadChunkSize = 1024 * 1024;
|
||||
AZStd::vector<char> readBuffer;
|
||||
readBuffer.resize_no_construct(static_cast<size_t>(maxReadChunkSize));
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
AZ::IO::SystemFile::SizeType bytesToRead = bytesRemaining < maxReadChunkSize ? bytesRemaining : maxReadChunkSize;
|
||||
if (m_captureFile.Read(bytesToRead, readBuffer.data()) != bytesToRead)
|
||||
{
|
||||
AZ_Warning("DrillerRemoteSession", false, "Failed reading driller data. No more driller data can be read.");
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
Decompress(readBuffer.data(), static_cast<size_t>(bytesToRead));
|
||||
ProcessIncomingDrillerData(fileName, m_uncompressedMsgBuffer.data(), m_uncompressedMsgBuffer.size());
|
||||
#else
|
||||
ProcessIncomingDrillerData(fileName, readBuffer.data(), readBuffer.size());
|
||||
#endif
|
||||
bytesRemaining -= bytesToRead;
|
||||
}
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_decompressor.StopDecompressor();
|
||||
#endif
|
||||
m_captureFile.Close();
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::OnReceivedMsg(TmMsgPtr msg)
|
||||
{
|
||||
AZ_Assert(msg->GetCustomBlob(), "Missing driller frame data!");
|
||||
|
||||
if (msg->GetCustomBlobSize() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_captureFile.IsOpen())
|
||||
{
|
||||
if (m_captureFile.Write(msg->GetCustomBlob(), msg->GetCustomBlobSize()) != msg->GetCustomBlobSize())
|
||||
{
|
||||
AZ_Warning("DrillerRemoteSession", false, "Failed writing capture data to %s, no more data will be written out.", m_captureFile.Name());
|
||||
m_captureFile.Close();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
Decompress(msg->GetCustomBlob(), msg->GetCustomBlobSize());
|
||||
ProcessIncomingDrillerData(m_captureFile.Name(),m_uncompressedMsgBuffer.data(), m_uncompressedMsgBuffer.size());
|
||||
#else
|
||||
ProcessIncomingDrillerData(m_captureFile.Name(),msg->GetCustomBlob(), msg->GetCustomBlobSize());
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerRemoteSession::Decompress(const void* compressedBuffer, size_t compressedBufferSize)
|
||||
{
|
||||
m_uncompressedMsgBuffer.clear();
|
||||
if (m_uncompressedMsgBuffer.capacity() < compressedBufferSize * 10)
|
||||
{
|
||||
m_uncompressedMsgBuffer.reserve(compressedBufferSize * 10);
|
||||
}
|
||||
#if defined(ENABLE_COMPRESSION_FOR_REMOTE_DRILLER)
|
||||
unsigned int compressedBytesRemaining = static_cast<unsigned int>(compressedBufferSize);
|
||||
unsigned int decompressedBytes = 0;
|
||||
while (compressedBytesRemaining > 0)
|
||||
{
|
||||
unsigned int uncompressedBytes = c_decompressionBufferSize;
|
||||
unsigned int bytesConsumed = m_decompressor.Decompress(reinterpret_cast<const char*>(compressedBuffer) + decompressedBytes, compressedBytesRemaining, m_decompressionBuffer, uncompressedBytes);
|
||||
decompressedBytes += bytesConsumed;
|
||||
compressedBytesRemaining -= bytesConsumed;
|
||||
m_uncompressedMsgBuffer.insert(m_uncompressedMsgBuffer.end(), &m_decompressionBuffer[0], &m_decompressionBuffer[uncompressedBytes]);
|
||||
}
|
||||
#else
|
||||
m_uncompressedMsgBuffer.insert(m_uncompressedMsgBuffer.end(), &((char*)compressedBuffer)[0], &((char*)compressedBuffer)[compressedBufferSize]);
|
||||
#endif
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerNetSessionStream
|
||||
//---------------------------------------------------------------------
|
||||
/**
|
||||
* Represents a driller session on the target machine.
|
||||
* It is responsible for listening for driller events and forwarding
|
||||
* them to the console machine.
|
||||
*/
|
||||
class DrillerNetSessionStream
|
||||
: public AZ::Debug::DrillerOutputStream
|
||||
, AZ::SystemTickBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(DrillerNetSessionStream, AZ::OSAllocator, 0);
|
||||
|
||||
DrillerNetSessionStream(AZ::u64 sessionId);
|
||||
~DrillerNetSessionStream();
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerOutputStream
|
||||
//---------------------------------------------------------------------
|
||||
virtual void WriteBinary(const void* data, unsigned int dataSize);
|
||||
virtual void OnEndOfFrame();
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// AZ::SystemTickBus
|
||||
//---------------------------------------------------------------------
|
||||
void OnSystemTick() override;
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static const size_t c_defaultUncompressedBufferSize = 256 * 1024;
|
||||
static const size_t c_defaultCompressedBufferSize = 32 * 1024;
|
||||
static const size_t c_bufferCount = 2;
|
||||
|
||||
AZ::Debug::DrillerSession* m_session;
|
||||
AZ::u64 m_sessionId;
|
||||
TargetInfo m_requestor;
|
||||
size_t m_activeBuffer;
|
||||
AZStd::vector<char, AZ::OSStdAllocator> m_uncompressedBuffer[c_bufferCount];
|
||||
AZStd::vector<char, AZ::OSStdAllocator> m_compressedBuffer[c_bufferCount];
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Compression
|
||||
AZ::ZLib m_compressor;
|
||||
AZStd::fixed_vector<char, c_defaultCompressedBufferSize> m_compressionBuffer;
|
||||
#endif
|
||||
|
||||
// String Pooling
|
||||
AZ::Debug::DrillerDefaultStringPool m_stringPool;
|
||||
|
||||
// TEMP Debug
|
||||
//AZ::IO::SystemFile m_file;
|
||||
};
|
||||
|
||||
DrillerNetSessionStream::DrillerNetSessionStream(AZ::u64 sessionId)
|
||||
: m_session(NULL)
|
||||
, m_sessionId(sessionId)
|
||||
, m_activeBuffer(0)
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
, m_compressor(&AZ::AllocatorInstance<AZ::OSAllocator>::Get())
|
||||
#endif
|
||||
{
|
||||
for (size_t i = 0; i < c_bufferCount; ++i)
|
||||
{
|
||||
m_uncompressedBuffer[i].reserve(c_defaultUncompressedBufferSize);
|
||||
m_compressedBuffer[i].reserve(c_defaultCompressedBufferSize);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Level 3 compression seems to give pretty good compression at decent speed.
|
||||
// Speed is paramount for us because initial driller packets can be huge and
|
||||
// we need to be able to compress the data within the driller report call
|
||||
// without blocking for too long.
|
||||
m_compressor.StartCompressor(3);
|
||||
#endif
|
||||
|
||||
SetStringPool(&m_stringPool);
|
||||
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
DrillerNetSessionStream::~DrillerNetSessionStream()
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
m_compressor.StopCompressor();
|
||||
#endif
|
||||
|
||||
// Debug
|
||||
//m_file.Close();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetSessionStream::WriteBinary(const void* data, unsigned int dataSize)
|
||||
{
|
||||
size_t activeBuffer = m_activeBuffer;
|
||||
|
||||
if (dataSize > 0)
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Only do the compression when the buffer is full so we don't run the compression all the time
|
||||
if (m_uncompressedBuffer[activeBuffer].size() + dataSize > c_defaultUncompressedBufferSize)
|
||||
{
|
||||
// compress
|
||||
unsigned int curDataSize = static_cast<unsigned int>(m_uncompressedBuffer[activeBuffer].size());
|
||||
unsigned int remaining = curDataSize;
|
||||
while (remaining > 0)
|
||||
{
|
||||
unsigned int processedBytes = curDataSize - remaining;
|
||||
unsigned int compressedBytes = m_compressor.Compress(m_uncompressedBuffer[activeBuffer].data() + processedBytes, remaining, m_compressionBuffer.data(), static_cast<unsigned int>(c_defaultCompressedBufferSize));
|
||||
if (compressedBytes > 0)
|
||||
{
|
||||
m_compressedBuffer[activeBuffer].insert(m_compressedBuffer[activeBuffer].end(), m_compressionBuffer.data(), m_compressionBuffer.data() + compressedBytes);
|
||||
}
|
||||
}
|
||||
m_uncompressedBuffer[activeBuffer].clear();
|
||||
}
|
||||
|
||||
m_uncompressedBuffer[activeBuffer].insert(m_uncompressedBuffer[activeBuffer].end(), reinterpret_cast<const char*>(data), reinterpret_cast<const char*>(data) + dataSize);
|
||||
#else
|
||||
// Since we are not compressing, transfer the input directly into our compressed buffer
|
||||
m_compressedBuffer[activeBuffer].insert(m_compressedBuffer[activeBuffer].end(), reinterpret_cast<const char*>(data), reinterpret_cast<const char*>(data) + dataSize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetSessionStream::OnEndOfFrame()
|
||||
{
|
||||
size_t activeBuffer = m_activeBuffer;
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
// Write whatever data has not yet been compressed and flush the compressor
|
||||
unsigned int curDataSize = static_cast<unsigned int>(m_uncompressedBuffer[activeBuffer].size());
|
||||
unsigned int remaining = curDataSize;
|
||||
unsigned int compressedBytes = 0;
|
||||
do
|
||||
{
|
||||
unsigned int processedBytes = curDataSize - remaining;
|
||||
compressedBytes = m_compressor.Compress(m_uncompressedBuffer[activeBuffer].data() + processedBytes, remaining, m_compressionBuffer.data(), static_cast<unsigned int>(c_defaultCompressedBufferSize), AZ::ZLib::FT_SYNC_FLUSH);
|
||||
if (compressedBytes > 0)
|
||||
{
|
||||
m_compressedBuffer[activeBuffer].insert(m_compressedBuffer[activeBuffer].end(), m_compressionBuffer.data(), m_compressionBuffer.data() + compressedBytes);
|
||||
}
|
||||
} while (compressedBytes > 0 || remaining > 0);
|
||||
#endif
|
||||
|
||||
m_activeBuffer = (activeBuffer + 1) % 2; // switch buffers
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
void DrillerNetSessionStream::OnSystemTick()
|
||||
{
|
||||
// The buffer index we want to send is the one we wrote to in the previous frame.
|
||||
size_t bufferIndex = (m_activeBuffer + 1) % 2;
|
||||
|
||||
if (m_compressedBuffer[bufferIndex].empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TmMsg msg(m_sessionId);
|
||||
|
||||
msg.AddCustomBlob(m_compressedBuffer[bufferIndex].data(), m_compressedBuffer[bufferIndex].size());
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_requestor, msg);
|
||||
|
||||
|
||||
// Debug
|
||||
//if (!m_file.IsOpen())
|
||||
//{
|
||||
// AZStd::string filename = AZStd::string::format("localdrill_%llu", m_sessionId);
|
||||
// m_file.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE);
|
||||
//}
|
||||
//m_file.Write(msg.GetCustomBlob(), msg.GetCustomBlobSize());
|
||||
|
||||
// Reset buffers
|
||||
m_uncompressedBuffer[bufferIndex].clear();
|
||||
m_compressedBuffer[bufferIndex].clear();
|
||||
|
||||
// Buffers may grow during exceptional circumstances. Re-shrink them to their default sizes
|
||||
// so we don't keep holding on to the memory.
|
||||
m_uncompressedBuffer[bufferIndex].reserve(c_defaultUncompressedBufferSize);
|
||||
m_compressedBuffer[bufferIndex].reserve(c_defaultCompressedBufferSize);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerNetworkAgent
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Init()
|
||||
{
|
||||
m_cbDrillerEnumRequest = TmMsgCallback(AZStd::bind(&DrillerNetworkAgentComponent::OnRequestDrillerEnum, this, AZStd::placeholders::_1));
|
||||
m_cbDrillerStartRequest = TmMsgCallback(AZStd::bind(&DrillerNetworkAgentComponent::OnRequestDrillerStart, this, AZStd::placeholders::_1));
|
||||
m_cbDrillerStopRequest = TmMsgCallback(AZStd::bind(&DrillerNetworkAgentComponent::OnRequestDrillerStop, this, AZStd::placeholders::_1));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Activate()
|
||||
{
|
||||
m_cbDrillerEnumRequest.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestDrillerEnum);
|
||||
m_cbDrillerStartRequest.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStartSession);
|
||||
m_cbDrillerStopRequest.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStopSession);
|
||||
TargetManagerClient::Bus::Handler::BusConnect();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Deactivate()
|
||||
{
|
||||
TargetManagerClient::Bus::Handler::BusDisconnect();
|
||||
m_cbDrillerEnumRequest.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestDrillerEnum);
|
||||
m_cbDrillerStartRequest.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStartSession);
|
||||
m_cbDrillerStopRequest.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_RequestStopSession);
|
||||
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop(m_activeSessions[i]->m_session);
|
||||
}
|
||||
delete m_activeSessions[i];
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("DrillerNetworkAgentService", 0xcd2ab821));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("DrillerNetworkAgentService", 0xcd2ab821));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<DrillerNetworkAgentComponent, AZ::Component>()
|
||||
->Version(1)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<DrillerNetworkAgentComponent>(
|
||||
"Driller Network Agent", "Runs on the machine being drilled and communicates with tools")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
;
|
||||
}
|
||||
|
||||
ReflectNetDrillerClasses(context);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::TargetLeftNetwork(TargetInfo info)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
for (AZStd::vector<DrillerNetSessionStream*>::iterator it = m_activeSessions.begin(); it != m_activeSessions.end(); )
|
||||
{
|
||||
if ((*it)->m_requestor.GetNetworkId() == info.GetNetworkId())
|
||||
{
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop((*it)->m_session);
|
||||
}
|
||||
delete *it;
|
||||
it = m_activeSessions.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::OnRequestDrillerEnum(TmMsgPtr msg)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (!mgr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TargetInfo sendTo;
|
||||
EBUS_EVENT_RESULT(sendTo, TargetManager::Bus, GetTargetInfo, msg->GetSenderTargetId());
|
||||
NetDrillerEnumeration drillerEnum;
|
||||
for (int i = 0; i < mgr->GetNumDrillers(); ++i)
|
||||
{
|
||||
AZ::Debug::Driller* driller = mgr->GetDriller(i);
|
||||
AZ_Assert(driller, "DrillerManager returned a NULL driller. This is not legal!");
|
||||
drillerEnum.m_enumeration.push_back();
|
||||
drillerEnum.m_enumeration.back().m_id = driller->GetId();
|
||||
drillerEnum.m_enumeration.back().m_groupName = driller->GroupName();
|
||||
drillerEnum.m_enumeration.back().m_name = driller->GetName();
|
||||
drillerEnum.m_enumeration.back().m_description = driller->GetDescription();
|
||||
}
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, sendTo, drillerEnum);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::OnRequestDrillerStart(TmMsgPtr msg)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (!mgr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NetDrillerStartSessionRequest* request = azdynamic_cast<NetDrillerStartSessionRequest*>(msg.get());
|
||||
AZ_Assert(request, "Not a NetDrillerStartSessionRequest msg!");
|
||||
AZ::Debug::DrillerManager::DrillerListType drillers;
|
||||
for (size_t i = 0; i < request->m_drillerIds.size(); ++i)
|
||||
{
|
||||
AZ::Debug::DrillerManager::DrillerInfo di;
|
||||
di.id = request->m_drillerIds[i];
|
||||
drillers.push_back(di);
|
||||
}
|
||||
DrillerNetSessionStream* session = aznew DrillerNetSessionStream(request->m_sessionId);
|
||||
EBUS_EVENT_RESULT(session->m_requestor, TargetManager::Bus, GetTargetInfo, msg->GetSenderTargetId());
|
||||
m_activeSessions.push_back(session);
|
||||
session->m_session = mgr->Start(*session, drillers);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkAgentComponent::OnRequestDrillerStop(TmMsgPtr msg)
|
||||
{
|
||||
NetDrillerStopSessionRequest* request = azdynamic_cast<NetDrillerStopSessionRequest*>(msg.get());
|
||||
for (AZStd::vector<DrillerNetSessionStream*>::iterator it = m_activeSessions.begin(); it != m_activeSessions.end(); ++it)
|
||||
{
|
||||
if ((*it)->m_sessionId == request->m_sessionId)
|
||||
{
|
||||
AZ::Debug::DrillerManager* mgr = NULL;
|
||||
EBUS_EVENT_RESULT(mgr, AZ::ComponentApplicationBus, GetDrillerManager);
|
||||
if (mgr)
|
||||
{
|
||||
mgr->Stop((*it)->m_session);
|
||||
}
|
||||
delete *it;
|
||||
m_activeSessions.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// DrillerRemoteConsole
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Init()
|
||||
{
|
||||
m_cbDrillerEnum = TmMsgCallback(AZStd::bind(&DrillerNetworkConsoleComponent::OnReceivedDrillerEnum, this, AZStd::placeholders::_1));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Activate()
|
||||
{
|
||||
m_cbDrillerEnum.BusConnect(NetworkDrillerSyncMsgId::NetDrillMsg_DrillerEnum);
|
||||
DrillerNetworkConsoleCommandBus::Handler::BusConnect();
|
||||
TargetManagerClient::Bus::Handler::BusConnect();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Deactivate()
|
||||
{
|
||||
TargetManagerClient::Bus::Handler::BusDisconnect();
|
||||
DrillerNetworkConsoleCommandBus::Handler::BusDisconnect();
|
||||
m_cbDrillerEnum.BusDisconnect(NetworkDrillerSyncMsgId::NetDrillMsg_DrillerEnum);
|
||||
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, NetDrillerStopSessionRequest(static_cast<AZ::u64>(reinterpret_cast<size_t>(m_activeSessions[i]))));
|
||||
m_activeSessions[i]->OnDrillerConnectionLost();
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("DrillerNetworkConsoleService", 0x2286125d));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("DrillerNetworkConsoleService", 0x2286125d));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<DrillerNetworkConsoleComponent, AZ::Component>()
|
||||
->Version(1)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<DrillerNetworkConsoleComponent>(
|
||||
"Driller Network Console", "Runs on the tool machine and is responsible for communications with the DrillerNetworkAgent")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
|
||||
;
|
||||
}
|
||||
|
||||
ReflectNetDrillerClasses(context);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::EnumerateAvailableDrillers()
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, TmMsg(NetworkDrillerSyncMsgId::NetDrillMsg_RequestDrillerEnum));
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::StartRemoteDrillerSession(const DrillerListType& drillers, DrillerRemoteSession* handler)
|
||||
{
|
||||
NetDrillerStartSessionRequest request;
|
||||
request.m_drillerIds = drillers;
|
||||
request.m_sessionId = static_cast<AZ::u64>(reinterpret_cast<size_t>(handler));
|
||||
m_activeSessions.push_back(handler);
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, request);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::StopRemoteDrillerSession(AZ::u64 sessionId)
|
||||
{
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
if (sessionId == static_cast<AZ::u64>(reinterpret_cast<size_t>(m_activeSessions[i])))
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, NetDrillerStopSessionRequest(sessionId));
|
||||
m_activeSessions[i] = m_activeSessions.back();
|
||||
m_activeSessions.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::DesiredTargetConnected(bool connected)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
EBUS_EVENT_RESULT(m_curTarget, TargetManager::Bus, GetDesiredTarget);
|
||||
EBUS_EVENT(DrillerNetworkConsoleCommandBus, EnumerateAvailableDrillers);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
m_activeSessions[i]->OnDrillerConnectionLost();
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
EBUS_EVENT(DrillerNetworkConsoleEventBus, OnReceivedDrillerEnumeration, DrillerInfoListType());
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::DesiredTargetChanged(AZ::u32 newTargetID, AZ::u32 oldTargetID)
|
||||
{
|
||||
(void)oldTargetID;
|
||||
(void)newTargetID;
|
||||
EBUS_EVENT(DrillerNetworkConsoleEventBus, OnReceivedDrillerEnumeration, DrillerInfoListType());
|
||||
for (size_t i = 0; i < m_activeSessions.size(); ++i)
|
||||
{
|
||||
EBUS_EVENT(TargetManager::Bus, SendTmMessage, m_curTarget, NetDrillerStopSessionRequest(static_cast<AZ::u64>(reinterpret_cast<size_t>(m_activeSessions[i]))));
|
||||
m_activeSessions[i]->OnDrillerConnectionLost();
|
||||
}
|
||||
m_activeSessions.clear();
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
void DrillerNetworkConsoleComponent::OnReceivedDrillerEnum(TmMsgPtr msg)
|
||||
{
|
||||
NetDrillerEnumeration* drillerEnum = azdynamic_cast<NetDrillerEnumeration*>(msg.get());
|
||||
AZ_Assert(drillerEnum, "No NetDrillerEnumeration message!");
|
||||
|
||||
EBUS_EVENT(DrillerNetworkConsoleEventBus, OnReceivedDrillerEnumeration, drillerEnum->m_enumeration);
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// ReflectNetDrillerClasses
|
||||
//---------------------------------------------------------------------
|
||||
void ReflectNetDrillerClasses(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
// Assume no one else will register our classes.
|
||||
if (serialize->FindClassData(DrillerInfo::RTTI_Type()) == nullptr)
|
||||
{
|
||||
serialize->Class<DrillerInfo>()
|
||||
->Field("Id", &DrillerInfo::m_id)
|
||||
->Field("GroupName", &DrillerInfo::m_groupName)
|
||||
->Field("Name", &DrillerInfo::m_name)
|
||||
->Field("Description", &DrillerInfo::m_description);
|
||||
serialize->Class<NetDrillerStartSessionRequest, TmMsg>()
|
||||
->Field("DrillerIds", &NetDrillerStartSessionRequest::m_drillerIds)
|
||||
->Field("SessionId", &NetDrillerStartSessionRequest::m_sessionId);
|
||||
serialize->Class<NetDrillerStopSessionRequest, TmMsg>()
|
||||
->Field("SessionId", &NetDrillerStopSessionRequest::m_sessionId);
|
||||
serialize->Class<NetDrillerEnumeration, TmMsg>()
|
||||
->Field("Enumeration", &NetDrillerEnumeration::m_enumeration);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------
|
||||
} // namespace AzFramework
|
||||
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AZFRAMEWORK_REMOTE_DRILLER_INTERFACE_H
|
||||
#define AZFRAMEWORK_REMOTE_DRILLER_INTERFACE_H
|
||||
|
||||
#include <AzCore/Driller/Driller.h>
|
||||
#include <AzCore/Compression/Compression.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/Driller/DrillerConsoleAPI.h>
|
||||
#include <AzFramework/TargetManagement/TargetManagementAPI.h>
|
||||
|
||||
//#define ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
struct ClassDataReflection;
|
||||
}
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
/**
|
||||
* Represents a remote driller session on the tool machine.
|
||||
* It is responsible for receiving and processing remote driller data.
|
||||
* Driller clients should derive from this class and implement the virtual interfaces.
|
||||
*/
|
||||
class DrillerRemoteSession
|
||||
: public TmMsgBus::Handler
|
||||
{
|
||||
public:
|
||||
DrillerRemoteSession();
|
||||
~DrillerRemoteSession();
|
||||
|
||||
// Called when new driller data arrives
|
||||
virtual void ProcessIncomingDrillerData(const char* streamIdentifier, const void* data, size_t dataSize) = 0;
|
||||
// Called when the connection to the driller is lost. The session should be deleted in response to this message
|
||||
virtual void OnDrillerConnectionLost() = 0;
|
||||
|
||||
// Start drilling the selected drillers as part of this session
|
||||
void StartDrilling(const DrillerListType& drillers, const char* captureFile);
|
||||
// Stop this drill session
|
||||
void StopDrilling();
|
||||
|
||||
// Replay a previously captured driller session from file
|
||||
void LoadCaptureData(const char* fileName);
|
||||
|
||||
protected:
|
||||
//---------------------------------------------------------------------
|
||||
// TmMsgBus
|
||||
//---------------------------------------------------------------------
|
||||
virtual void OnReceivedMsg(TmMsgPtr msg);
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void Decompress(const void* compressedBuffer, size_t compressedBufferSize);
|
||||
|
||||
static const AZ::u32 c_decompressionBufferSize = 128 * 1024;
|
||||
|
||||
AZStd::vector<char> m_uncompressedMsgBuffer;
|
||||
#ifdef ENABLE_COMPRESSION_FOR_REMOTE_DRILLER
|
||||
AZ::ZLib m_decompressor;
|
||||
char m_decompressionBuffer[c_decompressionBufferSize];
|
||||
#endif
|
||||
AZ::IO::SystemFile m_captureFile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Driller clients interested in receiving notification events from the
|
||||
* network console should implement this interface.
|
||||
*/
|
||||
class DrillerNetworkConsoleEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerNetworkConsoleEvents() {}
|
||||
|
||||
// A list of available drillers has been received from the target machine.
|
||||
virtual void OnReceivedDrillerEnumeration(const DrillerInfoListType& availableDrillers) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerNetworkConsoleEvents> DrillerNetworkConsoleEventBus;
|
||||
|
||||
/**
|
||||
* The network driller console implements this interface.
|
||||
* Commands can be sent to the network console through this interface.
|
||||
*/
|
||||
class DrillerNetworkConsoleCommands
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
typedef AZ::OSStdAllocator AllocatorType;
|
||||
|
||||
// there's only one driller console instance allowed
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual ~DrillerNetworkConsoleCommands() {}
|
||||
|
||||
// Request an enumeration of available drillers from the target machine
|
||||
virtual void EnumerateAvailableDrillers() = 0;
|
||||
// Start a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StartRemoteDrillerSession(const DrillerListType& drillers, DrillerRemoteSession* handler) = 0;
|
||||
// Stop a drilling session. This function is normally called internally by DrillerRemoteSession
|
||||
virtual void StopRemoteDrillerSession(AZ::u64 sessionId) = 0;
|
||||
};
|
||||
typedef AZ::EBus<DrillerNetworkConsoleCommands> DrillerNetworkConsoleCommandBus;
|
||||
|
||||
class DrillerNetSessionStream;
|
||||
|
||||
/**
|
||||
* Runs on the machine being drilled and is responsible for communications
|
||||
* with the DrillerNetworkConsole running on the tool side as well as
|
||||
* creating DrillerNetSessionStreams for each driller session being started.
|
||||
*/
|
||||
class DrillerNetworkAgentComponent
|
||||
: public AZ::Component
|
||||
, public TargetManagerClient::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(DrillerNetworkAgentComponent, "{B587A74D-6190-4149-91CB-0EA69936BD59}")
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
virtual void Init();
|
||||
virtual void Activate();
|
||||
virtual void Deactivate();
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TargetManagerClient
|
||||
virtual void TargetLeftNetwork(TargetInfo info);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TmMsg handlers
|
||||
virtual void OnRequestDrillerEnum(TmMsgPtr msg);
|
||||
virtual void OnRequestDrillerStart(TmMsgPtr msg);
|
||||
virtual void OnRequestDrillerStop(TmMsgPtr msg);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TmMsgCallback m_cbDrillerEnumRequest;
|
||||
TmMsgCallback m_cbDrillerStartRequest;
|
||||
TmMsgCallback m_cbDrillerStopRequest;
|
||||
|
||||
AZStd::vector<DrillerNetSessionStream*> m_activeSessions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs on the tool machine and is responsible for communications with the
|
||||
* DrillerNetworkAgent.
|
||||
*/
|
||||
class DrillerNetworkConsoleComponent
|
||||
: public AZ::Component
|
||||
, public DrillerNetworkConsoleCommandBus::Handler
|
||||
, public TargetManagerClient::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(DrillerNetworkConsoleComponent, "{78ACADA4-F2C7-4320-8E97-59DD8B9BE33A}")
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
virtual void Init();
|
||||
virtual void Activate();
|
||||
virtual void Deactivate();
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DrillerNetworkConsoleCommandBus
|
||||
virtual void EnumerateAvailableDrillers();
|
||||
virtual void StartRemoteDrillerSession(const DrillerListType& drillers, DrillerRemoteSession* handler);
|
||||
virtual void StopRemoteDrillerSession(AZ::u64 sessionId);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TargetManagerClient
|
||||
virtual void DesiredTargetConnected(bool connected);
|
||||
virtual void DesiredTargetChanged(AZ::u32 newTargetID, AZ::u32 oldTargetID);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// TmMsg handlers
|
||||
virtual void OnReceivedDrillerEnum(TmMsgPtr msg);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef AZStd::vector<DrillerRemoteSession*> ActiveSessionListType;
|
||||
ActiveSessionListType m_activeSessions;
|
||||
TargetInfo m_curTarget;
|
||||
TmMsgCallback m_cbDrillerEnum;
|
||||
};
|
||||
|
||||
void ReflectNetDrillerClasses(AZ::ReflectContext* context);
|
||||
} // namespace AzFramework
|
||||
|
||||
#endif // AZFRAMEWORK_REMOTE_DRILLER_INTERFACE_H
|
||||
#pragma once
|
||||
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
|
||||
#define SUBSYSTEM_DEFINES \
|
||||
X(PROFILE_ANY, "Any") \
|
||||
X(PROFILE_RENDERER, "Renderer") \
|
||||
X(PROFILE_3DENGINE, "3DEngine") \
|
||||
X(PROFILE_PARTICLE, "Particle") \
|
||||
X(PROFILE_AI, "AI") \
|
||||
X(PROFILE_ANIMATION, "Animation") \
|
||||
X(PROFILE_MOVIE, "Movie") \
|
||||
X(PROFILE_ENTITY, "Entity") \
|
||||
X(PROFILE_UI, "UI") \
|
||||
X(PROFILE_NETWORK, "Network") \
|
||||
X(PROFILE_PHYSICS, "Physics") \
|
||||
X(PROFILE_SCRIPT, "Script") \
|
||||
X(PROFILE_SCRIPT_CFUNC, "Script C Functions") \
|
||||
X(PROFILE_AUDIO, "Audio") \
|
||||
X(PROFILE_EDITOR, "Editor") \
|
||||
X(PROFILE_SYSTEM, "System") \
|
||||
X(PROFILE_ACTION, "Action") \
|
||||
X(PROFILE_GAME, "Game") \
|
||||
X(PROFILE_INPUT, "Input") \
|
||||
X(PROFILE_SYNC, "Sync") \
|
||||
X(PROFILE_NETWORK_TRAFFIC, "Network Traffic") \
|
||||
X(PROFILE_DEVICE, "Device")
|
||||
|
||||
#define X(Subsystem, SubsystemName) Subsystem,
|
||||
enum EProfiledSubsystem
|
||||
{
|
||||
SUBSYSTEM_DEFINES
|
||||
PROFILE_LAST_SUBSYSTEM
|
||||
};
|
||||
#undef X
|
||||
|
||||
#include <AzCore/Debug/EventTrace.h>
|
||||
|
||||
|
||||
|
||||
#define FUNCTION_PROFILER_LEGACYONLY(pISystem, subsystem)
|
||||
|
||||
#define FUNCTION_PROFILER(pISystem, subsystem)
|
||||
|
||||
#define FUNCTION_PROFILER_FAST(pISystem, subsystem, bProfileEnabled)
|
||||
|
||||
#define FUNCTION_PROFILER_ALWAYS(pISystem, subsystem)
|
||||
|
||||
#define FRAME_PROFILER_LEGACYONLY(szProfilerName, pISystem, subsystem)
|
||||
|
||||
#define FRAME_PROFILER(szProfilerName, pISystem, subsystem)
|
||||
|
||||
#define FRAME_PROFILER_FAST(szProfilerName, pISystem, subsystem, bProfileEnabled)
|
||||
|
||||
#define FUNCTION_PROFILER_SYS(subsystem)
|
||||
|
||||
#define STALL_PROFILER(cause)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue