include/core/CMemoryDefStd.h (152 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the following additional limitation. Functionality enabled by the * files subject to the Elastic License 2.0 may only be used in production when * invoked by an Elasticsearch process with a license key installed that permits * use of machine learning features. You may not use this file except in * compliance with the Elastic License 2.0 and the foregoing additional * limitation. */ #ifndef INCLUDED_ml_core_CMemoryDefStd_h #define INCLUDED_ml_core_CMemoryDefStd_h #include <core/CMemoryDec.h> #include <core/CMemoryDecStd.h> #include <core/CMemoryDef.h> namespace ml { namespace core { namespace memory_detail { // Windows creates an extra map/list node per map/list #ifdef Windows constexpr std::size_t EXTRA_NODES{1}; #else constexpr std::size_t EXTRA_NODES{0}; #endif // Big variations in deque page size! #ifdef Windows constexpr std::size_t MIN_DEQUE_PAGE_SIZE{16}; constexpr std::size_t MIN_DEQUE_PAGE_VEC_ENTRIES{8}; #elif defined(MacOSX) constexpr std::size_t MIN_DEQUE_PAGE_SIZE{4096}; constexpr std::size_t MIN_DEQUE_PAGE_VEC_ENTRIES{1}; #else constexpr std::size_t MIN_DEQUE_PAGE_SIZE{512}; constexpr std::size_t MIN_DEQUE_PAGE_VEC_ENTRIES{8}; #endif } namespace memory { template<typename T, typename A> std::size_t dynamicSize(const std::list<T, A>& t) { return memory::elementDynamicSize(t) + (memory_detail::EXTRA_NODES + t.size()) * (sizeof(T) + memory::storageNodeOverhead(t)); } template<typename T, typename A> std::size_t dynamicSize(const std::deque<T, A>& t) { // std::deque is a pointer to an array of pointers to pages std::size_t pageSize = std::max(sizeof(T), memory_detail::MIN_DEQUE_PAGE_SIZE); std::size_t itemsPerPage = pageSize / sizeof(T); // This could be an underestimate if items have been removed std::size_t numPages = (t.size() + itemsPerPage - 1) / itemsPerPage; // This could also be an underestimate if items have been removed std::size_t pageVecEntries = std::max(numPages, memory_detail::MIN_DEQUE_PAGE_VEC_ENTRIES); return memory::elementDynamicSize(t) + pageVecEntries * sizeof(std::size_t) + numPages * pageSize; } template<typename K, typename V, typename C, typename A> std::size_t dynamicSize(const std::map<K, V, C, A>& t) { return memory::elementDynamicSize(t) + (memory_detail::EXTRA_NODES + t.size()) * (sizeof(K) + sizeof(V) + memory::storageNodeOverhead(t)); } template<typename K, typename V, typename C, typename A> std::size_t dynamicSize(const std::multimap<K, V, C, A>& t) { // In practice, both std::multimap and std::map use the same // rb tree implementation. return memory::elementDynamicSize(t) + (memory_detail::EXTRA_NODES + t.size()) * (sizeof(K) + sizeof(V) + memory::storageNodeOverhead(t)); } template<typename T, typename C, typename A> std::size_t dynamicSize(const std::set<T, C, A>& t) { return memory::elementDynamicSize(t) + (memory_detail::EXTRA_NODES + t.size()) * (sizeof(T) + memory::storageNodeOverhead(t)); } template<typename T, typename C, typename A> std::size_t dynamicSize(const std::multiset<T, C, A>& t) { // In practice, both std::multiset and std::set use the same // rb tree implementation. return memory::elementDynamicSize(t) + (memory_detail::EXTRA_NODES + t.size()) * (sizeof(T) + memory::storageNodeOverhead(t)); } } namespace memory_debug { template<typename T, typename A> void dynamicSize(const char* name, const std::list<T, A>& t, const CMemoryUsage::TMemoryUsagePtr& mem) { // std::list appears to use 2 pointers per list node // (prev and next pointers). std::string componentName(name); componentName += "_list"; std::size_t listSize = (memory_detail::EXTRA_NODES + t.size()) * (sizeof(T) + memory::storageNodeOverhead(t)); CMemoryUsage::SMemoryUsage usage(componentName, listSize); CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); ptr->setName(usage); memory_debug::elementDynamicSize(std::move(componentName), t, mem); } template<typename T, typename C, typename A> void dynamicSize(const char* name, const std::deque<T, A>& t, const CMemoryUsage::TMemoryUsagePtr& mem) { // std::deque is a pointer to an array of pointers to pages std::string componentName(name); componentName += "_deque"; std::size_t pageSize = std::max(sizeof(T), memory_detail::MIN_DEQUE_PAGE_SIZE); std::size_t itemsPerPage = pageSize / sizeof(T); // This could be an underestimate if items have been removed std::size_t numPages = (t.size() + itemsPerPage - 1) / itemsPerPage; // This could also be an underestimate if items have been removed std::size_t pageVecEntries = std::max(numPages, memory_detail::MIN_DEQUE_PAGE_VEC_ENTRIES); std::size_t dequeTotal = pageVecEntries * sizeof(std::size_t) + numPages * pageSize; std::size_t dequeUsed = numPages * sizeof(std::size_t) + t.size() * sizeof(T); CMemoryUsage::SMemoryUsage usage(componentName, dequeTotal, dequeTotal - dequeUsed); CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); ptr->setName(usage); memory_debug::elementDynamicSize(std::move(componentName), t, mem); } template<typename K, typename V, typename C, typename A> void dynamicSize(const char* name, const std::map<K, V, C, A>& t, const CMemoryUsage::TMemoryUsagePtr& mem) { // std::map appears to use 4 pointers/size_ts per tree node // (colour, parent, left and right child pointers). std::string componentName(name); componentName += "_map"; std::size_t mapSize = (memory_detail::EXTRA_NODES + t.size()) * (sizeof(K) + sizeof(V) + memory::storageNodeOverhead(t)); CMemoryUsage::SMemoryUsage usage(componentName, mapSize); CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); ptr->setName(usage); memory_debug::associativeElementDynamicSize(std::move(componentName), t, mem); } template<typename K, typename V, typename C, typename A> void dynamicSize(const char* name, const std::multimap<K, V, C, A>& t, const CMemoryUsage::TMemoryUsagePtr& mem) { // In practice, both std::multimap and std::map use the same // rb tree implementation. std::string componentName(name); componentName += "_map"; std::size_t mapSize = (memory_detail::EXTRA_NODES + t.size()) * (sizeof(K) + sizeof(V) + memory::storageNodeOverhead(t)); CMemoryUsage::SMemoryUsage usage(componentName, mapSize); CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); ptr->setName(usage); memory_debug::associativeElementDynamicSize(std::move(componentName), t, mem); } template<typename T, typename C, typename A> void dynamicSize(const char* name, const std::set<T, C, A>& t, const CMemoryUsage::TMemoryUsagePtr& mem) { // std::set appears to use 4 pointers/size_ts per tree node // (colour, parent, left and right child pointers). std::string componentName(name); componentName += "_set"; std::size_t setSize = (memory_detail::EXTRA_NODES + t.size()) * (sizeof(T) + memory::storageNodeOverhead(t)); CMemoryUsage::SMemoryUsage usage(componentName, setSize); CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); ptr->setName(usage); memory_debug::elementDynamicSize(std::move(componentName), t, mem); } template<typename T, typename C, typename A> void dynamicSize(const char* name, const std::multiset<T, C, A>& t, const CMemoryUsage::TMemoryUsagePtr& mem) { // In practice, both std::multimap and std::map use the same // rb tree implementation. std::string componentName(name); componentName += "_set"; std::size_t setSize = (memory_detail::EXTRA_NODES + t.size()) * (sizeof(T) + memory::storageNodeOverhead(t)); CMemoryUsage::SMemoryUsage usage(componentName, setSize); CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); ptr->setName(usage); memory_debug::elementDynamicSize(std::move(componentName), t, mem); } } } } #endif // INCLUDED_ml_core_CMemoryDefStd_h