From f68fa1909ad86ae78532673bf1a469ba0cd67c21 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 24 Apr 2009 22:52:23 +0000 Subject: [PATCH] USE_DELETED_CHAIN, memory alignment --- dtool/Config.pp | 23 ++++++++ dtool/LocalSetup.pp | 14 +++++ dtool/pptempl/PostConfig.pp | 9 ++-- dtool/src/dtoolbase/deletedBufferChain.I | 6 +-- dtool/src/dtoolbase/deletedBufferChain.cxx | 10 ++++ dtool/src/dtoolbase/deletedChain.h | 15 ++++++ dtool/src/dtoolbase/memoryHook.cxx | 63 ++++++++++++++++++---- dtool/src/dtoolbase/memoryHook.h | 2 + dtool/src/dtoolbase/neverFreeMemory.cxx | 7 +++ 9 files changed, 133 insertions(+), 16 deletions(-) diff --git a/dtool/Config.pp b/dtool/Config.pp index 45c1810267..6f50d49ef9 100644 --- a/dtool/Config.pp +++ b/dtool/Config.pp @@ -395,6 +395,13 @@ //#defer ALTERNATIVE_MALLOC $[or $[WINDOWS_PLATFORM],$[DO_MEMORY_USAGE],$[not $[HAVE_THREADS]]] #define ALTERNATIVE_MALLOC +// Define this true to use the DELETED_CHAIN macros, which support +// fast re-use of existing allocated blocks, minimizing the low-level +// calls to malloc() and free() for frequently-created and -deleted +// objects. There's usually no reason to set this false, unless you +// suspect a bug in Panda's memory management code. +#define USE_DELETED_CHAIN 1 + // Define this true to build the low-level native network // implementation. Normally this should be set true. #define WANT_NATIVE_NET 1 @@ -407,6 +414,11 @@ // Normally, if you build NATIVE_NET, you will also build NET. #defer HAVE_NET $[WANT_NATIVE_NET] +// Do you want to build the egg loader? Usually there's no reason to +// avoid building this, unless you really want to make a low-footprint +// build (such as, for instance, for the iPhone). +#define HAVE_EGG 1 + // Is a third-party STL library installed, and where? This is only // necessary if the default include and link lines that come with the // compiler don't provide adequate STL support. At least some form of @@ -460,6 +472,17 @@ #define TIFF_LIBS tiff z #defer HAVE_TIFF $[libtest $[TIFF_LPATH],$[TIFF_LIBS]] +// These image file formats don't require the assistance of a +// third-party library to read and write, so there's normally no +// reason to disable them in the build, unless you are looking to +// reduce the memory footprint. +#define HAVE_SGI_RGB 1 +#define HAVE_TGA 1 +#define HAVE_IMG 1 +#define HAVE_SOFTIMAGE_PIC 1 +#define HAVE_BMP 1 +#define HAVE_PNM 1 + // Is libtar installed, and where? This is used to optimize patch // generation against tar files. #define TAR_IPATH diff --git a/dtool/LocalSetup.pp b/dtool/LocalSetup.pp index 616f4015a5..c5297daf85 100644 --- a/dtool/LocalSetup.pp +++ b/dtool/LocalSetup.pp @@ -244,6 +244,14 @@ $[cdefine HAVE_PNG] /* Define if we have libtiff installed. */ $[cdefine HAVE_TIFF] +/* Define if we want to build these other image file formats. */ +$[cdefine HAVE_SGI_RGB] +$[cdefine HAVE_TGA] +$[cdefine HAVE_IMG] +$[cdefine HAVE_SOFTIMAGE_PIC] +$[cdefine HAVE_BMP] +$[cdefine HAVE_PNM] + /* Define if we have libtar installed. */ $[cdefine HAVE_TAR] @@ -344,6 +352,9 @@ $[cdefine USE_PANDAFILESTREAM] /* Define if we want to compile the net code. */ $[cdefine HAVE_NET] +/* Define if we want to compile the egg code. */ +$[cdefine HAVE_EGG] + /* Define if we want to compile the audio code. */ $[cdefine HAVE_AUDIO] @@ -584,6 +595,9 @@ $[cdefine USE_MEMORY_PTMALLOC2] $[cdefine USE_MEMORY_MALLOC] $[cdefine USE_MEMORY_NOWRAPPERS] +// To activate the DELETED_CHAIN macros. +$[cdefine USE_DELETED_CHAIN] + // If we are to build the native net interfaces. $[cdefine WANT_NATIVE_NET] diff --git a/dtool/pptempl/PostConfig.pp b/dtool/pptempl/PostConfig.pp index e7c00a61eb..c1cc0a5089 100644 --- a/dtool/pptempl/PostConfig.pp +++ b/dtool/pptempl/PostConfig.pp @@ -8,12 +8,13 @@ #define IPH_VERSION 2.0 #if $[eq $[IPH_PLATFORM], iPhoneOS] - #define ARCH_FLAGS -arch armv6 - #define osflags -miphoneos-version-min=2.0 - #define DEBUGFLAGS + #define ARCH_FLAGS -arch armv6 -mcpu=arm1176jzf-s + #define osflags -fpascal-strings -fasm-blocks -fvisibility=hidden -fvisibility-inlines-hidden -miphoneos-version-min=2.0 + #define DEBUGFLAGS -gdwarf-2 + //#define DEBUGFLAGS #elif $[eq $[IPH_PLATFORM], iPhoneSimulator] #define ARCH_FLAGS -arch i386 - #define osflags -mmacosx-version-min=10.5 + #define osflags -fpascal-strings -fasm-blocks -fvisibility=hidden -fvisibility-inlines-hidden -mmacosx-version-min=10.5 #define DEBUGFLAGS -gdwarf-2 #else #error Inappropriate value for BUILD_IPHONE. diff --git a/dtool/src/dtoolbase/deletedBufferChain.I b/dtool/src/dtoolbase/deletedBufferChain.I index 4d1cb1113f..23a320dd8e 100644 --- a/dtool/src/dtoolbase/deletedBufferChain.I +++ b/dtool/src/dtoolbase/deletedBufferChain.I @@ -30,7 +30,7 @@ validate(void *ptr) { return false; } -#ifdef USE_DELETEDCHAINFLAG +#if defined(USE_DELETEDCHAINFLAG) && defined(USE_DELETED_CHAIN) const ObjectNode *obj = buffer_to_node(ptr); return AtomicAdjust::get(obj->_flag) == DCF_alive; #else @@ -56,7 +56,7 @@ get_buffer_size() const { //////////////////////////////////////////////////////////////////// INLINE void *DeletedBufferChain:: node_to_buffer(DeletedBufferChain::ObjectNode *node) { -#ifdef USE_DELETEDCHAINFLAG +#if defined(USE_DELETEDCHAINFLAG) && defined(USE_DELETED_CHAIN) // In development mode, we increment the pointer so that the // returned data does not overlap our _flag member. return (void *)(((AtomicAdjust::Integer *)node) + 1); @@ -72,7 +72,7 @@ node_to_buffer(DeletedBufferChain::ObjectNode *node) { //////////////////////////////////////////////////////////////////// INLINE DeletedBufferChain::ObjectNode *DeletedBufferChain:: buffer_to_node(void *ptr) { -#ifdef USE_DELETEDCHAINFLAG +#if defined(USE_DELETEDCHAINFLAG) && defined(USE_DELETED_CHAIN) // In development mode, we decrement the pointer to undo the // increment we did above. return (ObjectNode *)(((AtomicAdjust::Integer *)ptr) - 1); diff --git a/dtool/src/dtoolbase/deletedBufferChain.cxx b/dtool/src/dtoolbase/deletedBufferChain.cxx index c03ce287e2..8cf83c44c8 100644 --- a/dtool/src/dtoolbase/deletedBufferChain.cxx +++ b/dtool/src/dtoolbase/deletedBufferChain.cxx @@ -46,6 +46,7 @@ DeletedBufferChain(size_t buffer_size) { //////////////////////////////////////////////////////////////////// void *DeletedBufferChain:: allocate(size_t size, TypeHandle type_handle) { +#ifdef USE_DELETED_CHAIN TAU_PROFILE("void *DeletedBufferChain::allocate(size_t, TypeHandle)", " ", TAU_USER); assert(size <= _buffer_size); @@ -89,6 +90,10 @@ allocate(size_t size, TypeHandle type_handle) { #endif // DO_MEMORY_USAGE return ptr; + +#else // USE_DELETED_CHAIN + return PANDA_MALLOC_SINGLE(_buffer_size); +#endif // USE_DELETED_CHAIN } //////////////////////////////////////////////////////////////////// @@ -99,6 +104,7 @@ allocate(size_t size, TypeHandle type_handle) { //////////////////////////////////////////////////////////////////// void DeletedBufferChain:: deallocate(void *ptr, TypeHandle type_handle) { +#ifdef USE_DELETED_CHAIN TAU_PROFILE("void DeletedBufferChain::deallocate(void *, TypeHandle)", " ", TAU_USER); assert(ptr != (void *)NULL); @@ -127,4 +133,8 @@ deallocate(void *ptr, TypeHandle type_handle) { _deleted_chain = obj; _lock.release(); + +#else // USE_DELETED_CHAIN + PANDA_FREE_SINGLE(ptr); +#endif // USE_DELETED_CHAIN } diff --git a/dtool/src/dtoolbase/deletedChain.h b/dtool/src/dtoolbase/deletedChain.h index 0c08ac52c3..21038c606b 100644 --- a/dtool/src/dtoolbase/deletedChain.h +++ b/dtool/src/dtoolbase/deletedChain.h @@ -87,6 +87,7 @@ public: static DeletedChain _chain; }; +#ifdef USE_DELETED_CHAIN // Place this macro within a class definition to define appropriate // operator new and delete methods that take advantage of // DeletedChain. @@ -131,6 +132,20 @@ public: #define ALLOC_DELETED_CHAIN_DEF(Type) \ DeletedChain< Type > Type::_deleted_chain; +#else // USE_DELETED_CHAIN + +#define ALLOC_DELETED_CHAIN(Type) \ + inline static bool validate_ptr(const void *ptr) { \ + return (ptr != NULL); \ + } +#define ALLOC_DELETED_CHAIN_DECL(Type) \ + inline static bool validate_ptr(const void *ptr) { \ + return (ptr != NULL); \ + } +#define ALLOC_DELETED_CHAIN_DEF(Type) + +#endif // USE_DELETED_CHAIN + #include "deletedChain.T" #endif diff --git a/dtool/src/dtoolbase/memoryHook.cxx b/dtool/src/dtoolbase/memoryHook.cxx index d46d5d2d18..8eb9cc047f 100644 --- a/dtool/src/dtoolbase/memoryHook.cxx +++ b/dtool/src/dtoolbase/memoryHook.cxx @@ -189,9 +189,15 @@ heap_alloc_single(size_t size) { void *alloc = call_malloc(inflate_size(size)); #endif - if (alloc == (void *)NULL) { - cerr << "Out of memory!\n"; - abort(); + while (alloc == (void *)NULL) { + alloc_fail(); +#ifdef MEMORY_HOOK_MALLOC_LOCK + _lock.acquire(); + alloc = call_malloc(inflate_size(size)); + _lock.release(); +#else + alloc = call_malloc(inflate_size(size)); +#endif } #ifdef DO_MEMORY_USAGE @@ -255,9 +261,15 @@ heap_alloc_array(size_t size) { void *alloc = call_malloc(inflate_size(size)); #endif - if (alloc == (void *)NULL) { - cerr << "Out of memory!\n"; - abort(); + while (alloc == (void *)NULL) { + alloc_fail(); +#ifdef MEMORY_HOOK_MALLOC_LOCK + _lock.acquire(); + alloc = call_malloc(inflate_size(size)); + _lock.release(); +#else + alloc = call_malloc(inflate_size(size)); +#endif } #ifdef DO_MEMORY_USAGE @@ -298,9 +310,19 @@ heap_realloc_array(void *ptr, size_t size) { alloc = call_realloc(alloc, inflate_size(size)); #endif - if (alloc == (void *)NULL) { - cerr << "Out of memory!\n"; - abort(); + while (alloc == (void *)NULL) { + alloc_fail(); + + // Recover the original pointer. + alloc = ptr_to_alloc(ptr, orig_size); + +#ifdef MEMORY_HOOK_MALLOC_LOCK + _lock.acquire(); + alloc = call_realloc(alloc, inflate_size(size)); + _lock.release(); +#else + alloc = call_realloc(alloc, inflate_size(size)); +#endif } return alloc_to_ptr(alloc, size); @@ -499,6 +521,29 @@ get_deleted_chain(size_t buffer_size) { return chain; } +//////////////////////////////////////////////////////////////////// +// Function: MemoryHook::alloc_fail +// Access: Protected, Virtual +// Description: This callback method is called whenever a low-level +// call to call_malloc() has returned NULL, indicating +// failure. +// +// Since this method is called very low-level, and may +// be in the middle of any number of critical sections, +// it will be difficult for this callback initiate any +// emergency high-level operation to make more memory +// available. However, this module is set up to assume +// that that's what this method does, and will make +// another alloc attempt after it returns. Probably the +// only sensible thing this method can do, however, is +// just to display a message and abort. +//////////////////////////////////////////////////////////////////// +void MemoryHook:: +alloc_fail() { + cerr << "Out of memory!\n"; + abort(); +} + #ifdef DO_MEMORY_USAGE //////////////////////////////////////////////////////////////////// // Function: MemoryHook::overflow_heap_size diff --git a/dtool/src/dtoolbase/memoryHook.h b/dtool/src/dtoolbase/memoryHook.h index 76e54a4ec9..54d17cbed2 100644 --- a/dtool/src/dtoolbase/memoryHook.h +++ b/dtool/src/dtoolbase/memoryHook.h @@ -67,6 +67,8 @@ public: DeletedBufferChain *get_deleted_chain(size_t buffer_size); + virtual void alloc_fail(); + private: INLINE static size_t inflate_size(size_t size); INLINE static void *alloc_to_ptr(void *alloc, size_t size); diff --git a/dtool/src/dtoolbase/neverFreeMemory.cxx b/dtool/src/dtoolbase/neverFreeMemory.cxx index 9c2e95ea12..a9b34aac54 100644 --- a/dtool/src/dtoolbase/neverFreeMemory.cxx +++ b/dtool/src/dtoolbase/neverFreeMemory.cxx @@ -25,6 +25,10 @@ static const size_t min_page_remaining_size = 16; // We always allocate at least this many bytes at a time. static const size_t min_page_size = 128 * 1024; // 128K +// We always allocate integer multiples of this many bytes, to +// guarantee this minimum alignment. +static const size_t alignment_size = sizeof(long); + //////////////////////////////////////////////////////////////////// // Function: NeverFreeMemory::Constructor // Access: Private @@ -45,6 +49,9 @@ void *NeverFreeMemory:: ns_alloc(size_t size) { _lock.acquire(); + // Round up to the next alignment_size. + size = ((size + alignment_size - 1) / alignment_size) * alignment_size; + _total_used += size; // Look for a page that has sufficient space remaining.