#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 0 #define TRACK_GCHANDLE_ALLOCS 1 #if NEW_VERSION #define TRACK_GCHANDLE_ALLOCS 1 #endif #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; } double t95(int n) { return 1.96 + 2.4 / (n - 1.0); } template void MyScript::BenchmarkCall(BenchmarkContext& context, void(MyScript2::* fun)(TArgs...), TArgs... args) { long totalTimes = 0; auto chunkTimes = CHUNK_TIMES; const auto cycleTimes = 1 * LONGER; const double minTime = 200; const double maxMaxTime = 5000; double maxTime = maxMaxTime; const auto freq = Platform::GetClockFrequency(); context.results.Clear(); uint64 bestResult = UINT64_MAX; { auto start0 = Platform::GetTimeCycles(); for (int i = 0; i < 10; ++i) (*context.scriptTwo.*fun)(args...); auto end0 = Platform::GetTimeCycles(); auto elapsed0 = end0 - start0; auto elapsed0ns = (elapsed0 * (1.0 / static_cast(freq)) * 1000000000); if (elapsed0 > 100000) chunkTimes = CHUNK_TIMES / 50; else if (elapsed0 > 80000) chunkTimes = CHUNK_TIMES / 40; else if (elapsed0 > 60000) chunkTimes = CHUNK_TIMES / 30; else if (elapsed0 > 30000) chunkTimes = CHUNK_TIMES / 20; else if (elapsed0 > 20000) chunkTimes = CHUNK_TIMES / 10; else if (elapsed0 > 10000) chunkTimes = CHUNK_TIMES / 5; else if (elapsed0 > 5000) chunkTimes = CHUNK_TIMES / 2; /*if (chunkTimes != CHUNK_TIMES) LOG(Info, " - chunk times adjusted to {} (elapsed {})", chunkTimes, elapsed0); else LOG(Info, " - elapsed {}", elapsed0);*/ } auto start1 = Platform::GetTimeCycles(); uint64 totaccum = 0; while (true) { uint64 previousBest = bestResult; uint64 currentBest = UINT64_MAX; auto start2 = Platform::GetTimeCycles(); for (int i = 0; i < cycleTimes; ++i) { auto start = Platform::GetTimeCycles(); for (int j = 0; j < chunkTimes; ++j) (*context.scriptTwo.*fun)(args...); auto end = Platform::GetTimeCycles(); auto elapsed = end - start; if (elapsed < currentBest) currentBest = elapsed; context.results.Add(elapsed); totaccum += elapsed; } auto end2 = Platform::GetTimeCycles(); auto elapsed2 = end2 - start2; auto elapsed2Ms = (elapsed2 * (1.0 / static_cast(freq)) * 1000); //Sorting::MergeSort(context.results); totalTimes += cycleTimes * chunkTimes; if (currentBest < bestResult) bestResult = currentBest; auto elapsed1 = Platform::GetTimeCycles() - start1; auto elapsedMs = (elapsed1 * (1.0 / static_cast(freq)) * 1000); if (elapsedMs < minTime) continue; if (context.results.Count() > 20) { double avg = (double)totaccum / context.results.Count(); //avg = (avg * (1.0 / static_cast(freq)) * 1000000000); double stdev = 0; { auto n = context.results.Count(); double s = 0.0; for (int i = 0; i < n; ++i) { //double d = (context.results[i] * (1.0 / static_cast(freq)) * 1000000000); double d = (double)context.results[i]; d = d - avg; s += d * d; } stdev = sqrt(s / (n - 1)); } double ci = t95(context.results.Count()) * stdev / sqrt((double)context.results.Count()); double rel = (ci / avg) * 100; if (rel < 1.0) break; } if (elapsedMs >= maxTime) break; } double avg = (double)totaccum / context.results.Count(); avg = (avg * (1.0 / static_cast(freq)) * 1000000000); double stdev = 0; { auto n = context.results.Count(); double s = 0.0; for (int i = 0; i < n; ++i) { double d = (context.results[i] * (1.0 / static_cast(freq)) * 1000000000); d = d - avg; s += d * d; } stdev = sqrt(s / (n - 1)); } double ci = t95(context.results.Count()) * stdev / sqrt((double)context.results.Count()); double rel = (ci / avg) * 100; ci /= chunkTimes; stdev /= chunkTimes; avg /= chunkTimes; auto elapsed1 = Platform::GetTimeCycles() - start1; const auto bestResultNs = (bestResult * (1.0 / static_cast(freq)) * 1000000000 / chunkTimes); LOG(Info, " - VirtualCall: {:.1f}ns +-{:.1f}ns, std:{:.1f}ns, {:.1f}%, avg:{:.1f} ({:.0f}ms/{})", bestResultNs, ci, stdev, rel, avg, (elapsed1 * (1.0 / static_cast(freq)) * 1000), totalTimes, ci); } void MyScript::OnStart() { LOG(Info, "C++ OnStart"); MyScript2* scriptTwo = (MyScript2*)GetActor()->GetScript(1); if (scriptTwo == nullptr) return; bool callTests = true; bool thunkTests = false; bool invokeTests = false; // requires manual type conversion 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); StringStruct stringStruct; Array stringStructArray; for (int i = 0; i < 10; i++) stringStructArray.Add(stringStruct); BenchmarkContext benchmarkContext; benchmarkContext.scriptTwo = scriptTwo; benchmarkContext.results = results; // 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); BytesContainer bytes; bytes.Append((byte*)&f3, sizeof(Float3)); BytesContainer bytesOut; 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_ARGS2(CoverageTest4, bytes, bytesOut); COVERAGE_CALL_ARGS6(CoverageNamespaces1, networkChannelType, Array(&networkChannelType, 1), onlineLeaderboardSortModes, Array(&onlineLeaderboardSortModes, 1), onlineLeaderboardValueFormats, Array(&onlineLeaderboardValueFormats, 1)); scriptTwo->ManagedCoverageTests(); } // Warmup busy-loop { const auto freq = Platform::GetClockFrequency(); auto startt = Platform::GetTimeCycles(); auto elapsedMs = ((Platform::GetTimeCycles() - startt) * (1.0 / static_cast(freq)) * 1000); while (elapsedMs > 2000) { elapsedMs = ((Platform::GetTimeCycles() - startt) * (1.0 / static_cast(freq)) * 1000); } } #if TRACK_GCHANDLE_ALLOCS int64 allocationsBefore, deallocationsBefore; scriptTwo->GetStats(allocationsBefore, deallocationsBefore); #endif if (otherTests) { LOG_TEST(SimpleCall); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::SimpleCall); } if (thunkTests) { BENCHMARK_THUNK_BEGIN_ARGS0(TIMES2, SimpleCall); BENCHMARK_THUNK_CALL_ARGS0(); BENCHMARK_THUNK_END(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS0(TIMES2, SimpleCall); } } if (otherTests) { LOG_TEST(SimpleParams); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::SimpleParams, (int32)1, (float)2, '3', (double)4, (int64)5); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { //#if NEW_VERSION /*BENCHMARK_INVOKE_ARGS5(TIMES3, SimpleParams, (int32)1, (float)2, (char)'3', (double)4, (int64)5);*/ //#else int32 a = 1; float b = 2; char c = 3; double d = 4; int64 e = 5; BENCHMARK_INVOKE_ARGS5(TIMES3, SimpleParams, (void*)&a, (void*)&b, (void*)&c, (void*)&d, (void*)&e); //#endif /*void* params[5]; { auto klass = MyScript2::GetStaticClass(); auto method = klass->GetMethod("SimpleParams", 5); auto instance = scriptTwo->GetManagedInstance(); MObject* exception = nullptr; const auto times = (100 * 3); const auto chunkTimes = 100; const auto freq = Platform::GetClockFrequency(); 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); results.Clear(); auto start2 = Platform::GetTimeCycles(); for (int i = 0; i < times; ++i) { auto start = Platform::GetTimeCycles(); for (int j = 0; j < chunkTimes; ++j) method->Invoke(instance, params, &exception); auto end = Platform::GetTimeCycles(); auto elapsed = end - start; results.Add(elapsed); } auto end2 = Platform::GetTimeCycles(); auto elapsed2 = end2 - start2; Sorting::MergeSort(results); const auto resultsIndex = 0; Log::Logger::Write(LogType::Info, ::String::Format(L" - InvokeOnly: {:.1f}ns ({:.0f}ms total {} times)", (results[resultsIndex] * (1.0 / static_cast(freq)) * 1000000000 / chunkTimes), (elapsed2 * (1.0 / static_cast(freq)) * 1000), times * chunkTimes)); };*/ #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 (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::StringParamAnsi, shortStringAnsi); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); 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 (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::StringParam, shortString); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, StringParam, MUtils::Box(shortString, MCore::TypeCache::String)); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } #if false if (otherTests) { LOG_TEST(StringParamRef); if (callTests) { BenchmarkCall(&MyScript2::StringParamRef, shortString); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamRef, MUtils::Box(shortString, MCore::TypeCache::String)); #if NEW_VERSION MUtils::FreeManaged((MObject*)params[0]); #endif } } #endif if (otherTests) { LOG_TEST(StringParamRefConst); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::StringParamRefConst, shortString); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); 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 (callTests) { String str = shortString; BenchmarkCall(benchmarkContext, &MyScript2::StringParamAsRef, str); } if (thunkTests) { 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();*/ } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { String str = shortString; #if NEW_VERSION BENCHMARK_INVOKE_ARGS1_REF(TIMES3, StringParamAsRef, MUtils::Box(shortString, MCore::TypeCache::String), MUtils::FreeManaged); #else BENCHMARK_INVOKE_ARGS1_REF(TIMES3, StringParamAsRef, MUtils::Box(shortString, MCore::TypeCache::String), {}); #endif } } if (otherTests) { LOG_TEST(ActorParam); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::ActorParam, actor); } if (thunkTests) { BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, ActorParam); params[0] = ScriptingObject::ToManaged((ScriptingObject*)actor); BENCHMARK_THUNK_CALL_ARGS1(); BENCHMARK_THUNK_END(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES2, ActorParam, ScriptingObject::ToManaged((ScriptingObject*)actor)); } } if (otherTests) { LOG_TEST(ComplexParam); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::ComplexParam, behaviorUpdateContext); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { //auto param1 = MUtils::Box(behaviorUpdateContext, BehaviorUpdateContext::TypeInitializer.GetClass()); /*void* params[1]; { auto klass = MyScript2::GetStaticClass(); auto method = klass->GetMethod("ComplexParam", 1); auto instance = scriptTwo->GetManagedInstance(); MObject* exception = nullptr; const auto times = (1000 * 3); const auto chunkTimes = 100; const auto freq = Platform::GetClockFrequency(); params[0] = &behaviorUpdateContext; results.Clear(); auto start2 = Platform::GetTimeCycles(); for (int i = 0; i < times; ++i) { auto start = Platform::GetTimeCycles(); for (int j = 0; j < chunkTimes; ++j) method->Invoke(instance, params, &exception); auto end = Platform::GetTimeCycles(); auto elapsed = end - start; results.Add(elapsed); } auto end2 = Platform::GetTimeCycles(); auto elapsed2 = end2 - start2; Sorting::MergeSort(results); const auto resultsIndex = 0; Log::Logger::Write(LogType::Info, ::String::Format(L" - InvokeOnly: {:.1f}ns ({:.0f}ms total {} times)", (results[resultsIndex] * (1.0 / static_cast(freq)) * 1000000000 / chunkTimes), (elapsed2 * (1.0 / static_cast(freq)) * 1000), times * chunkTimes)); };*/ BENCHMARK_INVOKE_ARGS1(TIMES2, ComplexParam, &behaviorUpdateContext); #if NEW_VERSION //MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(Complex2Param); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::Complex2Param, renderContext); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, Complex2Param, &renderContext); #if NEW_VERSION //MUtils::FreeManaged((MObject*)params[0]); #endif } } if (otherTests) { LOG_TEST(Complex2ParamConst); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::Complex2ParamConst, renderContext); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, Complex2ParamConst, &renderContext); #if NEW_VERSION //MUtils::FreeManaged((MObject*)params[0]); #endif } } if (asRefTests) { LOG_TEST(Complex2ParamAsRef); if (callTests) { RenderContext context = renderContext; BenchmarkCall(benchmarkContext, &MyScript2::Complex2ParamAsRef, context); } if (thunkTests) { 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();*/ } //else // LOG(Info, " - InvokeThunkOnly: skipped"); } if (arrayTests) { LOG_TEST(SimpleArrayParam); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::SimpleArrayParam, simpleArray); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); 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 (callTests) { Array arr = simpleArray; BenchmarkCall&>(benchmarkContext, &MyScript2::SimpleArrayParamAsRef, simpleArray); } if (thunkTests) { 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();*/ } //else // LOG(Info, " - InvokeThunkOnly: skipped"); } if (arrayTests) { LOG_TEST(ActorArrayParam); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::ActorArrayParam, actorArray); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); if (invokeTests) { BENCHMARK_INVOKE_ARGS1(TIMES3, ActorArrayParam, MUtils::ToArray(actorArray, Actor::TypeInitializer.GetClass())); #if NEW_VERSION MUtils::FreeManagedArray((MArray*)params[0]); #endif } } if (otherTests) { LOG_TEST(StringFieldStructParam); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::StringFieldStructParam, stringStruct); } } if (otherTests && asRefTests) { LOG_TEST(StringFieldStructParamAsRef); if (callTests) { StringStruct ss = stringStruct; BenchmarkCall(benchmarkContext, &MyScript2::StringFieldStructParamAsRef, ss); } } if (arrayTests) { LOG_TEST(StringFieldStructArrayParam); if (callTests) { BenchmarkCall&>(benchmarkContext, &MyScript2::StringFieldStructArrayParam, stringStructArray); } } if (arrayTests && asRefTests) { LOG_TEST(StringFieldStructArrayParamAsRef); if (callTests) { Array arr = stringStructArray; BenchmarkCall&>(benchmarkContext, &MyScript2::StringFieldStructArrayParamAsRef, arr); } } if (arrayTests) { LOG_TEST(ComplexArrayParam); if (callTests) { BenchmarkCall(benchmarkContext, &MyScript2::ComplexArrayParam, complexArray); } if (thunkTests) { 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(); } //else // LOG(Info, " - InvokeThunkOnly: skipped"); 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 (callTests) { Array arr = complexArray; BenchmarkCall&>(benchmarkContext, &MyScript2::ComplexArrayParamAsRef, arr); } if (thunkTests) { 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();*/ } //else // LOG(Info, " - InvokeThunkOnly: skipped"); } #if TRACK_GCHANDLE_ALLOCS 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() { }