#include "MyScript.h" #include "Engine/Content/Content.h" #include "Engine/Level/Actor.h" #include "Engine/Core/Log.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Scripting/ManagedCLR/MUtils.h" #include "Engine/Scripting/ManagedCLR/MCore.h" #include "Engine/Scripting/ManagedCLR/MClass.h" #include "Engine/Scripting/ManagedCLR/MEvent.h" #include "Engine/Scripting/ManagedCLR/MMethod.h" #include "Engine/Level/Scene/Scene.h" #include "Engine/Core/Collections/Sorting.h" #include "Engine/Render2D/FontAsset.h" #define NEW_VERSION 1 #if BUILD_DEBUG #define LONGER 3 #define CHUNK_TIMES 100 #else #define LONGER 10//*10 #define CHUNK_TIMES 1000 #endif #define TIMES (10000*LONGER) #define TIMES2 (1000*LONGER) #define TIMES3 (100*LONGER) #define TIMES4 (10*LONGER) #define TIMES5 (1*LONGER) #define TIMES_ONCE 1 MyScript2::MyScript2(const SpawnParams& params) : Script(params) { // _tickUpdate = true; } MyScript::MyScript(const SpawnParams& params) : Script(params) { // _tickUpdate = true; } void MyScript::OnStart() { LOG(Info, "C++ OnStart"); MyScript2* scriptTwo = (MyScript2*)GetActor()->GetScript(1); if (scriptTwo == nullptr) return; bool thunkTests = false; bool invokeTests = true; bool coverageTests = false; bool otherTests = true; bool arrayTests = true; bool asRefTests = true; Array results(TIMES); auto CyclesToSeconds = 1.0 / static_cast(Platform::GetClockFrequency()); LOG(Info, "CyclesToSeconds: {}, freq: {}", CyclesToSeconds, Platform::GetClockFrequency()); String shortString = TEXT("Testing string parameter marshalling"); StringAnsi shortStringAnsi = "Testing string parameter marshalling"; Actor* actor = GetActor(); SceneReference sceneRef; sceneRef.ID = actor->GetScene()->GetID(); BehaviorUpdateContext behaviorUpdateContext = {}; RenderContext renderContext = MainRenderTask::Instance; renderContext.List = RenderList::GetFromPool(); Array simpleArray; for (int i=0; i<10; i++) simpleArray.Add(i); Array actorArray; for (int i=0; i<10; i++) actorArray.Add(actor); TestStruct testStruct; testStruct.Object = actor; testStruct.SceneRef = sceneRef; Array complexArray; for (int i=0; i<10; i++) complexArray.Add(testStruct); // Coverage if (coverageTests) { int32 integer = 1; bool boolean = true; Float3 f3(1.0f, 2.0f, 3.0f); Guid fontAssetGuid; Guid::Parse("ab96b25a49461d9f4f819484cf5c8213", fontAssetGuid); FontAsset* fontAsset = Content::LoadAsync(fontAssetGuid); NetworkChannelType networkChannelType = NetworkChannelType::Reliable; OnlineLeaderboardSortModes onlineLeaderboardSortModes = OnlineLeaderboardSortModes::Ascending; OnlineLeaderboardValueFormats onlineLeaderboardValueFormats = OnlineLeaderboardValueFormats::Numeric; AssetReference fontAssetRef(fontAsset); ModelLOD* lod = nullptr; Array ints(&integer, 1); Array booleans(&boolean, 1); Array actors(&actor, 1); Array strings(&shortString, 1); Array ansiStrings(&shortStringAnsi, 1); Array float3s(&f3, 1); Array lods(&lod, 1); COVERAGE_CALL_ARGS6(CoverageTest1, integer, boolean, actor, shortString, shortStringAnsi, f3); COVERAGE_CALL_ARGS6(CoverageTest1Array, ints, booleans, actors, strings, ansiStrings, float3s); COVERAGE_CALL_ARGS5(CoverageTest1ByRef, integer, boolean/*, actor*/, shortString, shortStringAnsi, f3); COVERAGE_CALL_ARGS5(CoverageTest1ArrayByRef, ints, booleans/*, actors*/, strings, ansiStrings, float3s); COVERAGE_CALL_ARGS4(CoverageTest2, fontAssetGuid, fontAssetRef, Array(&fontAssetGuid, 1), Array>(&fontAssetRef, 1)); COVERAGE_CALL_ARGS2(CoverageTest3, lod, lods); COVERAGE_CALL_ARGS6(CoverageNamespaces1, networkChannelType, Array(&networkChannelType, 1), onlineLeaderboardSortModes, Array(&onlineLeaderboardSortModes, 1), onlineLeaderboardValueFormats, Array(&onlineLeaderboardValueFormats, 1)); scriptTwo->ManagedCoverageTests(); } #if NEW_VERSION int64 allocationsBefore, deallocationsBefore; scriptTwo->GetStats(allocationsBefore, deallocationsBefore); #endif if (otherTests) { LOG_TEST(SimpleCall); if (thunkTests) { BENCHMARK_CALL_ARGS0(TIMES2, SimpleCall); BENCHMARK_THUNK_BEGIN_ARGS0(TIMES2, SimpleCall); BENCHMARK_THUNK_CALL_ARGS0(); BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS0(TIMES2, SimpleCall); } } if (otherTests) { LOG_TEST(SimpleParams); if (thunkTests) { BENCHMARK_CALL_ARGS5(TIMES4, SimpleParams, 1, 2, '3', 4, 5); BENCHMARK_THUNK_BEGIN_ARGS5(TIMES3, SimpleParams); params[0] = MUtils::Box(1, MCore::TypeCache::Int32); params[1] = MUtils::Box(2, MCore::TypeCache::Single); params[2] = MUtils::Box('3', MCore::TypeCache::SByte); params[3] = MUtils::Box(4, MCore::TypeCache::Double); params[4] = MUtils::Box(5, MCore::TypeCache::Int64); BENCHMARK_THUNK_CALL_ARGS5(); #if NEW_VERSION auto __param0_handle = *(MGCHandle*)¶ms[0]; MCore::GCHandle::Free(__param0_handle); auto __param1_handle = *(MGCHandle*)¶ms[1]; MCore::GCHandle::Free(__param1_handle); auto __param2_handle = *(MGCHandle*)¶ms[2]; MCore::GCHandle::Free(__param2_handle); auto __param3_handle = *(MGCHandle*)¶ms[3]; MCore::GCHandle::Free(__param3_handle); auto __param4_handle = *(MGCHandle*)¶ms[4]; MCore::GCHandle::Free(__param4_handle); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS5(TIMES3, SimpleParams, MUtils::Box(1, MCore::TypeCache::Int32), MUtils::Box(2, MCore::TypeCache::Single), MUtils::Box('3', MCore::TypeCache::SByte), MUtils::Box(4, MCore::TypeCache::Double), MUtils::Box(5, MCore::TypeCache::Int64)); #if NEW_VERSION auto __param0_handle = *(MGCHandle*)¶ms[0]; MCore::GCHandle::Free(__param0_handle); auto __param1_handle = *(MGCHandle*)¶ms[1]; MCore::GCHandle::Free(__param1_handle); auto __param2_handle = *(MGCHandle*)¶ms[2]; MCore::GCHandle::Free(__param2_handle); auto __param3_handle = *(MGCHandle*)¶ms[3]; MCore::GCHandle::Free(__param3_handle); auto __param4_handle = *(MGCHandle*)¶ms[4]; MCore::GCHandle::Free(__param4_handle); #endif } } if (otherTests) { LOG_TEST(StringParamAnsi); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES3, StringParamAnsi, shortStringAnsi); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, StringParamAnsi); params[0] = MUtils::Box(shortStringAnsi, MCore::TypeCache::String); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamAnsi, MUtils::Box(shortStringAnsi, MCore::TypeCache::String)); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(StringParam); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES3, StringParam, shortString); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, StringParam); params[0] = MUtils::Box(shortString, MCore::TypeCache::String); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, StringParam, MUtils::Box(shortString, MCore::TypeCache::String)); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(StringParamRef); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES3, StringParamRef, shortString); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, StringParamRef); params[0] = MUtils::Box(shortString, MCore::TypeCache::String); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamRef, MUtils::Box(shortString, MCore::TypeCache::String)); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(StringParamRefConst); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES3, StringParamRefConst, shortString); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, StringParamRefConst); params[0] = MUtils::Box(shortString, MCore::TypeCache::String); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamRefConst, MUtils::Box(shortString, MCore::TypeCache::String)); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (asRefTests) { LOG_TEST(StringParamAsRef); if (thunkTests) { String str = shortString; BENCHMARK_CALL_ARGS1_REF(TIMES3, StringParamAsRef, str); LOG(Info, " - InvokeThunkOnly: not valid"); /* str = shortString; BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, StringParamAsRef); #if NEW_VERSION auto __param_orig_str = MUtils::Box(str, MCore::TypeCache::String); auto __param_str = __param_orig_str; params[0] = &__param_str; #else auto __param_str = MUtils::Box(str, MCore::TypeCache::String); params[0] = &__param_str; #endif BENCHMARK_THUNK_CALL_ARGS1_REF({ params[0] = &__param_str; }); str = MUtils::Unbox(*(MObject**)params[0]); ASSERT(str == shortString); #if NEW_VERSION MUtils::FreeManaged((MObject*)__param_str); if (__param_orig_str != __param_str) MUtils::FreeManaged((MObject*)__param_orig_str); #endif BENCHMARK_THUNK_END();*/ } if (invokeTests) { String str = shortString; BENCHMARK_INVOKE_ARGS1_REF(TIMES3, StringParamAsRef, MUtils::Box(str, MCore::TypeCache::String), MUtils::FreeManaged); } } if (otherTests) { LOG_TEST(ActorParam); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES2, ActorParam, actor); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, ActorParam); params[0] = ScriptingObject::ToManaged((ScriptingObject*)actor); BENCHMARK_THUNK_CALL_ARGS1(); BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, ActorParam, ScriptingObject::ToManaged((ScriptingObject*)actor)); } } if (otherTests) { LOG_TEST(ComplexParam); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES3, ComplexParam, behaviorUpdateContext); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, ComplexParam); params[0] = MUtils::Box(behaviorUpdateContext, BehaviorUpdateContext::TypeInitializer.GetClass()); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, ComplexParam, MUtils::Box(behaviorUpdateContext, BehaviorUpdateContext::TypeInitializer.GetClass())); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(Complex2Param); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES4, Complex2Param, renderContext); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, Complex2Param); params[0] = MUtils::Box(renderContext, RenderContext::TypeInitializer.GetClass()); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, Complex2Param, MUtils::Box(renderContext, RenderContext::TypeInitializer.GetClass())); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(Complex2ParamConst); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES4, Complex2ParamConst, renderContext); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, Complex2ParamConst); params[0] = MUtils::Box(renderContext, RenderContext::TypeInitializer.GetClass()); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, Complex2ParamConst, MUtils::Box(renderContext, RenderContext::TypeInitializer.GetClass())); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } if (asRefTests) { LOG_TEST(Complex2ParamAsRef); if (thunkTests) { RenderContext context = renderContext; BENCHMARK_CALL_ARGS1_REF(TIMES4, Complex2ParamAsRef, context); LOG(Info, " - InvokeThunkOnly: not valid"); /* context = renderContext; BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, Complex2ParamAsRef); #if NEW_VERSION auto __param_orig_context = MUtils::Box(context, RenderContext::TypeInitializer.GetClass()); auto __param_context = __param_orig_context; params[0] = &__param_context; #else auto __param_context = MUtils::Box(context, RenderContext::TypeInitializer.GetClass()); params[0] = &__param_context; #endif BENCHMARK_THUNK_CALL_ARGS1_REF({ if (__param_orig_context != __param_context) MUtils::FreeManaged((MObject*)__param_orig_context); params[0] = &__param_context; }); context = MUtils::Unbox(*(MObject**)params[0]); ASSERT(context.Buffers == renderContext.Buffers); ASSERT(context.Task == renderContext.Task); #if NEW_VERSION context = MUtils::Unbox(*(MObject**)params[0]); MUtils::FreeManaged((MObject*)__param_context); if (__param_orig_context != __param_context) MUtils::FreeManaged((MObject*)__param_orig_context); #endif BENCHMARK_THUNK_END();*/ } } if (arrayTests) { LOG_TEST(SimpleArrayParam); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES4, SimpleArrayParam, simpleArray); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, SimpleArrayParam); params[0] = MUtils::ToArray(simpleArray, MCore::TypeCache::Int32); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, SimpleArrayParam, MUtils::ToArray(simpleArray, MCore::TypeCache::Int32)); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif } } if (arrayTests && asRefTests) { LOG_TEST(SimpleArrayParamAsRef); if (thunkTests) { Array arr = simpleArray; BENCHMARK_CALL_ARGS1_REF(TIMES4, SimpleArrayParamAsRef, simpleArray); LOG(Info, " - InvokeThunkOnly: not valid"); /* arr = simpleArray; BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, SimpleArrayParamAsRef); #if NEW_VERSION auto __param_orig_arr = MUtils::ToArray(arr, MCore::TypeCache::Int32); auto __param_arr = __param_orig_arr; params[0] = &__param_arr; #else auto __param_arr = MUtils::ToArray(arr, MCore::TypeCache::Int32); params[0] = &__param_arr; #endif BENCHMARK_THUNK_CALL_ARGS1(); arr = MUtils::Unbox>(*(MObject**)params[0]); ASSERT(arr.Count() == simpleArray.Count()); for (int i=0; i(__param_arr); //fgfgh3 if (__param_orig_arr != __param_arr) MUtils::FreeManagedArray(__param_orig_arr); //fgfgh4 #endif BENCHMARK_THUNK_END();*/ } } if (arrayTests) { LOG_TEST(ActorArrayParam); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES4, ActorArrayParam, actorArray); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, ActorArrayParam); params[0] = MUtils::ToArray(actorArray, Actor::TypeInitializer.GetClass()); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, ActorArrayParam, MUtils::ToArray(actorArray, Actor::TypeInitializer.GetClass())); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif } } if (arrayTests) { LOG_TEST(ComplexArrayParam); if (thunkTests) { BENCHMARK_CALL_ARGS1(TIMES4, ComplexArrayParam, complexArray); BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, ComplexArrayParam); params[0] = MUtils::ToArray(complexArray, TestStruct::TypeInitializer.GetClass()); BENCHMARK_THUNK_CALL_ARGS1(); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif BENCHMARK_THUNK_END(); } if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, ComplexArrayParam, MUtils::ToArray(complexArray, TestStruct::TypeInitializer.GetClass())); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif } } if (arrayTests && asRefTests) { LOG_TEST(ComplexArrayParamAsRef); if (thunkTests) { Array arr = complexArray; BENCHMARK_CALL_ARGS1_REF(TIMES4, ComplexArrayParamAsRef, arr); LOG(Info, " - InvokeThunkOnly: not valid"); /* arr = complexArray; BENCHMARK_THUNK_BEGIN_ARGS1(TIMES4, ComplexArrayParamAsRef); #if NEW_VERSION auto __param_orig_arr = MUtils::ToArray(arr, TestStruct::TypeInitializer.GetClass()); auto __param_arr = __param_orig_arr; params[0] = &__param_arr; #else auto __param_arr = MUtils::ToArray(arr, TestStruct::TypeInitializer.GetClass()); params[0] = &__param_arr; #endif BENCHMARK_THUNK_CALL_ARGS1(); arr = MUtils::Unbox>(*(MObject**)params[0]); ASSERT(arr.Count() == complexArray.Count()); for (int i = 0; i < arr.Count(); i++) ASSERT(arr[i] == complexArray[i]); #if NEW_VERSION MUtils::FreeManagedArray(__param_arr); if (__param_orig_arr != __param_arr) MUtils::FreeManagedArray(__param_orig_arr); #endif BENCHMARK_THUNK_END();*/ } } #if NEW_VERSION int64 allocationsAfter, deallocationsAfter; scriptTwo->GetStats(allocationsAfter, deallocationsAfter); int64 allocationsDiff = allocationsAfter-allocationsBefore; int64 deallocationsDiff = deallocationsAfter-deallocationsBefore; int64 leftover = allocationsDiff - deallocationsDiff; LOG(Info, "Total ManagedHandle allocations: {}, deallocations: {}, leftover: {}", allocationsDiff, deallocationsDiff, leftover); #endif } void MyScript::OnEnable() { //LOG(Info, "C++ OnEnable"); } void MyScript::OnDisable() { LOG(Info, "running garbage collector"); MCore::GC::Collect(MCore::GC::MaxGeneration(), MGCCollectionMode::Aggressive, true, true); MCore::GC::WaitForPendingFinalizers(); } void MyScript::OnUpdate() { }