LCOV - code coverage report
Current view: top level - DCPS - MemoryPool.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 12 13 92.3 %
Date: 2023-04-30 01:32:43 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *
       4             :  * Distributed under the OpenDDS License.
       5             :  * See: http://www.opendds.org/license.html
       6             :  */
       7             : 
       8             : #ifndef OPENDDS_DCPS_MEMORYPOOL_H
       9             : #define OPENDDS_DCPS_MEMORYPOOL_H
      10             : 
      11             : #include "dcps_export.h"
      12             : 
      13             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      14             : 
      15             : namespace OpenDDS {
      16             : namespace Test {
      17             :   class MemoryPoolTest;
      18             :   class FreeIndexTest;
      19             : }
      20             : namespace DCPS {
      21             : 
      22             : /// Header of all allocations - found at beginning of allocation inside pool.
      23             : /// Extra room must be added to each allocation for this header.
      24             : class OpenDDS_Dcps_Export AllocHeader {
      25             : public:
      26             :   /** Construct */
      27             :   AllocHeader();
      28             : 
      29             :   /** Get alloc size */
      30       66371 :   unsigned int size() const { return is_free() ? -alloc_size_ : alloc_size_; }
      31             :   /** Get prev alloc size */
      32           0 :   unsigned int prev_size() const { return prev_size_; }
      33             :   /** Is this alloc free */
      34       82036 :   bool is_free() const { return alloc_size_ < 0; }
      35             : 
      36             :   /** Get pointer to start of my buffer */
      37             :   unsigned char* ptr() const;
      38             : 
      39             :   /** Go to next header */
      40             :   AllocHeader* next_adjacent();
      41             : 
      42             :   /** Go to prev header */
      43             :   AllocHeader* prev_adjacent();
      44             : 
      45             :   /** Allocate from this block: change size, and mark as allocated */
      46             :   void allocate(size_t size);
      47             : 
      48             :   /** Set the size value stored in this header */
      49             :   void set_size(size_t size);
      50             :   /** Set the prev size value stored in this header */
      51        1305 :   void set_prev_size(int size) { prev_size_ = size; }
      52             :   /** Mark this block as allocated */
      53         784 :   void set_allocated() { if (alloc_size_ < 0) alloc_size_ = - alloc_size_; }
      54             : 
      55             :   /** Join with the next adjacent block */
      56             :   void join_next();
      57             : 
      58             : protected:
      59             :   /** Sizes are those of buffers, does not include size of headers */
      60             :   int alloc_size_; ///< Size of my buffer, negative if free, positive if alloc
      61             :   int prev_size_;  ///< Size of previous buffer, or 0 if first, never negative
      62             : };
      63             : 
      64             : /// Header of free allocations - found at beginning of allocation inside pool.
      65             : /// This forces a minimum allocation size, so that, when freed, header can
      66             : /// be cast to this type.
      67             : class OpenDDS_Dcps_Export FreeHeader : public AllocHeader {
      68             : public:
      69             :   /** Initialize the first AllocHeader with its size */
      70             :   void init_free_block(unsigned int pool_size);
      71             : 
      72             :   /** Mark as free */
      73             :   void set_free();
      74             : 
      75             :   /** Get next equal or smaller free block in size order */
      76             :   FreeHeader* smaller_free(unsigned char* pool_base) const;
      77             :   /** Get next equal or larger free block in size order */
      78             :   FreeHeader* larger_free(unsigned char* pool_base) const;
      79             : 
      80             :   /** Set the next equal or smaller free block in size order */
      81             :   void set_smaller_free(FreeHeader* next, unsigned char* pool_base);
      82             :   /** Set the next equal or larger free block in size order */
      83             :   void set_larger_free(FreeHeader* prev, unsigned char* pool_base);
      84             : 
      85             : private:
      86             :   size_t offset_smaller_free_; ///< Offset to smaller free block in size order
      87             :   size_t offset_larger_free_;  ///< Offset to larger free block in size order
      88             : };
      89             : 
      90             : /// Node of free index.  Should point to smallest free block of the range
      91             : /// from size (inclusive) to limit (non inclusive).  If multiple free
      92             : /// allocations of the smallest size in range exist, should point to the one
      93             : /// which is the "smallest" (in free list order).
      94             : class FreeIndexNode {
      95             : public:
      96             :   FreeIndexNode();
      97             :   /** Set the free alloc this node points to */
      98        2802 :   void set_ptr(FreeHeader* ptr) { ptr_ = ptr; }
      99             :   /** Set the sizes for this node */
     100             :   void set_sizes(size_t size, size_t limit);
     101             : 
     102             :   /** Does this node contain a given size */
     103         299 :   bool contains(size_t size) { return ((size >= size_) && (size < limit_)); }
     104             : 
     105             :   /** Get this node's free block */
     106       54712 :   FreeHeader* ptr() { return ptr_; }
     107             :   /** Get this node's minimum size */
     108           8 :   unsigned int size() const { return static_cast<unsigned int>(size_); }
     109             : 
     110             : private:
     111             :   size_t size_;       ///< size of buffer
     112             :   size_t limit_;      ///< upper_limit of buffer size (one too large)
     113             :   FreeHeader* ptr_;   ///< points to smallest free alloc of size_ or larger
     114             : };
     115             : 
     116             : /// Index of free nodes in memory pool.
     117             : /// Allows for a faster search of free nodes
     118             : class OpenDDS_Dcps_Export FreeIndex {
     119             :   friend class Test::MemoryPoolTest;
     120             :   friend class Test::FreeIndexTest;
     121             : public:
     122             :   explicit FreeIndex(FreeHeader*& largest_free);
     123             :   /** Initialize index with initial free block */
     124             :   void init(FreeHeader* init_free_block);
     125             : 
     126             :   /** Add free block to index */
     127             :   void add(FreeHeader* free_block);
     128             :   /** Remove free block from index */
     129             :   void remove(FreeHeader* free_block, FreeHeader* next_largest);
     130             : 
     131             :   /** Find smallest free block of size or larger */
     132             :   FreeHeader* find(size_t size, unsigned char* base);
     133             : 
     134             :   /** Calculate index of node corresponding to a size */
     135             :   static unsigned int node_index(size_t size);
     136             : 
     137             : #ifdef VALIDATE_MEMORY_POOL
     138             :   static void validate_index(FreeIndex& index,
     139             :                              unsigned char* base,
     140             :                              bool log = false);
     141             : #endif
     142             : private:
     143             :   enum {
     144             :     min_index_pow = 3,
     145             :     max_index_pow = 12
     146             :   };
     147             :   enum {
     148             :     min_index = 8,    // 2^^3
     149             :     max_index = 4096  // 2^^12
     150             :   };
     151             : 
     152             :   size_t size_;               ///< Number of index nodes
     153             :   FreeHeader*& largest_free_; ///< Memory pool's pointer to largest free block
     154             :   FreeIndexNode nodes_[max_index_pow - min_index_pow + 1];   ///< Index nodes
     155             : };
     156             : 
     157             : // MemoryPool tracks free list, in size order (next meaning largest to smallest)
     158             : // and an index into the list at various sizes, which point to the smallest
     159             : // free allocation of that size or larger (but not larger than the next size).
     160             : // Allocations can be done by checking the index for the needed size, and going
     161             : // to the first free block.
     162             : class OpenDDS_Dcps_Export MemoryPool {
     163             :   friend class Test::MemoryPoolTest;
     164             : public:
     165             :   explicit MemoryPool(unsigned int pool_size, size_t granularity = 8);
     166             :   ~MemoryPool();
     167             : 
     168             :   /** Does the pool include a given pointer */
     169       12017 :   bool includes(void* ptr) const {
     170       12017 :      return (pool_ptr_ <= ptr) && (ptr < pool_ptr_ + pool_size_); }
     171             : 
     172             :   /** Allocate size bytes from the pool **/
     173             :   void* pool_alloc(size_t size);
     174             : 
     175             :   /** Attempt to free an allocation.  Return true if allocation is managed by
     176             :       this pool (and thus was freed).
     177             :    */
     178             :   bool pool_free(void* ptr);
     179             : 
     180             :   /** Low water mark of maximum available bytes for an allocation */
     181             :   size_t lwm_free_bytes() const;
     182             : 
     183             :   /** Calculate aligned size of allocation */
     184         907 :   static size_t align(size_t size, size_t granularity) {
     185         907 :      return (size + granularity - 1) / granularity * granularity; }
     186             : 
     187             :   size_t size () const { return pool_size_; }
     188             : 
     189             : private:
     190             :   const size_t granularity_;     ///< Configured granularity
     191             :   const size_t min_alloc_size_;  ///< Aligned minimum allocation size
     192             :   const size_t pool_size_;       ///< Configured pool size
     193             :   size_t lwm_free_bytes_;        ///< Low water mark of available bytes
     194             :   unsigned char* pool_ptr_;      ///< Pointer to pool
     195             : 
     196             :   FreeHeader* largest_free_;     ///< Pointer to largest free index
     197             :   FreeIndex free_index_;         ///< Index of free nodex
     198             : 
     199             :   enum {
     200             :     min_free_size = sizeof(FreeHeader)
     201             :   };
     202             : 
     203             :   // Helpers
     204             :   void remove_free_alloc(FreeHeader* block_to_alloc);
     205             :   void insert_free_alloc(FreeHeader* block_freed);
     206             :   void join_free_allocs(FreeHeader* block_freed);
     207             :   unsigned char* allocate(FreeHeader* free_block, size_t alloc_size);
     208             : 
     209             :   bool joinable_next(FreeHeader* freed);
     210             :   bool joinable_prev(FreeHeader* freed);
     211             : 
     212             : #ifdef VALIDATE_MEMORY_POOL
     213             :   static void validate_pool(MemoryPool& pool, bool log = false);
     214             : #endif
     215             : };
     216             : 
     217             : }} // end namespaces
     218             : 
     219             : OPENDDS_END_VERSIONED_NAMESPACE_DECL
     220             : 
     221             : #endif // OPENDDS_MEMORY_POOL_H

Generated by: LCOV version 1.16