mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
core: extend debug allocation tracing and reduce render-time allocations
- intercept global new/delete operations in debug memory-manager builds - distinguish anonymous global allocations from source-tracked leaks - modernize eeNew to support constructor-expression syntax - improve memory reports with tabulated leaks and separate largest allocations - cache autocomplete shortcuts instead of hashing string keys on key events - reuse UIStyle property sets across state changes - reuse Text shadow colors and avoid temporary outline-color copies - use inline storage for temporary linear-gradient rendering data - make unit tests resolve assets from the executable directory - add memory-manager and PropertyIdSet regression coverage
This commit is contained in:
@@ -6,20 +6,23 @@
|
||||
#include <cstring>
|
||||
#include <eepp/config.hpp>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace EE {
|
||||
|
||||
class EE_API AllocatedPointer {
|
||||
public:
|
||||
AllocatedPointer( void* data, const std::string& File, int Line, size_t memory,
|
||||
bool track = false );
|
||||
bool track = false, bool globalAllocation = false );
|
||||
|
||||
std::string mFile;
|
||||
int mLine;
|
||||
size_t mMemory;
|
||||
void* mData;
|
||||
bool mTrack;
|
||||
bool mGlobalAllocation;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<void*, AllocatedPointer> AllocatedPointerMap;
|
||||
@@ -39,14 +42,19 @@ class EE_API MemoryManager {
|
||||
|
||||
static bool removePointer( void* data, const char* file, const size_t& line );
|
||||
|
||||
/** Removes a pointer when it is tracked, without diagnosing foreign allocator bookkeeping. */
|
||||
static bool removePointerIfTracked( void* data );
|
||||
|
||||
static void showResults();
|
||||
|
||||
template <class T> static T* deletePtr( T* data ) {
|
||||
template <class T> static T* deletePtr( T* data, const char* file, size_t line ) {
|
||||
removePointer( data, file, line );
|
||||
delete data;
|
||||
return data;
|
||||
}
|
||||
|
||||
template <class T> static T* deleteArrayPtr( T* data ) {
|
||||
template <class T> static T* deleteArrayPtr( T* data, const char* file, size_t line ) {
|
||||
removePointer( data, file, line );
|
||||
delete[] data;
|
||||
return data;
|
||||
}
|
||||
@@ -60,25 +68,46 @@ class EE_API MemoryManager {
|
||||
|
||||
static void* reallocate( void* ptr, size_t size );
|
||||
|
||||
/** Allocation entry points used by the debug global new/delete overrides. */
|
||||
static void* allocateGlobal( size_t size, size_t alignment );
|
||||
|
||||
static void freeGlobal( void* ptr ) noexcept;
|
||||
|
||||
template <typename Factory>
|
||||
static auto create( Factory&& factory, const char* file, int line ) -> decltype( factory() ) {
|
||||
auto* pointer = std::forward<Factory>( factory )();
|
||||
using Type = typename std::remove_pointer<decltype( pointer )>::type;
|
||||
return static_cast<Type*>(
|
||||
addPointer( AllocatedPointer( pointer, file, line, sizeof( Type ) ) ) );
|
||||
}
|
||||
|
||||
static size_t getPeakMemoryUsage();
|
||||
|
||||
static size_t getTotalMemoryUsage();
|
||||
|
||||
static AllocatedPointer getBiggestAllocation();
|
||||
|
||||
static AllocatedPointer getBiggestNonAnonymousAllocation();
|
||||
};
|
||||
#if defined( __GNUC__ ) && __GNUC__ >= 12
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef EE_MEMORY_MANAGER
|
||||
#define eeNewExpression( constructor ) \
|
||||
EE::MemoryManager::create( [&]() { return new constructor; }, __FILE__, __LINE__ )
|
||||
|
||||
#define eeNewLegacy( classType, constructor ) \
|
||||
EE::MemoryManager::create( [&]() { return new classType constructor; }, __FILE__, __LINE__ )
|
||||
|
||||
#define eeNewSelect( _1, _2, NAME, ... ) NAME
|
||||
|
||||
#define eeNew( ... ) eeNewSelect( __VA_ARGS__, eeNewLegacy, eeNewExpression )( __VA_ARGS__ )
|
||||
|
||||
#define eeNewTracked( classType, constructor ) \
|
||||
(classType*)EE::MemoryManager::addPointer( EE::AllocatedPointer( \
|
||||
new classType constructor, __FILE__, __LINE__, sizeof( classType ), true ) )
|
||||
|
||||
#define eeNew( classType, constructor ) \
|
||||
(classType*)EE::MemoryManager::addPointer( EE::AllocatedPointer( \
|
||||
new classType constructor, __FILE__, __LINE__, sizeof( classType ) ) )
|
||||
|
||||
#define eeNewInPlace( place, classType, constructor ) \
|
||||
(classType*)EE::MemoryManager::addPointerInPlace( \
|
||||
place, EE::AllocatedPointer( new place classType constructor, __FILE__, __LINE__, \
|
||||
@@ -104,12 +133,7 @@ class EE_API MemoryManager {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wuse-after-free"
|
||||
#endif
|
||||
#define eeDelete( data ) \
|
||||
{ \
|
||||
if ( EE::MemoryManager::removePointer( EE::MemoryManager::deletePtr( data ), __FILE__, \
|
||||
__LINE__ ) == false ) \
|
||||
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
|
||||
}
|
||||
#define eeDelete( data ) EE::MemoryManager::deletePtr( data, __FILE__, __LINE__ )
|
||||
#if defined( __GNUC__ ) && __GNUC__ >= 12
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
@@ -117,12 +141,7 @@ class EE_API MemoryManager {
|
||||
#pragma GCC diagnostic ignored "-Wuse-after-free"
|
||||
#endif
|
||||
|
||||
#define eeDeleteArray( data ) \
|
||||
{ \
|
||||
if ( EE::MemoryManager::removePointer( EE::MemoryManager::deleteArrayPtr( data ), \
|
||||
__FILE__, __LINE__ ) == false ) \
|
||||
printf( "Deleting at '%s' %d\n", __FILE__, __LINE__ ); \
|
||||
}
|
||||
#define eeDeleteArray( data ) EE::MemoryManager::deleteArrayPtr( data, __FILE__, __LINE__ )
|
||||
#if defined( __GNUC__ ) && __GNUC__ >= 12
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
@@ -143,7 +162,13 @@ class EE_API MemoryManager {
|
||||
|
||||
#define eeNewTracked( classType, constructor ) new classType constructor
|
||||
|
||||
#define eeNew( classType, constructor ) new classType constructor
|
||||
#define eeNewExpression( constructor ) new constructor
|
||||
|
||||
#define eeNewLegacy( classType, constructor ) new classType constructor
|
||||
|
||||
#define eeNewSelect( _1, _2, NAME, ... ) NAME
|
||||
|
||||
#define eeNew( ... ) eeNewSelect( __VA_ARGS__, eeNewLegacy, eeNewExpression )( __VA_ARGS__ )
|
||||
|
||||
#define eeNewInPlace( place, classType, constructor ) new place classType constructor
|
||||
|
||||
|
||||
@@ -422,6 +422,7 @@ class EE_API Text {
|
||||
|
||||
std::vector<VertexCoords> mVertices;
|
||||
std::vector<Color> mColors;
|
||||
std::vector<Color> mShadowColors;
|
||||
std::vector<GlyphRenderMode> mRenderModes;
|
||||
std::vector<VertexCoords> mOutlineVertices;
|
||||
std::vector<Color> mOutlineColors;
|
||||
|
||||
@@ -25,9 +25,9 @@ class EE_API PropertyIdSet {
|
||||
|
||||
size_t size() const { return mIds.size(); }
|
||||
|
||||
bool operator==( const PropertyIdSet& other ) { return mIds == other.mIds; }
|
||||
bool operator==( const PropertyIdSet& other ) const { return mIds == other.mIds; }
|
||||
|
||||
bool operator!=( const PropertyIdSet& other ) { return mIds != other.mIds; }
|
||||
bool operator!=( const PropertyIdSet& other ) const { return mIds != other.mIds; }
|
||||
|
||||
// Union with another set
|
||||
PropertyIdSet& operator|=( const PropertyIdSet& other ) {
|
||||
@@ -43,7 +43,7 @@ class EE_API PropertyIdSet {
|
||||
|
||||
// Intersection with another set
|
||||
PropertyIdSet& operator&=( const PropertyIdSet& other ) {
|
||||
if ( mIds.size() > 0 && other.mIds.size() > 0 ) {
|
||||
if ( !mIds.empty() && !other.mIds.empty() ) {
|
||||
for ( auto it = mIds.begin(); it != mIds.end(); )
|
||||
if ( other.mIds.count( *it ) == 0 )
|
||||
it = mIds.erase( it );
|
||||
@@ -57,7 +57,7 @@ class EE_API PropertyIdSet {
|
||||
|
||||
PropertyIdSet operator&( const PropertyIdSet& other ) const {
|
||||
PropertyIdSet result;
|
||||
if ( mIds.size() > 0 && other.mIds.size() > 0 ) {
|
||||
if ( !mIds.empty() && !other.mIds.empty() ) {
|
||||
for ( Uint32 id : mIds )
|
||||
if ( other.mIds.count( id ) == 1 )
|
||||
result.mIds.insert( id );
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <eepp/math/ease.hpp>
|
||||
#include <eepp/ui/css/animationdefinition.hpp>
|
||||
#include <eepp/ui/css/elementdefinition.hpp>
|
||||
#include <eepp/ui/css/propertyidset.hpp>
|
||||
#include <eepp/ui/css/stylesheetproperty.hpp>
|
||||
#include <eepp/ui/css/stylesheetstyle.hpp>
|
||||
#include <eepp/ui/css/transitiondefinition.hpp>
|
||||
@@ -103,6 +104,7 @@ class EE_API UIStyle : public UIState {
|
||||
UnorderedSet<UIWidget*> mRelatedWidgets;
|
||||
UnorderedSet<UIWidget*> mSubscribedWidgets;
|
||||
UnorderedSet<UIWidget*> mStructurallyVolatileChildren;
|
||||
std::optional<CSS::PropertyIdSet> mChangedProperties;
|
||||
Uint32 mStateDepthCounter{ 0 };
|
||||
Uint64 mLoadedVersion{ 0 };
|
||||
const CSS::StyleSheet* mLoadedStyleSheet{ nullptr };
|
||||
|
||||
Reference in New Issue
Block a user