Files
GoakeFlax/Source/Game/MyScript.cpp
2026-01-05 15:02:44 +02:00

949 lines
34 KiB
C++

#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<typename... TArgs>
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<double>(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<double>(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<double>(freq)) * 1000);
if (elapsedMs < minTime)
continue;
if (context.results.Count() > 20)
{
double avg = (double)totaccum / context.results.Count();
//avg = (avg * (1.0 / static_cast<double>(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<double>(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<double>(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<double>(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<double>(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<double>(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<uint64> results(TIMES);
auto CyclesToSeconds = 1.0 / static_cast<double>(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<int> simpleArray; for (int i=0; i<10; i++) simpleArray.Add(i);
Array<Actor*> actorArray; for (int i=0; i<10; i++) actorArray.Add(actor);
TestStruct testStruct; testStruct.Object = actor; testStruct.SceneRef = sceneRef;
Array<TestStruct> complexArray; for (int i=0; i<10; i++) complexArray.Add(testStruct);
StringStruct stringStruct;
Array<StringStruct> 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<FontAsset>(fontAssetGuid);
NetworkChannelType networkChannelType = NetworkChannelType::Reliable;
OnlineLeaderboardSortModes onlineLeaderboardSortModes = OnlineLeaderboardSortModes::Ascending;
OnlineLeaderboardValueFormats onlineLeaderboardValueFormats = OnlineLeaderboardValueFormats::Numeric;
AssetReference<FontAsset> fontAssetRef(fontAsset);
ModelLOD* lod = nullptr;
Array<int32> ints(&integer, 1);
Array<bool> booleans(&boolean, 1);
Array<Actor*> actors(&actor, 1);
Array<String> strings(&shortString, 1);
Array<StringAnsi> ansiStrings(&shortStringAnsi, 1);
Array<Float3> float3s(&f3, 1);
Array<ModelLOD*> 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<Guid>(&fontAssetGuid, 1), Array<AssetReference<FontAsset>>(&fontAssetRef, 1));
COVERAGE_CALL_ARGS2(CoverageTest3, lod, lods);
//COVERAGE_CALL_ARGS2(CoverageTest4, bytes, bytesOut);
COVERAGE_CALL_ARGS6(CoverageNamespaces1, networkChannelType, Array<NetworkChannelType>(&networkChannelType, 1), onlineLeaderboardSortModes, Array<OnlineLeaderboardSortModes>(&onlineLeaderboardSortModes, 1), onlineLeaderboardValueFormats, Array<OnlineLeaderboardValueFormats>(&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<double>(freq)) * 1000);
while (elapsedMs > 2000)
{
elapsedMs = ((Platform::GetTimeCycles() - startt) * (1.0 / static_cast<double>(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<int>(1, MCore::TypeCache::Int32);
params[1] = MUtils::Box<float>(2, MCore::TypeCache::Single);
params[2] = MUtils::Box<char>('3', MCore::TypeCache::SByte);
params[3] = MUtils::Box<double>(4, MCore::TypeCache::Double);
params[4] = MUtils::Box<long>(5, MCore::TypeCache::Int64);
BENCHMARK_THUNK_CALL_ARGS5();
#if NEW_VERSION
auto __param0_handle = *(MGCHandle*)&params[0];
MCore::GCHandle::Free(__param0_handle);
auto __param1_handle = *(MGCHandle*)&params[1];
MCore::GCHandle::Free(__param1_handle);
auto __param2_handle = *(MGCHandle*)&params[2];
MCore::GCHandle::Free(__param2_handle);
auto __param3_handle = *(MGCHandle*)&params[3];
MCore::GCHandle::Free(__param3_handle);
auto __param4_handle = *(MGCHandle*)&params[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<int32>(1, MCore::TypeCache::Int32);
params[1] = MUtils::Box<float>(2, MCore::TypeCache::Single);
params[2] = MUtils::Box<char>('3', MCore::TypeCache::SByte);
params[3] = MUtils::Box<double>(4, MCore::TypeCache::Double);
params[4] = MUtils::Box<int64>(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<double>(freq)) * 1000000000 / chunkTimes), (elapsed2 * (1.0 / static_cast<double>(freq)) * 1000), times * chunkTimes));
};*/
#if NEW_VERSION
auto __param0_handle = *(MGCHandle*)&params[0];
MCore::GCHandle::Free(__param0_handle);
auto __param1_handle = *(MGCHandle*)&params[1];
MCore::GCHandle::Free(__param1_handle);
auto __param2_handle = *(MGCHandle*)&params[2];
MCore::GCHandle::Free(__param2_handle);
auto __param3_handle = *(MGCHandle*)&params[3];
MCore::GCHandle::Free(__param3_handle);
auto __param4_handle = *(MGCHandle*)&params[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<StringAnsi>(shortStringAnsi, MCore::TypeCache::String);
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<StringAnsi>((MObject*)params[0]);
#endif
BENCHMARK_THUNK_END();
}
//else
// LOG(Info, " - InvokeThunkOnly: skipped");
if (invokeTests)
{
BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamAnsi,
MUtils::Box<StringAnsi>(shortStringAnsi, MCore::TypeCache::String));
#if NEW_VERSION
MUtils::FreeManaged<StringAnsi>((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<String>(shortString, MCore::TypeCache::String);
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<String>((MObject*)params[0]);
#endif
BENCHMARK_THUNK_END();
}
//else
// LOG(Info, " - InvokeThunkOnly: skipped");
if (invokeTests)
{
BENCHMARK_INVOKE_ARGS1(TIMES2, StringParam,
MUtils::Box<String>(shortString, MCore::TypeCache::String));
#if NEW_VERSION
MUtils::FreeManaged<String>((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<String>(shortString, MCore::TypeCache::String);
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<String>((MObject*)params[0]);
#endif
BENCHMARK_THUNK_END();
}
//else
// LOG(Info, " - InvokeThunkOnly: skipped");
if (invokeTests)
{
BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamRef,
MUtils::Box<String>(shortString, MCore::TypeCache::String));
#if NEW_VERSION
MUtils::FreeManaged<String>((MObject*)params[0]);
#endif
}
}
#endif
if (otherTests)
{
LOG_TEST(StringParamRefConst);
if (callTests)
{
BenchmarkCall<const String&>(benchmarkContext, &MyScript2::StringParamRefConst, shortString);
}
if (thunkTests)
{
BENCHMARK_THUNK_BEGIN_ARGS1(TIMES2, StringParamRefConst);
params[0] = MUtils::Box<String>(shortString, MCore::TypeCache::String);
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<String>((MObject*)params[0]);
#endif
BENCHMARK_THUNK_END();
}
//else
// LOG(Info, " - InvokeThunkOnly: skipped");
if (invokeTests)
{
BENCHMARK_INVOKE_ARGS1(TIMES2, StringParamRefConst,
MUtils::Box<String>(shortString, MCore::TypeCache::String));
#if NEW_VERSION
MUtils::FreeManaged<String>((MObject*)params[0]);
#endif
}
}
if (asRefTests)
{
LOG_TEST(StringParamAsRef);
if (callTests)
{
String str = shortString;
BenchmarkCall<String&>(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<String>(str, MCore::TypeCache::String);
auto __param_str = __param_orig_str;
params[0] = &__param_str;
#else
auto __param_str = MUtils::Box<String>(str, MCore::TypeCache::String);
params[0] = &__param_str;
#endif
BENCHMARK_THUNK_CALL_ARGS1_REF({ params[0] = &__param_str; });
str = MUtils::Unbox<String>(*(MObject**)params[0]);
ASSERT(str == shortString);
#if NEW_VERSION
MUtils::FreeManaged<String>((MObject*)__param_str);
if (__param_orig_str != __param_str)
MUtils::FreeManaged<String>((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<String>(shortString, MCore::TypeCache::String),
MUtils::FreeManaged<String>);
#else
BENCHMARK_INVOKE_ARGS1_REF(TIMES3, StringParamAsRef,
MUtils::Box<String>(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, BehaviorUpdateContext::TypeInitializer.GetClass());
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<BehaviorUpdateContext>((MObject*)params[0]);
#endif
BENCHMARK_THUNK_END();
}
//else
// LOG(Info, " - InvokeThunkOnly: skipped");
if (invokeTests)
{
//auto param1 = MUtils::Box<BehaviorUpdateContext>(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<double>(freq)) * 1000000000 / chunkTimes), (elapsed2 * (1.0 / static_cast<double>(freq)) * 1000), times * chunkTimes));
};*/
BENCHMARK_INVOKE_ARGS1(TIMES2, ComplexParam, &behaviorUpdateContext);
#if NEW_VERSION
//MUtils::FreeManaged<BehaviorUpdateContext>((MObject*)params[0]);
#endif
}
}
if (otherTests)
{
LOG_TEST(Complex2Param);
if (callTests)
{
BenchmarkCall<RenderContext&>(benchmarkContext, &MyScript2::Complex2Param, renderContext);
}
if (thunkTests)
{
BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, Complex2Param);
params[0] = MUtils::Box<RenderContext>(renderContext, RenderContext::TypeInitializer.GetClass());
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<RenderContext>((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<RenderContext>((MObject*)params[0]);
#endif
}
}
if (otherTests)
{
LOG_TEST(Complex2ParamConst);
if (callTests)
{
BenchmarkCall<const RenderContext&>(benchmarkContext, &MyScript2::Complex2ParamConst, renderContext);
}
if (thunkTests)
{
BENCHMARK_THUNK_BEGIN_ARGS1(TIMES3, Complex2ParamConst);
params[0] = MUtils::Box<RenderContext>(renderContext, RenderContext::TypeInitializer.GetClass());
BENCHMARK_THUNK_CALL_ARGS1();
#if NEW_VERSION
MUtils::FreeManaged<RenderContext>((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<RenderContext>((MObject*)params[0]);
#endif
}
}
if (asRefTests)
{
LOG_TEST(Complex2ParamAsRef);
if (callTests)
{
RenderContext context = renderContext;
BenchmarkCall<RenderContext&>(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<RenderContext>(context, RenderContext::TypeInitializer.GetClass());
auto __param_context = __param_orig_context;
params[0] = &__param_context;
#else
auto __param_context = MUtils::Box<RenderContext>(context, RenderContext::TypeInitializer.GetClass());
params[0] = &__param_context;
#endif
BENCHMARK_THUNK_CALL_ARGS1_REF({ if (__param_orig_context != __param_context) MUtils::FreeManaged<RenderContext>((MObject*)__param_orig_context); params[0] = &__param_context; });
context = MUtils::Unbox<RenderContext>(*(MObject**)params[0]);
ASSERT(context.Buffers == renderContext.Buffers);
ASSERT(context.Task == renderContext.Task);
#if NEW_VERSION
context = MUtils::Unbox<RenderContext>(*(MObject**)params[0]);
MUtils::FreeManaged<RenderContext>((MObject*)__param_context);
if (__param_orig_context != __param_context)
MUtils::FreeManaged<RenderContext>((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<int>((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<int>((MArray*)params[0]);
#endif
}
}
if (arrayTests && asRefTests)
{
LOG_TEST(SimpleArrayParamAsRef);
if (callTests)
{
Array<int> arr = simpleArray;
BenchmarkCall<Array<int32>&>(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<Array<int>>(*(MObject**)params[0]);
ASSERT(arr.Count() == simpleArray.Count());
for (int i=0; i<arr.Count(); i++) ASSERT(arr[i] == simpleArray[i]);
#if NEW_VERSION
MUtils::FreeManagedArray<int>(__param_arr); //fgfgh3
if (__param_orig_arr != __param_arr)
MUtils::FreeManagedArray<int>(__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<Actor*>((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<Actor*>((MArray*)params[0]);
#endif
}
}
if (otherTests)
{
LOG_TEST(StringFieldStructParam);
if (callTests)
{
BenchmarkCall<StringStruct&>(benchmarkContext, &MyScript2::StringFieldStructParam, stringStruct);
}
}
if (otherTests && asRefTests)
{
LOG_TEST(StringFieldStructParamAsRef);
if (callTests)
{
StringStruct ss = stringStruct;
BenchmarkCall<StringStruct&>(benchmarkContext, &MyScript2::StringFieldStructParamAsRef, ss);
}
}
if (arrayTests)
{
LOG_TEST(StringFieldStructArrayParam);
if (callTests)
{
BenchmarkCall<Array<StringStruct>&>(benchmarkContext, &MyScript2::StringFieldStructArrayParam, stringStructArray);
}
}
if (arrayTests && asRefTests)
{
LOG_TEST(StringFieldStructArrayParamAsRef);
if (callTests)
{
Array<StringStruct> arr = stringStructArray;
BenchmarkCall<Array<StringStruct>&>(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<TestStruct>((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<TestStruct>((MArray*)params[0]);
#endif
}
}
if (arrayTests && asRefTests)
{
LOG_TEST(ComplexArrayParamAsRef);
if (callTests)
{
Array<TestStruct> arr = complexArray;
BenchmarkCall<Array<TestStruct>&>(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<Array<TestStruct>>(*(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<TestStruct>(__param_arr);
if (__param_orig_arr != __param_arr)
MUtils::FreeManagedArray<TestStruct>(__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()
{
}