diff options
Diffstat (limited to 'intern/cycles/util/util_guarded_allocator.h')
-rw-r--r-- | intern/cycles/util/util_guarded_allocator.h | 124 |
1 files changed, 100 insertions, 24 deletions
diff --git a/intern/cycles/util/util_guarded_allocator.h b/intern/cycles/util/util_guarded_allocator.h index 2df717253e3..f6004749a13 100644 --- a/intern/cycles/util/util_guarded_allocator.h +++ b/intern/cycles/util/util_guarded_allocator.h @@ -17,17 +17,10 @@ #ifndef __UTIL_GUARDED_ALLOCATOR_H__ #define __UTIL_GUARDED_ALLOCATOR_H__ -/* Define this in order to use Blender's guarded allocator to keep - * track of allocated buffers, their sizes and peak memory usage. - * - * This is usually a bad level call, but it's really handy to keep - * track of overall peak memory consumption during the scene - * synchronization step. - */ -#undef WITH_BLENDER_GUARDEDALLOC - +#include <cstddef> #include <memory> +#include "util_debug.h" #include "util_types.h" #ifdef WITH_BLENDER_GUARDEDALLOC @@ -42,39 +35,122 @@ void util_guarded_mem_free(size_t n); /* Guarded allocator for the use with STL. */ template <typename T> -class GuardedAllocator : public std::allocator<T> { +class GuardedAllocator { public: - template<typename _Tp1> - struct rebind { - typedef GuardedAllocator<_Tp1> other; - }; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + GuardedAllocator() {} + GuardedAllocator(const GuardedAllocator&) {} T *allocate(size_t n, const void *hint = 0) { - util_guarded_mem_alloc(n * sizeof(T)); -#ifdef WITH_BLENDER_GUARDEDALLOC + size_t size = n * sizeof(T); + util_guarded_mem_alloc(size); (void)hint; - return (T*)MEM_mallocN_aligned(n * sizeof(T), 16, "Cycles Alloc"); +#ifdef WITH_BLENDER_GUARDEDALLOC + if(n == 0) { + return NULL; + } + /* C++ standard requires allocation functions to allocate memory suitably + * aligned for any standard type. This is 16 bytes for 64 bit platform as + * far as i concerned. We might over-align on 32bit here, but that should + * be all safe actually. + */ + return (T*)MEM_mallocN_aligned(size, 16, "Cycles Alloc"); #else - return std::allocator<T>::allocate(n, hint); + return (T*)malloc(size); #endif } void deallocate(T *p, size_t n) { util_guarded_mem_free(n * sizeof(T)); + if(p != NULL) { #ifdef WITH_BLENDER_GUARDEDALLOC - MEM_freeN((void*)p); + MEM_freeN(p); #else - std::allocator<T>::deallocate(p, n); + free(p); #endif + } + } + + T *address(T& x) const + { + return &x; + } + + const T *address(const T& x) const + { + return &x; + } + + GuardedAllocator<T>& operator=(const GuardedAllocator&) + { + return *this; + } + + void construct(T *p, const T& val) + { + new ((T *)p) T(val); } - GuardedAllocator() : std::allocator<T>() { } - GuardedAllocator(const GuardedAllocator &a) : std::allocator<T>(a) { } + void destroy(T *p) + { + p->~T(); + } + + size_t max_size() const + { + return size_t(-1); + } + + template <class U> + struct rebind { + typedef GuardedAllocator<U> other; + }; + template <class U> - GuardedAllocator(const GuardedAllocator<U> &a) : std::allocator<T>(a) { } - ~GuardedAllocator() { } + GuardedAllocator(const GuardedAllocator<U>&) {} + + template <class U> + GuardedAllocator& operator=(const GuardedAllocator<U>&) { return *this; } + + inline bool operator==(GuardedAllocator const& /*other*/) const { return true; } + inline bool operator!=(GuardedAllocator const& other) const { return !operator==(other); } + +#ifdef _MSC_VER + /* Welcome to the black magic here. + * + * The issue is that MSVC C++ allocates container proxy on any + * vector initialization, including static vectors which don't + * have any data yet. This leads to several issues: + * + * - Static objects initialization fiasco (global_stats from + * util_stats.h might not be initialized yet). + * - If main() function changes allocator type (for example, + * this might happen with `blender --debug-memory`) nobody + * will know how to convert already allocated memory to a new + * guarded allocator. + * + * Here we work this around by making it so container proxy does + * not use guarded allocation. A bit fragile, unfortunately. + */ + template<> + struct rebind<std::_Container_proxy> { + typedef std::allocator<std::_Container_proxy> other; + }; + + operator std::allocator<std::_Container_proxy>() const + { + return std::allocator<std::_Container_proxy>(); + } +#endif }; /* Get memory usage and peak from the guarded STL allocator. */ |