|
6 | 6 | #ifndef INCLUDED_ml_core_CMemory_h |
7 | 7 | #define INCLUDED_ml_core_CMemory_h |
8 | 8 |
|
| 9 | +#include <core/BoostMultiIndex.h> |
9 | 10 | #include <core/CLogger.h> |
10 | 11 | #include <core/CMemoryUsage.h> |
11 | 12 | #include <core/CNonInstantiatable.h> |
|
14 | 15 | #include <boost/any.hpp> |
15 | 16 | #include <boost/circular_buffer_fwd.hpp> |
16 | 17 | #include <boost/container/container_fwd.hpp> |
| 18 | +#include <boost/mpl/range_c.hpp> |
17 | 19 | #include <boost/optional/optional_fwd.hpp> |
18 | 20 | #include <boost/shared_array.hpp> |
19 | 21 | #include <boost/type_traits/is_pointer.hpp> |
@@ -491,6 +493,30 @@ class CORE_EXPORT CMemory : private CNonInstantiatable { |
491 | 493 | return mem + pageVecEntries * sizeof(std::size_t) + numPages * pageSize; |
492 | 494 | } |
493 | 495 |
|
| 496 | + //! Overload for boost::multi_index::multi_index_container. |
| 497 | + template<typename T, typename I, typename A> |
| 498 | + static std::size_t |
| 499 | + dynamicSize(const boost::multi_index::multi_index_container<T, I, A>& t) { |
| 500 | + // It's tricky to determine the container overhead of a multi-index |
| 501 | + // container. It can have an arbitrary number of indices, each of which |
| 502 | + // can be of a different type. To accurately determine the overhead |
| 503 | + // would require some serious template metaprogramming to interpret the |
| 504 | + // "typename I" template argument, and it's just not worth it given the |
| 505 | + // infrequent and relatively simple usage (generally just two indices |
| 506 | + // in our current codebase). Therefore there's an approximation here |
| 507 | + // that the overhead is 2 pointers per entry per index. |
| 508 | + using TMultiIndex = boost::multi_index::multi_index_container<T, I, A>; |
| 509 | + constexpr std::size_t indexCount{ |
| 510 | + boost::mpl::size<typename TMultiIndex::index_type_list>::value}; |
| 511 | + std::size_t mem = 0; |
| 512 | + if (!memory_detail::SDynamicSizeAlwaysZero<T>::value()) { |
| 513 | + for (auto i = t.begin(); i != t.end(); ++i) { |
| 514 | + mem += dynamicSize(*i); |
| 515 | + } |
| 516 | + } |
| 517 | + return mem + t.size() * (sizeof(T) + 2 * indexCount * sizeof(std::size_t)); |
| 518 | + } |
| 519 | + |
494 | 520 | //! Overload for boost::circular_buffer. |
495 | 521 | template<typename T, typename A> |
496 | 522 | static std::size_t dynamicSize(const boost::circular_buffer<T, A>& t) { |
@@ -970,7 +996,7 @@ class CORE_EXPORT CMemoryDebug : private CNonInstantiatable { |
970 | 996 | componentName += "_list"; |
971 | 997 |
|
972 | 998 | std::size_t listSize = (memory_detail::EXTRA_NODES + t.size()) * |
973 | | - (sizeof(T) + 4 * sizeof(std::size_t)); |
| 999 | + (sizeof(T) + 2 * sizeof(std::size_t)); |
974 | 1000 |
|
975 | 1001 | CMemoryUsage::SMemoryUsage usage(componentName, listSize); |
976 | 1002 | CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); |
@@ -1009,6 +1035,37 @@ class CORE_EXPORT CMemoryDebug : private CNonInstantiatable { |
1009 | 1035 | } |
1010 | 1036 | } |
1011 | 1037 |
|
| 1038 | + //! Overload for boost::multi_index::multi_index_container. |
| 1039 | + template<typename T, typename I, typename A> |
| 1040 | + static void dynamicSize(const char* name, |
| 1041 | + const boost::multi_index::multi_index_container<T, I, A>& t, |
| 1042 | + CMemoryUsage::TMemoryUsagePtr mem) { |
| 1043 | + // It's tricky to determine the container overhead of a multi-index |
| 1044 | + // container. It can have an arbitrary number of indices, each of which |
| 1045 | + // can be of a different type. To accurately determine the overhead |
| 1046 | + // would require some serious template metaprogramming to interpret the |
| 1047 | + // "typename I" template argument, and it's just not worth it given the |
| 1048 | + // infrequent and relatively simple usage (generally just two indices |
| 1049 | + // in our current codebase). Therefore there's an approximation here |
| 1050 | + // that the overhead is 2 pointers per entry per index. |
| 1051 | + using TMultiIndex = boost::multi_index::multi_index_container<T, I, A>; |
| 1052 | + constexpr std::size_t indexCount{ |
| 1053 | + boost::mpl::size<typename TMultiIndex::index_type_list>::value}; |
| 1054 | + std::string componentName(name); |
| 1055 | + |
| 1056 | + std::size_t items = t.size(); |
| 1057 | + CMemoryUsage::SMemoryUsage usage( |
| 1058 | + componentName + "::" + typeid(T).name(), |
| 1059 | + items * (sizeof(T) + 2 * indexCount * sizeof(std::size_t))); |
| 1060 | + CMemoryUsage::TMemoryUsagePtr ptr = mem->addChild(); |
| 1061 | + ptr->setName(usage); |
| 1062 | + |
| 1063 | + componentName += "_item"; |
| 1064 | + for (auto i = t.begin(); i != t.end(); ++i) { |
| 1065 | + dynamicSize(componentName.c_str(), *i, ptr); |
| 1066 | + } |
| 1067 | + } |
| 1068 | + |
1012 | 1069 | //! Overload for boost::circular_buffer. |
1013 | 1070 | template<typename T, typename A> |
1014 | 1071 | static void dynamicSize(const char* name, |
|
0 commit comments