| Index: src/memory.cpp
|
| diff --git a/src/memory.cpp b/src/memory.cpp
|
| index 5b81f26e3dc004d9ae475e9a2cc04e4c5d327b7f..9432f0ae442814dd017184a93c93dcc7e4ab22af 100644
|
| --- a/src/memory.cpp
|
| +++ b/src/memory.cpp
|
| @@ -8,6 +8,7 @@
|
| //===----------------------------------------------------------------------===//
|
|
|
| #define _LIBCPP_BUILDING_MEMORY
|
| +#include "cassert"
|
| #include "memory"
|
| #ifndef _LIBCPP_HAS_NO_THREADS
|
| #include "mutex"
|
| @@ -15,6 +16,12 @@
|
| #endif
|
| #include "include/atomic_support.h"
|
|
|
| +#if defined(__APPLE__)
|
| +#include <malloc/malloc.h>
|
| +#elif defined(ANDROID)
|
| +extern "C" size_t dlmalloc_usable_size(const void*) __attribute__((weak));
|
| +#endif
|
| +
|
| _LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
| namespace
|
| @@ -225,4 +232,147 @@ align(size_t alignment, size_t size, void*& ptr, size_t& space)
|
| return r;
|
| }
|
|
|
| +// allocation_counter
|
| +
|
| +namespace
|
| +{
|
| +
|
| +struct lockable_counter {
|
| + pthread_mutex_t lock;
|
| + allocation_counter::value value;
|
| +};
|
| +
|
| +lockable_counter lockable_counters[] =
|
| +{
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| + {PTHREAD_MUTEX_INITIALIZER},
|
| +};
|
| +constexpr size_t lockable_counters_size = sizeof(lockable_counters) / sizeof(*lockable_counters);
|
| +static_assert(lockable_counters_size == allocation_group_count, "bad number of allocation counters");
|
| +
|
| +lockable_counter& counter_for_group(allocation_group group)
|
| +{
|
| + return lockable_counters[static_cast<int>(group)];
|
| +}
|
| +
|
| +size_t get_usable_size(const void* ptr) {
|
| +#if defined(__APPLE__)
|
| + return malloc_size(ptr);
|
| +#elif defined(ANDROID)
|
| + return dlmalloc_usable_size(ptr);
|
| +#else
|
| + #error Unsupported platform!
|
| +#endif
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +const char* get_allocation_group_name(allocation_group group)
|
| +{
|
| + switch (group)
|
| + {
|
| + case allocation_group::allocator: return "std::allocator";
|
| + case allocation_group::deque: return "std::deque";
|
| + case allocation_group::list: return "std::list";
|
| + case allocation_group::map: return "std::map";
|
| + case allocation_group::multimap: return "std::multimap";
|
| + case allocation_group::multiset: return "std::multiset";
|
| + case allocation_group::set: return "std::set";
|
| + case allocation_group::shared_ptr: return "std::shared_ptr";
|
| + case allocation_group::string: return "std::string";
|
| + case allocation_group::unordered_map: return "std::unordered_map";
|
| + case allocation_group::unordered_multimap: return "std::unordered_multimap";
|
| + case allocation_group::unordered_multiset: return "std::unordered_multiset";
|
| + case allocation_group::unordered_set: return "std::unordered_set";
|
| + case allocation_group::vector: return "std::vector";
|
| + case allocation_group::vector_bool: return "std::vector<bool>";
|
| +
|
| + case allocation_group::group_count: break;
|
| + }
|
| + return nullptr;
|
| +}
|
| +
|
| +allocation_counter::value allocation_counter::get(allocation_group group)
|
| +{
|
| + value result;
|
| + auto& counter = counter_for_group(group);
|
| + pthread_mutex_lock(&counter.lock);
|
| + {
|
| + result = counter.value;
|
| + }
|
| + pthread_mutex_unlock(&counter.lock);
|
| + return result;
|
| +}
|
| +
|
| +void allocation_counter::allocated(allocation_group group, const void* ptr, size_t size, size_t payload_size)
|
| +{
|
| + if (!ptr) {
|
| + return;
|
| + }
|
| + size_t usable_size = get_usable_size(ptr);
|
| + assert(usable_size >= size);
|
| + auto& counter = counter_for_group(group);
|
| + pthread_mutex_lock(&counter.lock);
|
| + {
|
| + counter.value.total_usable_size += usable_size;
|
| + counter.value.total_size += size;
|
| + counter.value.total_count += 1;
|
| + counter.value.total_payload_size += payload_size;
|
| + }
|
| + pthread_mutex_unlock(&counter.lock);
|
| +}
|
| +
|
| +void allocation_counter::deallocated(allocation_group group, const void* ptr, size_t size, size_t payload_size)
|
| +{
|
| + size_t usable_size = get_usable_size(ptr);
|
| + assert(usable_size >= size);
|
| + auto& counter = counter_for_group(group);
|
| + pthread_mutex_lock(&counter.lock);
|
| + {
|
| + assert(counter.value.total_usable_size >= usable_size &&
|
| + counter.value.total_size >= size &&
|
| + counter.value.total_count >= 1 &&
|
| + counter.value.total_payload_size >= payload_size);
|
| + counter.value.total_usable_size -= usable_size;
|
| + counter.value.total_size -= size;
|
| + counter.value.total_count -= 1;
|
| + counter.value.total_payload_size -= payload_size;
|
| + assert(counter.value.total_constructed_size <= counter.value.total_size);
|
| + }
|
| + pthread_mutex_unlock(&counter.lock);
|
| +}
|
| +
|
| +void allocation_counter::constructed(allocation_group group, size_t size) {
|
| + auto& counter = counter_for_group(group);
|
| + pthread_mutex_lock(&counter.lock);
|
| + {
|
| + counter.value.total_constructed_size += size;
|
| + assert(counter.value.total_constructed_size <= counter.value.total_size);
|
| + }
|
| + pthread_mutex_unlock(&counter.lock);
|
| +}
|
| +
|
| +void allocation_counter::destroyed(allocation_group group, size_t size) {
|
| + auto& counter = counter_for_group(group);
|
| + pthread_mutex_lock(&counter.lock);
|
| + {
|
| + assert(size <= counter.value.total_constructed_size);
|
| + counter.value.total_constructed_size -= size;
|
| + }
|
| + pthread_mutex_unlock(&counter.lock);
|
| +}
|
| +
|
| _LIBCPP_END_NAMESPACE_STD
|
|
|