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_DYNAMIC_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H
9 : #define OPENDDS_DCPS_DYNAMIC_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H
10 :
11 : #include "debug.h"
12 : #include "Atomic.h"
13 : #include "PoolAllocationBase.h"
14 :
15 : #include <ace/Free_List.h>
16 : #include <ace/Guard_T.h>
17 : #include <ace/Malloc_Allocator.h>
18 : #include <ace/Malloc_T.h>
19 :
20 : #if !defined (ACE_LACKS_PRAGMA_ONCE)
21 : # pragma once
22 : #endif /* ACE_LACKS_PRAGMA_ONCE */
23 :
24 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
25 :
26 : namespace OpenDDS {
27 : namespace DCPS {
28 :
29 : /**
30 : * @class Dynamic_Cached_Allocator_With_Overflow
31 : *
32 : * @brief A size-based allocator that caches blocks for quicker access,
33 : * but if the pool is exhausted it will use the heap.
34 : *
35 : * This class enables caching of dynamically allocated,
36 : * fixed-size chunks. Notice that the <code>chunk_size</code>
37 : * must be greater than or equal to <code> sizeof (void*) </code> for
38 : * this to work properly.
39 : *
40 : * This class can be configured flexibly with different types of
41 : * ACE_LOCK strategies that support the @a ACE_Thread_Mutex and @a
42 : * ACE_Process_Mutex constructor API.
43 : */
44 : template <class ACE_LOCK>
45 : class Dynamic_Cached_Allocator_With_Overflow : public ACE_New_Allocator, public PoolAllocationBase {
46 : public:
47 : /// Create a cached memory pool with @a n_chunks chunks
48 : /// each with @a chunk_size size.
49 0 : Dynamic_Cached_Allocator_With_Overflow(size_t n_chunks, size_t chunk_size)
50 0 : : allocs_from_heap_(0),
51 0 : allocs_from_pool_(0),
52 0 : frees_to_heap_(0),
53 0 : frees_to_pool_(0),
54 0 : free_list_(ACE_PURE_FREE_LIST)
55 : {
56 0 : chunk_size_ = ACE_MALLOC_ROUNDUP(chunk_size, ACE_MALLOC_ALIGN);
57 0 : begin_ = static_cast<unsigned char*> (ACE_Allocator::instance()->malloc(n_chunks * chunk_size_));
58 : // Remember end of the pool.
59 0 : end_ = begin_ + n_chunks * chunk_size_;
60 :
61 : // Put into free list using placement contructor, no real memory
62 : // allocation in the <new> below.
63 0 : for (size_t c = 0;
64 0 : c < n_chunks;
65 : c++) {
66 0 : void* placement = begin_ + c * chunk_size_;
67 :
68 0 : free_list_.add(new(placement) ACE_Cached_Mem_Pool_Node<char>);
69 : }
70 0 : }
71 :
72 : /// Clear things up.
73 0 : ~Dynamic_Cached_Allocator_With_Overflow() {
74 0 : ACE_Allocator::instance()->free(begin_);
75 0 : begin_ = 0;
76 0 : chunk_size_ = 0;
77 0 : }
78 :
79 : /**
80 : * Get a chunk of memory from free list cache. Note that @a nbytes is
81 : * only checked to make sure that it's less or equal to @a chunk_size,
82 : * and is otherwise ignored since malloc() always returns a pointer to an
83 : * item of @a chunk_size size.
84 : */
85 0 : void *malloc(size_t nbytes = 0) {
86 : // Check if size requested fits within pre-determined size.
87 0 : if (nbytes > chunk_size_)
88 0 : return 0;
89 :
90 : // addr() call is really not absolutely necessary because of the way
91 : // ACE_Cached_Mem_Pool_Node's internal structure arranged.
92 0 : void* rtn = free_list_.remove()->addr();
93 :
94 0 : if (0 == rtn) {
95 0 : rtn = ACE_Allocator::instance()->malloc(chunk_size_);
96 0 : allocs_from_heap_++;
97 :
98 0 : if (DCPS_debug_level >= 2) {
99 0 : if (allocs_from_heap_ == 1 && DCPS_debug_level >= 2)
100 0 : ACE_DEBUG((LM_DEBUG,
101 : "(%P|%t) Dynamic_Cached_Allocator_With_Overflow::malloc %x"
102 : " %d heap allocs with %d outstanding\n",
103 : this, allocs_from_heap_.load(),
104 : allocs_from_heap_.load() - frees_to_heap_.load()));
105 :
106 0 : if (DCPS_debug_level >= 6)
107 0 : if (allocs_from_heap_ % 500 == 0)
108 0 : ACE_DEBUG((LM_DEBUG,
109 : "(%P|%t) Dynamic_Cached_Allocator_With_Overflow::malloc %@"
110 : " %Lu heap allocs with %Lu outstanding\n",
111 : this, allocs_from_heap_.load(),
112 : allocs_from_heap_.load() - frees_to_heap_.load()));
113 : }
114 :
115 : } else {
116 0 : allocs_from_pool_++;
117 :
118 0 : if (DCPS_debug_level >= 6)
119 0 : if (allocs_from_pool_ % 500 == 0)
120 0 : ACE_DEBUG((LM_DEBUG,
121 : "(%P|%t) Dynamic_Cached_Allocator_With_Overflow::malloc %x"
122 : " %d pool allocs %d pool free with %d available\n",
123 : this, allocs_from_pool_.load(),
124 : frees_to_pool_.load(),
125 : available()));
126 : }
127 :
128 0 : return rtn;
129 : }
130 :
131 : /**
132 : * Get a chunk of memory from free list cache, giving them
133 : * @a initial_value. Note that @a nbytes is only checked to make sure
134 : * that it's less or equal to @a chunk_size, and is otherwise ignored
135 : * since calloc() always returns a pointer to an item of @a chunk_size.
136 : */
137 0 : virtual void *calloc(size_t /* nbytes */,
138 : char /* initial_value */ = '\0') {
139 0 : ACE_NOTSUP_RETURN(0);
140 : }
141 :
142 : /// This method is a no-op and just returns 0 since the free list
143 : /// only works with fixed sized entities.
144 0 : virtual void *calloc(size_t /* n_elem */,
145 : size_t /* elem_size */,
146 : char /* initial_value */ = '\0') {
147 0 : ACE_NOTSUP_RETURN(0);
148 : }
149 :
150 : /// Return a chunk of memory back to free list cache.
151 0 : void free(void * ptr) {
152 0 : unsigned char* tmp = static_cast<unsigned char*> (ptr);
153 0 : if (tmp < begin_ ||
154 0 : tmp >= end_) {
155 0 : ACE_Allocator::instance()->free(tmp);
156 0 : frees_to_heap_ ++;
157 :
158 0 : if (frees_to_heap_ > allocs_from_heap_) {
159 0 : ACE_ERROR((LM_ERROR,
160 : "(%P|%t) ERROR: Dynamic_Cached_Allocator_With_Overflow::free %x"
161 : " more deletes %d than allocs %d to the heap\n",
162 : this,
163 : frees_to_heap_.load(),
164 : allocs_from_heap_.load()));
165 : }
166 :
167 0 : if (DCPS_debug_level >= 6) {
168 0 : if (frees_to_heap_ % 500 == 0) {
169 0 : ACE_DEBUG((LM_DEBUG,
170 : "(%P|%t) Dynamic_Cached_Allocator_With_Overflow::free %@"
171 : " %Lu heap allocs with %Lu outstanding\n",
172 : this, allocs_from_heap_.load(),
173 : allocs_from_heap_.load() - frees_to_heap_.load()));
174 : }
175 : }
176 :
177 0 : return;
178 :
179 0 : } else if (ptr != 0) {
180 0 : frees_to_pool_ ++;
181 :
182 0 : if (frees_to_pool_ > allocs_from_pool_) {
183 0 : ACE_ERROR((LM_ERROR,
184 : "(%P|%t) ERROR: Dynamic_Cached_Allocator_With_Overflow::free %x"
185 : " more deletes %d than allocs %d from the pool\n",
186 : this,
187 : frees_to_pool_.load(),
188 : allocs_from_pool_.load()));
189 : }
190 :
191 0 : free_list_.add((ACE_Cached_Mem_Pool_Node<char> *) ptr) ;
192 :
193 0 : if (DCPS_debug_level >= 6)
194 0 : if (available() % 500 == 0)
195 0 : ACE_DEBUG((LM_DEBUG,
196 : "(%P|%t) Dynamic_Cached_Allocator_With_Overflow::malloc %x"
197 : " %d pool allocs %d pool frees with %d available\n",
198 : this, allocs_from_pool_.load(), frees_to_pool_.load(),
199 : available()));
200 : }
201 : }
202 :
203 : /// Return the number of chunks available in the cache.
204 : size_t pool_depth() {
205 : return free_list_.size() ;
206 : }
207 :
208 : // -- for debug
209 :
210 : /** How many chunks are available at this time.
211 : */
212 0 : size_t available() {
213 0 : return free_list_.size();
214 : };
215 :
216 : /// number of allocations from the heap.
217 : Atomic<unsigned long> allocs_from_heap_;
218 : /// number of allocations from the pool.
219 : Atomic<unsigned long> allocs_from_pool_;
220 : /// number of frees returned to the heap
221 : Atomic<unsigned long> frees_to_heap_ ;
222 : /// number of frees returned to the pool
223 : Atomic<unsigned long> frees_to_pool_;
224 : private:
225 : /// Remember how we allocate the memory in the first place so
226 : /// we can clear things up later.
227 : unsigned char* begin_;
228 : /// The end of the pool.
229 : unsigned char* end_;
230 :
231 : /// Maintain a cached memory free list. We use @c char as template
232 : /// parameter, although sizeof(char) is usually less than
233 : /// sizeof(void*). Really important is that @a chunk_size
234 : /// must be greater or equal to sizeof(void*).
235 : ACE_Locked_Free_List<ACE_Cached_Mem_Pool_Node<char>, ACE_LOCK> free_list_;
236 :
237 : /// Remember the size of our chunks.
238 : size_t chunk_size_;
239 : };
240 :
241 : } // namespace DCPS
242 : } // namespace OpenDDS
243 :
244 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
245 :
246 : #endif /* DYNAMIC_CACHED_ALLOCATOR_WITH_OVERFLOW_T_H */
|