LCOV - code coverage report
Current view: top level - src - memusage.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 25 34 73.5 %
Date: 2023-09-26 12:08:55 Functions: 13 26 50.0 %

          Line data    Source code
       1             : // Copyright (c) 2015-2022 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #ifndef BITCOIN_MEMUSAGE_H
       6             : #define BITCOIN_MEMUSAGE_H
       7             : 
       8             : #include <indirectmap.h>
       9             : #include <prevector.h>
      10             : #include <support/allocators/pool.h>
      11             : 
      12             : #include <cassert>
      13             : #include <cstdlib>
      14             : #include <map>
      15             : #include <memory>
      16             : #include <set>
      17             : #include <vector>
      18             : #include <unordered_map>
      19             : #include <unordered_set>
      20             : 
      21             : 
      22             : namespace memusage
      23             : {
      24             : 
      25             : /** Compute the total memory used by allocating alloc bytes. */
      26             : static size_t MallocUsage(size_t alloc);
      27             : 
      28             : /** Dynamic memory usage for built-in types is zero. */
      29           0 : static inline size_t DynamicUsage(const int8_t& v) { return 0; }
      30           0 : static inline size_t DynamicUsage(const uint8_t& v) { return 0; }
      31           0 : static inline size_t DynamicUsage(const int16_t& v) { return 0; }
      32           0 : static inline size_t DynamicUsage(const uint16_t& v) { return 0; }
      33           0 : static inline size_t DynamicUsage(const int32_t& v) { return 0; }
      34           0 : static inline size_t DynamicUsage(const uint32_t& v) { return 0; }
      35           0 : static inline size_t DynamicUsage(const int64_t& v) { return 0; }
      36           0 : static inline size_t DynamicUsage(const uint64_t& v) { return 0; }
      37             : static inline size_t DynamicUsage(const float& v) { return 0; }
      38           0 : static inline size_t DynamicUsage(const double& v) { return 0; }
      39             : template<typename X> static inline size_t DynamicUsage(X * const &v) { return 0; }
      40             : template<typename X> static inline size_t DynamicUsage(const X * const &v) { return 0; }
      41             : 
      42             : /** Compute the memory used for dynamically allocated but owned data structures.
      43             :  *  For generic data types, this is *not* recursive. DynamicUsage(vector<vector<int> >)
      44             :  *  will compute the memory used for the vector<int>'s, but not for the ints inside.
      45             :  *  This is for efficiency reasons, as these functions are intended to be fast. If
      46             :  *  application data structures require more accurate inner accounting, they should
      47             :  *  iterate themselves, or use more efficient caching + updating on modification.
      48             :  */
      49             : 
      50      499504 : static inline size_t MallocUsage(size_t alloc)
      51             : {
      52             :     // Measured on libc6 2.19 on Linux.
      53      499504 :     if (alloc == 0) {
      54       38713 :         return 0;
      55             :     } else if (sizeof(void*) == 8) {
      56      460791 :         return ((alloc + 31) >> 4) << 4;
      57             :     } else if (sizeof(void*) == 4) {
      58             :         return ((alloc + 15) >> 3) << 3;
      59             :     } else {
      60             :         assert(0);
      61             :     }
      62      499504 : }
      63             : 
      64             : // STL data structures
      65             : 
      66             : template<typename X>
      67             : struct stl_tree_node
      68             : {
      69             : private:
      70             :     int color;
      71             :     void* parent;
      72             :     void* left;
      73             :     void* right;
      74             :     X x;
      75             : };
      76             : 
      77             : struct stl_shared_counter
      78             : {
      79             :     /* Various platforms use different sized counters here.
      80             :      * Conservatively assume that they won't be larger than size_t. */
      81             :     void* class_type;
      82             :     size_t use_count;
      83             :     size_t weak_count;
      84             : };
      85             : 
      86             : template<typename X>
      87       75369 : static inline size_t DynamicUsage(const std::vector<X>& v)
      88             : {
      89       75369 :     return MallocUsage(v.capacity() * sizeof(X));
      90             : }
      91             : 
      92             : template<unsigned int N, typename X, typename S, typename D>
      93      253023 : static inline size_t DynamicUsage(const prevector<N, X, S, D>& v)
      94             : {
      95      253023 :     return MallocUsage(v.allocated_memory());
      96             : }
      97             : 
      98             : template<typename X, typename Y>
      99        8226 : static inline size_t DynamicUsage(const std::set<X, Y>& s)
     100             : {
     101        8226 :     return MallocUsage(sizeof(stl_tree_node<X>)) * s.size();
     102             : }
     103             : 
     104             : template<typename X, typename Y>
     105        1040 : static inline size_t IncrementalDynamicUsage(const std::set<X, Y>& s)
     106             : {
     107        1040 :     return MallocUsage(sizeof(stl_tree_node<X>));
     108             : }
     109             : 
     110             : template<typename X, typename Y, typename Z>
     111       18489 : static inline size_t DynamicUsage(const std::map<X, Y, Z>& m)
     112             : {
     113       18489 :     return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >)) * m.size();
     114             : }
     115             : 
     116             : template<typename X, typename Y, typename Z>
     117             : static inline size_t IncrementalDynamicUsage(const std::map<X, Y, Z>& m)
     118             : {
     119             :     return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >));
     120             : }
     121             : 
     122             : // indirectmap has underlying map with pointer as key
     123             : 
     124             : template<typename X, typename Y>
     125       18489 : static inline size_t DynamicUsage(const indirectmap<X, Y>& m)
     126             : {
     127       18489 :     return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >)) * m.size();
     128             : }
     129             : 
     130             : template<typename X, typename Y>
     131             : static inline size_t IncrementalDynamicUsage(const indirectmap<X, Y>& m)
     132             : {
     133             :     return MallocUsage(sizeof(stl_tree_node<std::pair<const X*, Y> >));
     134             : }
     135             : 
     136             : template<typename X>
     137             : static inline size_t DynamicUsage(const std::unique_ptr<X>& p)
     138             : {
     139             :     return p ? MallocUsage(sizeof(X)) : 0;
     140             : }
     141             : 
     142             : template<typename X>
     143        5047 : static inline size_t DynamicUsage(const std::shared_ptr<X>& p)
     144             : {
     145             :     // A shared_ptr can either use a single continuous memory block for both
     146             :     // the counter and the storage (when using std::make_shared), or separate.
     147             :     // We can't observe the difference, however, so assume the worst.
     148        5047 :     return p ? MallocUsage(sizeof(X)) + MallocUsage(sizeof(stl_shared_counter)) : 0;
     149             : }
     150             : 
     151             : template<typename X>
     152             : struct unordered_node : private X
     153             : {
     154             : private:
     155             :     void* ptr;
     156             : };
     157             : 
     158             : template<typename X, typename Y>
     159             : static inline size_t DynamicUsage(const std::unordered_set<X, Y>& s)
     160             : {
     161             :     return MallocUsage(sizeof(unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());
     162             : }
     163             : 
     164             : template<typename X, typename Y, typename Z>
     165             : static inline size_t DynamicUsage(const std::unordered_map<X, Y, Z>& m)
     166             : {
     167             :     return MallocUsage(sizeof(unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
     168             : }
     169             : 
     170             : template <class Key, class T, class Hash, class Pred, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
     171       32095 : static inline size_t DynamicUsage(const std::unordered_map<Key,
     172             :                                                            T,
     173             :                                                            Hash,
     174             :                                                            Pred,
     175             :                                                            PoolAllocator<std::pair<const Key, T>,
     176             :                                                                          MAX_BLOCK_SIZE_BYTES,
     177             :                                                                          ALIGN_BYTES>>& m)
     178             : {
     179       32095 :     auto* pool_resource = m.get_allocator().resource();
     180             : 
     181             :     // The allocated chunks are stored in a std::list. Size per node should
     182             :     // therefore be 3 pointers: next, previous, and a pointer to the chunk.
     183       32095 :     size_t estimated_list_node_size = MallocUsage(sizeof(void*) * 3);
     184       32095 :     size_t usage_resource = estimated_list_node_size * pool_resource->NumAllocatedChunks();
     185       32095 :     size_t usage_chunks = MallocUsage(pool_resource->ChunkSizeBytes()) * pool_resource->NumAllocatedChunks();
     186       32095 :     return usage_resource + usage_chunks + MallocUsage(sizeof(void*) * m.bucket_count());
     187             : }
     188             : 
     189             : } // namespace memusage
     190             : 
     191             : #endif // BITCOIN_MEMUSAGE_H

Generated by: LCOV version 1.14