From 8c62f1120f4e5b8eae05399c85a82070e416d866 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 25 May 2025 17:39:20 +0200 Subject: [PATCH] Optimize dynamic memory allocations for managed runtime interop collections with a new Arena Allocation --- Source/Engine/Core/Collections/Array.h | 12 +++ Source/Engine/Core/Memory/Allocation.h | 34 ++++++-- Source/Engine/Core/Memory/ArenaAllocation.h | 79 +++++++++++++++++++ .../Engine/Core/Memory/SimpleHeapAllocation.h | 5 ++ Source/Engine/Scripting/BinaryModule.cpp | 4 +- Source/Engine/Scripting/ManagedCLR/MClass.h | 25 +++--- Source/Engine/Scripting/ManagedCLR/MEvent.h | 4 +- Source/Engine/Scripting/ManagedCLR/MField.h | 5 +- Source/Engine/Scripting/ManagedCLR/MMethod.h | 5 +- .../Engine/Scripting/ManagedCLR/MProperty.h | 5 +- Source/Engine/Scripting/Runtime/DotNet.cpp | 34 +++++--- Source/Engine/Scripting/Runtime/Mono.cpp | 10 +-- Source/Engine/Scripting/Runtime/None.cpp | 18 ++--- 13 files changed, 185 insertions(+), 55 deletions(-) diff --git a/Source/Engine/Core/Collections/Array.h b/Source/Engine/Core/Collections/Array.h index 5845d7f50..ab142961d 100644 --- a/Source/Engine/Core/Collections/Array.h +++ b/Source/Engine/Core/Collections/Array.h @@ -20,6 +20,7 @@ API_CLASS(InBuild) class Array public: using ItemType = T; using AllocationData = typename AllocationType::template Data; + using AllocationTag = typename AllocationType::Tag; private: int32 _count; @@ -36,6 +37,17 @@ public: { } + /// + /// Initializes an empty without reserving any space. + /// + /// The custom allocation tag. + Array(AllocationTag tag) + : _count(0) + , _capacity(0) + , _allocation(tag) + { + } + /// /// Initializes by reserving space. /// diff --git a/Source/Engine/Core/Memory/Allocation.h b/Source/Engine/Core/Memory/Allocation.h index 6da929d86..d6958d2c3 100644 --- a/Source/Engine/Core/Memory/Allocation.h +++ b/Source/Engine/Core/Memory/Allocation.h @@ -36,6 +36,17 @@ namespace AllocationUtils capacity++; return capacity; } + + inline int32 CalculateCapacityGrow(int32 capacity, int32 minCapacity) + { + if (capacity < minCapacity) + capacity = minCapacity; + if (capacity < 8) + capacity = 8; + else + capacity = RoundUpToPowerOf2(capacity); + return capacity; + } } /// @@ -46,6 +57,7 @@ class FixedAllocation { public: enum { HasSwap = false }; + typedef void* Tag; template class alignas(sizeof(void*)) Data @@ -58,6 +70,10 @@ public: { } + FORCE_INLINE Data(Tag tag) + { + } + FORCE_INLINE ~Data() { } @@ -106,6 +122,7 @@ class HeapAllocation { public: enum { HasSwap = true }; + typedef void* Tag; template class Data @@ -118,6 +135,10 @@ public: { } + FORCE_INLINE Data(Tag tag) + { + } + FORCE_INLINE ~Data() { Allocator::Free(_data); @@ -135,13 +156,7 @@ public: FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, const int32 minCapacity) const { - if (capacity < minCapacity) - capacity = minCapacity; - if (capacity < 8) - capacity = 8; - else - capacity = AllocationUtils::RoundUpToPowerOf2(capacity); - return capacity; + return AllocationUtils::CalculateCapacityGrow(capacity, minCapacity); } FORCE_INLINE void Allocate(const int32 capacity) @@ -184,6 +199,7 @@ class InlinedAllocation { public: enum { HasSwap = false }; + typedef void* Tag; template class alignas(sizeof(void*)) Data @@ -200,6 +216,10 @@ public: { } + FORCE_INLINE Data(Tag tag) + { + } + FORCE_INLINE ~Data() { } diff --git a/Source/Engine/Core/Memory/ArenaAllocation.h b/Source/Engine/Core/Memory/ArenaAllocation.h index 43004ab30..af8df2001 100644 --- a/Source/Engine/Core/Memory/ArenaAllocation.h +++ b/Source/Engine/Core/Memory/ArenaAllocation.h @@ -1,5 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. +#pragma once + #include "Allocation.h" /// @@ -63,3 +65,80 @@ public: collection.Clear(); } }; + +/// +/// The memory allocation policy that uses a part of shared page allocator. Allocations are performed in stack-manner, and free is no-op. +/// +class ArenaAllocation +{ +public: + enum { HasSwap = true }; + typedef ArenaAllocator* Tag; + + template + class Data + { + private: + T* _data = nullptr; + ArenaAllocator* _arena = nullptr; + + public: + FORCE_INLINE Data() + { + } + + FORCE_INLINE Data(Tag tag) + { + _arena = tag; + } + + FORCE_INLINE ~Data() + { + } + + FORCE_INLINE T* Get() + { + return _data; + } + + FORCE_INLINE const T* Get() const + { + return _data; + } + + FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, const int32 minCapacity) const + { + return AllocationUtils::CalculateCapacityGrow(capacity, minCapacity); + } + + FORCE_INLINE void Allocate(const int32 capacity) + { + ASSERT_LOW_LAYER(!_data && _arena); + _data = (T*)_arena->Allocate(capacity * sizeof(T), alignof(T)); + } + + FORCE_INLINE void Relocate(const int32 capacity, int32 oldCount, int32 newCount) + { + ASSERT_LOW_LAYER(_arena); + T* newData = capacity != 0 ? (T*)_arena->Allocate(capacity * sizeof(T), alignof(T)) : nullptr; + if (oldCount) + { + if (newCount > 0) + Memory::MoveItems(newData, _data, newCount); + Memory::DestructItems(_data, oldCount); + } + _data = newData; + } + + FORCE_INLINE void Free() + { + _data = nullptr; + } + + FORCE_INLINE void Swap(Data& other) + { + ::Swap(_data, other._data); + ::Swap(_arena, other._arena); + } + }; +}; diff --git a/Source/Engine/Core/Memory/SimpleHeapAllocation.h b/Source/Engine/Core/Memory/SimpleHeapAllocation.h index 4df5bb660..6afcffd64 100644 --- a/Source/Engine/Core/Memory/SimpleHeapAllocation.h +++ b/Source/Engine/Core/Memory/SimpleHeapAllocation.h @@ -11,6 +11,7 @@ class SimpleHeapAllocation { public: enum { HasSwap = true }; + typedef void* Tag; template class Data @@ -23,6 +24,10 @@ public: { } + FORCE_INLINE Data(Tag tag) + { + } + FORCE_INLINE ~Data() { if (_data) diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index 1a48a3846..da01a9f07 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -815,7 +815,7 @@ namespace { MMethod* FindMethod(MClass* mclass, const MMethod* referenceMethod) { - const Array& methods = mclass->GetMethods(); + const auto& methods = mclass->GetMethods(); for (int32 i = 0; i < methods.Count(); i++) { MMethod* method = methods[i]; @@ -1095,7 +1095,7 @@ void ManagedBinaryModule::InitType(MClass* mclass) // Initialize scripting interfaces implemented in C# int32 interfacesCount = 0; MClass* klass = mclass; - const Array& interfaceClasses = klass->GetInterfaces(); + const auto& interfaceClasses = klass->GetInterfaces(); for (const MClass* interfaceClass : interfaceClasses) { const ScriptingTypeHandle interfaceType = FindType(interfaceClass); diff --git a/Source/Engine/Scripting/ManagedCLR/MClass.h b/Source/Engine/Scripting/ManagedCLR/MClass.h index a74b4f7da..a89d75205 100644 --- a/Source/Engine/Scripting/ManagedCLR/MClass.h +++ b/Source/Engine/Scripting/ManagedCLR/MClass.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Memory/ArenaAllocation.h" #include "MTypes.h" /// @@ -25,12 +26,12 @@ private: #endif MAssembly* _assembly; - mutable Array _methods; - mutable Array _fields; - mutable Array _properties; - mutable Array _attributes; - mutable Array _events; - mutable Array _interfaces; + mutable Array _methods; + mutable Array _fields; + mutable Array _properties; + mutable Array _attributes; + mutable Array _events; + mutable Array _interfaces; MVisibility _visibility; @@ -248,7 +249,7 @@ public: /// /// Be aware this will not include the methods of any base classes. /// The list of methods. - const Array& GetMethods() const; + const Array& GetMethods() const; /// /// Returns an object referencing a field with the specified name. @@ -263,7 +264,7 @@ public: /// /// Be aware this will not include the fields of any base classes. /// The list of fields. - const Array& GetFields() const; + const Array& GetFields() const; /// /// Returns an object referencing a event with the specified name. @@ -276,7 +277,7 @@ public: /// Returns all events belonging to this class. /// /// The list of events. - const Array& GetEvents() const; + const Array& GetEvents() const; /// /// Returns an object referencing a property with the specified name. @@ -291,14 +292,14 @@ public: /// /// Be aware this will not include the properties of any base classes. /// The list of properties. - const Array& GetProperties() const; + const Array& GetProperties() const; /// /// Returns all interfaces implemented by this class (excluding interfaces from base classes). /// /// Be aware this will not include the interfaces of any base classes. /// The list of interfaces. - const Array& GetInterfaces() const; + const Array& GetInterfaces() const; public: /// @@ -332,5 +333,5 @@ public: /// Returns an instance of all attributes connected with given class. Returns null if the class doesn't have any attributes. /// /// The array of attribute objects. - const Array& GetAttributes() const; + const Array& GetAttributes() const; }; diff --git a/Source/Engine/Scripting/ManagedCLR/MEvent.h b/Source/Engine/Scripting/ManagedCLR/MEvent.h index 0aade183e..9d8551774 100644 --- a/Source/Engine/Scripting/ManagedCLR/MEvent.h +++ b/Source/Engine/Scripting/ManagedCLR/MEvent.h @@ -29,7 +29,7 @@ protected: mutable int32 _hasAddMonoMethod : 1; mutable int32 _hasRemoveMonoMethod : 1; - mutable Array _attributes; + mutable Array _attributes; public: #if USE_MONO @@ -121,5 +121,5 @@ public: /// Returns an instance of all attributes connected with given event. Returns null if the event doesn't have any attributes. /// /// The array of attribute objects. - const Array& GetAttributes() const; + const Array& GetAttributes() const; }; diff --git a/Source/Engine/Scripting/ManagedCLR/MField.h b/Source/Engine/Scripting/ManagedCLR/MField.h index ed73db711..66213d6ab 100644 --- a/Source/Engine/Scripting/ManagedCLR/MField.h +++ b/Source/Engine/Scripting/ManagedCLR/MField.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Memory/ArenaAllocation.h" #include "MTypes.h" /// @@ -32,7 +33,7 @@ protected: mutable int32 _hasCachedAttributes : 1; int32 _isStatic : 1; - mutable Array _attributes; + mutable Array _attributes; public: #if USE_MONO @@ -157,5 +158,5 @@ public: /// Returns an instance of all attributes connected with given field. Returns null if the field doesn't have any attributes. /// /// The array of attribute objects. - const Array& GetAttributes() const; + const Array& GetAttributes() const; }; diff --git a/Source/Engine/Scripting/ManagedCLR/MMethod.h b/Source/Engine/Scripting/ManagedCLR/MMethod.h index 8d24b533b..700fa9593 100644 --- a/Source/Engine/Scripting/ManagedCLR/MMethod.h +++ b/Source/Engine/Scripting/ManagedCLR/MMethod.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Memory/ArenaAllocation.h" #if COMPILE_WITH_PROFILER #include "Engine/Profiler/ProfilerSrcLoc.h" #endif @@ -42,7 +43,7 @@ protected: #endif int32 _isStatic : 1; - mutable Array _attributes; + mutable Array _attributes; public: #if USE_MONO @@ -197,5 +198,5 @@ public: /// Returns an instance of all attributes connected with given method. Returns null if the method doesn't have any attributes. /// /// The array of attribute objects. - const Array& GetAttributes() const; + const Array& GetAttributes() const; }; diff --git a/Source/Engine/Scripting/ManagedCLR/MProperty.h b/Source/Engine/Scripting/ManagedCLR/MProperty.h index 7e426b474..e48d98375 100644 --- a/Source/Engine/Scripting/ManagedCLR/MProperty.h +++ b/Source/Engine/Scripting/ManagedCLR/MProperty.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/Core/Collections/Array.h" +#include "Engine/Core/Memory/ArenaAllocation.h" #include "MTypes.h" /// @@ -31,7 +32,7 @@ protected: mutable int32 _hasSetMethod : 1; mutable int32 _hasGetMethod : 1; - mutable Array _attributes; + mutable Array _attributes; public: #if USE_MONO @@ -135,5 +136,5 @@ public: /// Returns an instance of all attributes connected with given property. Returns null if the property doesn't have any attributes. /// /// The array of attribute objects. - const Array& GetAttributes() const; + const Array& GetAttributes() const; }; diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index cd4da3f20..ce5f315f1 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -212,7 +212,7 @@ MClass* GetClass(MType* typeHandle); MClass* GetOrCreateClass(MType* typeHandle); MType* GetObjectType(MObject* obj); -void* GetCustomAttribute(const Array& attributes, const MClass* attributeClass) +void* GetCustomAttribute(const Array& attributes, const MClass* attributeClass) { for (MObject* attr : attributes) { @@ -223,7 +223,7 @@ void* GetCustomAttribute(const Array& attributes, const MClass* attrib return nullptr; } -void GetCustomAttributes(Array& result, void* handle, void* getAttributesFunc) +void GetCustomAttributes(Array& result, void* handle, void* getAttributesFunc) { MObject** attributes; int numAttributes; @@ -922,6 +922,12 @@ MClass::MClass(MAssembly* parentAssembly, void* handle, const char* name, const , _namespace(parentAssembly->AllocString(namespace_)) , _fullname(parentAssembly->AllocString(fullname)) , _assembly(parentAssembly) + , _methods(&parentAssembly->Memory) + , _fields(&parentAssembly->Memory) + , _properties(&parentAssembly->Memory) + , _attributes(&parentAssembly->Memory) + , _events(&parentAssembly->Memory) + , _interfaces(&parentAssembly->Memory) , _hasCachedProperties(false) , _hasCachedFields(false) , _hasCachedMethods(false) @@ -1050,7 +1056,7 @@ MMethod* MClass::GetMethod(const char* name, int32 numParams) const return nullptr; } -const Array& MClass::GetMethods() const +const Array& MClass::GetMethods() const { if (_hasCachedMethods) return _methods; @@ -1089,7 +1095,7 @@ MField* MClass::GetField(const char* name) const return nullptr; } -const Array& MClass::GetFields() const +const Array& MClass::GetFields() const { if (_hasCachedFields) return _fields; @@ -1116,7 +1122,7 @@ const Array& MClass::GetFields() const return _fields; } -const Array& MClass::GetEvents() const +const Array& MClass::GetEvents() const { if (_hasCachedEvents) return _events; @@ -1139,7 +1145,7 @@ MProperty* MClass::GetProperty(const char* name) const return nullptr; } -const Array& MClass::GetProperties() const +const Array& MClass::GetProperties() const { if (_hasCachedProperties) return _properties; @@ -1166,7 +1172,7 @@ const Array& MClass::GetProperties() const return _properties; } -const Array& MClass::GetInterfaces() const +const Array& MClass::GetInterfaces() const { if (_hasCachedInterfaces) return _interfaces; @@ -1206,7 +1212,7 @@ MObject* MClass::GetAttribute(const MClass* klass) const return (MObject*)GetCustomAttribute(GetAttributes(), klass); } -const Array& MClass::GetAttributes() const +const Array& MClass::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1239,6 +1245,7 @@ MEvent::MEvent(MClass* parentClass, void* handle, const char* name) , _hasCachedAttributes(false) , _hasAddMonoMethod(true) , _hasRemoveMonoMethod(true) + , _attributes(&parentClass->GetAssembly()->Memory) { } @@ -1267,7 +1274,7 @@ MObject* MEvent::GetAttribute(const MClass* klass) const return (MObject*)GetCustomAttribute(GetAttributes(), klass); } -const Array& MEvent::GetAttributes() const +const Array& MEvent::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1313,6 +1320,7 @@ MField::MField(MClass* parentClass, void* handle, const char* name, void* type, , _parentClass(parentClass) , _name(parentClass->GetAssembly()->AllocString(name)) , _hasCachedAttributes(false) + , _attributes(&parentClass->GetAssembly()->Memory) { switch (attributes & MFieldAttributes::FieldAccessMask) { @@ -1389,7 +1397,7 @@ MObject* MField::GetAttribute(const MClass* klass) const return (MObject*)GetCustomAttribute(GetAttributes(), klass); } -const Array& MField::GetAttributes() const +const Array& MField::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1410,6 +1418,7 @@ MMethod::MMethod(MClass* parentClass, StringAnsiView name, void* handle, int32 p , _name(name) , _hasCachedAttributes(false) , _hasCachedSignature(false) + , _attributes(&parentClass->GetAssembly()->Memory) { switch (attributes & MMethodAttributes::MemberAccessMask) { @@ -1555,7 +1564,7 @@ MObject* MMethod::GetAttribute(const MClass* klass) const return (MObject*)GetCustomAttribute(GetAttributes(), klass); } -const Array& MMethod::GetAttributes() const +const Array& MMethod::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1584,6 +1593,7 @@ MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void* , _name(parentClass->GetAssembly()->AllocString(name)) , _handle(handle) , _hasCachedAttributes(false) + , _attributes(&parentClass->GetAssembly()->Memory) { _hasGetMethod = getterHandle != nullptr; if (_hasGetMethod) @@ -1644,7 +1654,7 @@ MObject* MProperty::GetAttribute(const MClass* klass) const return (MObject*)GetCustomAttribute(GetAttributes(), klass); } -const Array& MProperty::GetAttributes() const +const Array& MProperty::GetAttributes() const { if (_hasCachedAttributes) return _attributes; diff --git a/Source/Engine/Scripting/Runtime/Mono.cpp b/Source/Engine/Scripting/Runtime/Mono.cpp index 317f4e798..86b800e97 100644 --- a/Source/Engine/Scripting/Runtime/Mono.cpp +++ b/Source/Engine/Scripting/Runtime/Mono.cpp @@ -1539,7 +1539,7 @@ MObject* MClass::GetAttribute(const MClass* klass) const return attrInfo ? mono_custom_attrs_get_attr(attrInfo, klass->GetNative()) : nullptr; } -const Array& MClass::GetAttributes() const +const Array& MClass::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1662,7 +1662,7 @@ MObject* MEvent::GetAttribute(const MClass* klass) const return foundAttr; } -const Array& MEvent::GetAttributes() const +const Array& MEvent::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1815,7 +1815,7 @@ MObject* MField::GetAttribute(const MClass* klass) const return foundAttr; } -const Array& MField::GetAttributes() const +const Array& MField::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -1988,7 +1988,7 @@ MObject* MMethod::GetAttribute(const MClass* klass) const return foundAttr; } -const Array& MMethod::GetAttributes() const +const Array& MMethod::GetAttributes() const { if (_hasCachedAttributes) return _attributes; @@ -2118,7 +2118,7 @@ MObject* MProperty::GetAttribute(const MClass* klass) const return foundAttr; } -const Array& MProperty::GetAttributes() const +const Array& MProperty::GetAttributes() const { if (_hasCachedAttributes) return _attributes; diff --git a/Source/Engine/Scripting/Runtime/None.cpp b/Source/Engine/Scripting/Runtime/None.cpp index a7c921cb0..580029eef 100644 --- a/Source/Engine/Scripting/Runtime/None.cpp +++ b/Source/Engine/Scripting/Runtime/None.cpp @@ -358,7 +358,7 @@ MMethod* MClass::GetMethod(const char* name, int32 numParams) const return nullptr; } -const Array& MClass::GetMethods() const +const Array& MClass::GetMethods() const { _hasCachedMethods = true; return _methods; @@ -369,13 +369,13 @@ MField* MClass::GetField(const char* name) const return nullptr; } -const Array& MClass::GetFields() const +const Array& MClass::GetFields() const { _hasCachedFields = true; return _fields; } -const Array& MClass::GetEvents() const +const Array& MClass::GetEvents() const { _hasCachedEvents = true; return _events; @@ -386,7 +386,7 @@ MProperty* MClass::GetProperty(const char* name) const return nullptr; } -const Array& MClass::GetProperties() const +const Array& MClass::GetProperties() const { _hasCachedProperties = true; return _properties; @@ -407,7 +407,7 @@ MObject* MClass::GetAttribute(const MClass* klass) const return nullptr; } -const Array& MClass::GetAttributes() const +const Array& MClass::GetAttributes() const { _hasCachedAttributes = true; return _attributes; @@ -449,7 +449,7 @@ MObject* MEvent::GetAttribute(const MClass* klass) const return nullptr; } -const Array& MEvent::GetAttributes() const +const Array& MEvent::GetAttributes() const { return _attributes; } @@ -501,7 +501,7 @@ MObject* MField::GetAttribute(const MClass* klass) const return nullptr; } -const Array& MField::GetAttributes() const +const Array& MField::GetAttributes() const { return _attributes; } @@ -556,7 +556,7 @@ MObject* MMethod::GetAttribute(const MClass* klass) const return nullptr; } -const Array& MMethod::GetAttributes() const +const Array& MMethod::GetAttributes() const { return _attributes; } @@ -603,7 +603,7 @@ MObject* MProperty::GetAttribute(const MClass* klass) const return nullptr; } -const Array& MProperty::GetAttributes() const +const Array& MProperty::GetAttributes() const { return _attributes; }