Files
o3de/Gems/EMotionFX/Code/Tests/AnimGraphRefCountTests.cpp
T
lumberyard-employee-dm 098005afbc AZStd::basic_string improvements (#6438)
* AZStd::basic_string improvements

The AZStd::basic_string class has a better implementation of the Short
String Optimization, which increases the amount of characters that can
be stored in a `basic_string<char>` from 15 characters to 22
characters(not-including null-terminating characters). For a
`basic_string<wchar_t>` on Windows the amount of characters that can be
stored increases from 7 to 10. Using `basic_string<wchar_t>` on Unix
platforms SSO character amount from 3 to 4 characters.

An additional benefit is that the size of the AZStd::basic_string class
has been reduced from 40 bytes to 32 bytes when using the
AZStd::allocator.
When using a stateless allocator with no non static data members such as
AZStd::stateless_allocator, the size of the AZStd::basic_string is 24
bytes.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Corrected comments and updated type alias to usings for AZStd::basic_string

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Added Benchmarks for the basic_string and basic_fixed_string class

The benchmarks currently measure the speed of the `assign` overloads.
A benchmark has also been added to compare the speed swapping two
`basic_string` instances by 3 memcpy vs 3 pointer swap operations

Speed up string operation when in the iterator overload cases of the
`assign`, `append`, `insert` and `replace` function.
The code was always performing the logic to copy over a string that is
overlapping, without actually checking if the string was overlapping in
the first place.

Added an `az_builtin_is_constant_evaluated` macro that allows use of the
C++20 `std::is_constant_evaluated` feature to determine if an operation
is being performed at compile time vs run time.

That macro is being used to speed up the char_trait operations at run
time, by using the faster standard library functions.
For example char_traits::move now uses "memmove" at runtime, instead of
a for loop.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Simplified string logic in AWSMetricsServiceApiTest.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
2022-01-10 10:03:31 -06:00

188 lines
6.9 KiB
C++

/*
* 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/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <EMotionFX/Source/EventHandler.h>
#include <EMotionFX/Source/AnimGraph.h>
#include <EMotionFX/Source/AnimGraphInstance.h>
#include <EMotionFX/Source/AnimGraphBindPoseNode.h>
#include <EMotionFX/Source/AnimGraphEntryNode.h>
#include <EMotionFX/Source/AnimGraphExitNode.h>
#include <EMotionFX/Source/AnimGraphStateMachine.h>
#include <Tests/AnimGraphFixture.h>
namespace EMotionFX
{
class AnimGraphRefCountFixture
: public AnimGraphFixture
{
public:
void Run()
{
Simulate(/*simulationTime*/10.0f, /*expectedFps*/60.0f, /*fpsVariance*/0.0f,
/*preCallback*/[this](AnimGraphInstance*)
{
this->m_animGraphInstance->SetAutoReleaseRefDatas(false);
this->m_animGraphInstance->SetAutoReleasePoses(false);
},
/*postCallback*/[](AnimGraphInstance*){},
/*preUpdateCallback*/[](AnimGraphInstance*, float, float, int){},
/*postUpdateCallback*/[this](AnimGraphInstance*, float, float, int)
{
// Check if data and pose ref counts are back to 0 for all nodes.
const size_t numNodes = this->m_animGraph->GetNumNodes();
for (size_t i = 0; i < numNodes; ++i)
{
const AnimGraphNode* node = this->m_animGraph->GetNode(i);
// Check the ref counts only for unique datas that got allocated. Lazy-init of the unique datas does not allocate unique datas for unused or unvisted nodes.
AnimGraphNodeData* nodeData = static_cast<AnimGraphNodeData*>(this->m_animGraphInstance->GetUniqueObjectData(node->GetObjectIndex()));
if (nodeData)
{
EXPECT_EQ(0, nodeData->GetRefDataRefCount()) << "Expected the data ref count to be 0 post update.";
EXPECT_EQ(0, nodeData->GetPoseRefCount()) << "Expected the pose ref count to be 0 post update.";
}
}
this->m_animGraphInstance->ReleaseRefDatas();
this->m_animGraphInstance->ReleasePoses();
});
}
};
///////////////////////////////////////////////////////////////////////////
struct AnimGraphRefCountData_SimpleChain
{
int m_numStates;
float m_blendTime;
float m_countDownTime;
};
class AnimGraphRefCountTest_SimpleChain
: public AnimGraphRefCountFixture
, public ::testing::WithParamInterface<AnimGraphRefCountData_SimpleChain>
{
public:
void ConstructGraph() override
{
const AnimGraphRefCountData_SimpleChain& param = GetParam();
AnimGraphFixture::ConstructGraph();
/*
+-------+ +---+ +---+ +---+
| Start |--->| A |--->| B |---> ... --->| N |
+-------+ +---+ +---+ +---+
*/
AnimGraphBindPoseNode* stateStart = aznew AnimGraphBindPoseNode();
m_rootStateMachine->AddChildNode(stateStart);
m_rootStateMachine->SetEntryState(stateStart);
const char startChar = 'A';
AnimGraphNode* prevState = stateStart;
for (int i = 0; i < param.m_numStates; ++i)
{
AnimGraphBindPoseNode* state = aznew AnimGraphBindPoseNode();
state->SetName(AZStd::string(1, static_cast<char>(startChar + i)).c_str());
m_rootStateMachine->AddChildNode(state);
AddTransitionWithTimeCondition(prevState, state, /*blendTime*/param.m_blendTime, /*countDownTime*/param.m_countDownTime);
prevState = state;
}
}
};
TEST_P(AnimGraphRefCountTest_SimpleChain, AnimGraphRefCountTest_SimpleChain)
{
Run();
}
std::vector<AnimGraphRefCountData_SimpleChain> animGraphRefCountTest_SimpleChainTestData
{
{
/*m_numStates*/3,
/*m_blendTime*/1.0,
/*m_countDownTime*/1.0
},
{
3,
0.0,
1.0
},
{
3,
0.0,
0.0
},
{
8,
0.5,
0.5
},
{
16,
0.2,
0.2
}
};
INSTANTIATE_TEST_CASE_P(AnimGraphRefCountTest_SimpleChain,
AnimGraphRefCountTest_SimpleChain,
::testing::ValuesIn(animGraphRefCountTest_SimpleChainTestData)
);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class AnimGraphRefCountTest_SimpleEntryExit
: public AnimGraphRefCountFixture
{
public:
void ConstructGraph() override
{
AnimGraphFixture::ConstructGraph();
AnimGraphBindPoseNode* stateStart = aznew AnimGraphBindPoseNode();
stateStart->SetName("Start");
m_rootStateMachine->AddChildNode(stateStart);
m_rootStateMachine->SetEntryState(stateStart);
AnimGraphStateMachine* stateMachine = aznew AnimGraphStateMachine();
stateMachine->SetName("Sub SM");
m_rootStateMachine->AddChildNode(stateMachine);
AddTransitionWithTimeCondition(stateStart, stateMachine, 1.0, 1.0);
{
AnimGraphEntryNode* subEntryNode = aznew AnimGraphEntryNode();
subEntryNode->SetName("Entry");
stateMachine->AddChildNode(subEntryNode);
stateMachine->SetEntryState(subEntryNode);
AnimGraphBindPoseNode* subBetweenNode = aznew AnimGraphBindPoseNode();
subBetweenNode->SetName("Sub In-between");
stateMachine->AddChildNode(subBetweenNode);
AddTransitionWithTimeCondition(subEntryNode, subBetweenNode, 0.0, 0.3);
AnimGraphExitNode* exitNode = aznew AnimGraphExitNode();
exitNode->SetName("Exit");
stateMachine->AddChildNode(exitNode);
AddTransitionWithTimeCondition(subBetweenNode, exitNode, 1.0, 1.0);
}
AnimGraphBindPoseNode* stateEnd = aznew AnimGraphBindPoseNode();
stateEnd->SetName("End");
m_rootStateMachine->AddChildNode(stateEnd);
AddTransitionWithTimeCondition(stateMachine, stateEnd, 1.0, 3.0);
}
};
TEST_F(AnimGraphRefCountTest_SimpleEntryExit, AnimGraphRefCountTest_SimpleEntryExit)
{
Run();
}
} // namespace EMotionFX