]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/MemPool.cc
31be72e2d7b0093d4e30a8fd2fa42fba8cf032bb
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
10 * DEBUG: section 63 Low Level Memory Pool Management
11 * AUTHOR: Alex Rousskov, Andres Kroonmaa, Robert Collins
19 #include "MemPoolChunked.h"
20 #include "MemPoolMalloc.h"
22 #define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */
27 * XXX This is a boundary violation between lib and src.. would be good
28 * if it could be solved otherwise, but left for now.
30 extern time_t squid_curtime
;
33 static MemPoolMeter TheMeter
;
34 static MemPoolIterator Iterator
;
36 static int Pool_id_counter
= 0;
39 MemPools::GetInstance()
41 /* Must use this idiom, as we can be double-initialised
42 * if we are called during static initialisations.
45 Instance
= new MemPools
;
49 MemPools
* MemPools::Instance
= NULL
;
54 Iterator
.pool
= MemPools::GetInstance().pools
;
59 memPoolIterateDone(MemPoolIterator
** iter
)
66 MemImplementingAllocator
*
67 memPoolIterateNext(MemPoolIterator
* iter
)
69 MemImplementingAllocator
*pool
;
76 iter
->pool
= pool
->next
;
81 MemPools::setIdleLimit(ssize_t new_idle_limit
)
83 mem_idle_limit
= new_idle_limit
;
87 MemPools::idleLimit() const
89 return mem_idle_limit
;
92 /* Change the default calue of defaultIsChunked to override
93 * all pools - including those used before main() starts where
94 * MemPools::GetInstance().setDefaultPoolChunking() can be called.
96 MemPools::MemPools() : pools(NULL
), mem_idle_limit(2 << 20 /* 2 MB */),
97 poolCount(0), defaultIsChunked(USE_CHUNKEDMEMPOOLS
&& !RUNNING_ON_VALGRIND
)
99 char *cfg
= getenv("MEMPOOLS");
101 defaultIsChunked
= atoi(cfg
);
104 MemImplementingAllocator
*
105 MemPools::create(const char *label
, size_t obj_size
)
108 if (defaultIsChunked
)
109 return new MemPoolChunked (label
, obj_size
);
111 return new MemPoolMalloc (label
, obj_size
);
115 MemPools::setDefaultPoolChunking(bool const &aBool
)
117 defaultIsChunked
= aBool
;
121 MemAllocator::objectType() const
127 MemAllocator::inUseCount()
129 return getInUseCount();
133 MemImplementingAllocator::flushMeters()
139 meter
.gb_freed
.count
+= calls
;
144 meter
.gb_allocated
.count
+= calls
;
149 meter
.gb_saved
.count
+= calls
;
155 MemImplementingAllocator::flushMetersFull()
158 getMeter().gb_allocated
.bytes
= getMeter().gb_allocated
.count
* obj_size
;
159 getMeter().gb_saved
.bytes
= getMeter().gb_saved
.count
* obj_size
;
160 getMeter().gb_freed
.bytes
= getMeter().gb_freed
.count
* obj_size
;
164 MemPoolMeter::flush()
169 gb_allocated
.count
= 0;
170 gb_allocated
.bytes
= 0;
171 gb_oallocated
.count
= 0;
172 gb_oallocated
.bytes
= 0;
179 MemPoolMeter::MemPoolMeter()
185 * Updates all pool counters, and recreates TheMeter totals from all pools
188 MemPools::flushMeters()
190 MemImplementingAllocator
*pool
;
191 MemPoolIterator
*iter
;
195 iter
= memPoolIterate();
196 while ((pool
= memPoolIterateNext(iter
))) {
197 pool
->flushMetersFull();
198 memMeterAdd(TheMeter
.alloc
, pool
->getMeter().alloc
.level
* pool
->obj_size
);
199 memMeterAdd(TheMeter
.inuse
, pool
->getMeter().inuse
.level
* pool
->obj_size
);
200 memMeterAdd(TheMeter
.idle
, pool
->getMeter().idle
.level
* pool
->obj_size
);
201 TheMeter
.gb_allocated
.count
+= pool
->getMeter().gb_allocated
.count
;
202 TheMeter
.gb_saved
.count
+= pool
->getMeter().gb_saved
.count
;
203 TheMeter
.gb_freed
.count
+= pool
->getMeter().gb_freed
.count
;
204 TheMeter
.gb_allocated
.bytes
+= pool
->getMeter().gb_allocated
.bytes
;
205 TheMeter
.gb_saved
.bytes
+= pool
->getMeter().gb_saved
.bytes
;
206 TheMeter
.gb_freed
.bytes
+= pool
->getMeter().gb_freed
.bytes
;
208 memPoolIterateDone(&iter
);
212 MemImplementingAllocator::alloc()
214 if (++alloc_calls
== FLUSH_LIMIT
)
221 MemImplementingAllocator::freeOne(void *obj
)
224 (void) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(obj
, obj_size
);
225 deallocate(obj
, MemPools::GetInstance().mem_idle_limit
== 0);
230 * Returns all cached frees to their home chunks
231 * If chunks unreferenced age is over, destroys Idle chunk
232 * Flushes meters for a pool
233 * If pool is not specified, iterates through all pools.
234 * When used for all pools, if new_idle_limit is above -1, new
235 * idle memory limit is set before Cleanup. This allows to shrink
236 * memPool memory usage to specified minimum.
239 MemPools::clean(time_t maxage
)
242 if (mem_idle_limit
< 0) // no limit to enforce
246 if (TheMeter
.idle
.level
> mem_idle_limit
)
249 MemImplementingAllocator
*pool
;
250 MemPoolIterator
*iter
;
251 iter
= memPoolIterate();
252 while ((pool
= memPoolIterateNext(iter
)))
253 if (pool
->idleTrigger(shift
))
255 memPoolIterateDone(&iter
);
258 /* Persistent Pool stats. for GlobalStats accumulation */
259 static MemPoolStats pp_stats
;
262 * Totals statistics is returned
265 memPoolGetGlobalStats(MemPoolGlobalStats
* stats
)
269 MemPoolIterator
*iter
;
271 memset(stats
, 0, sizeof(MemPoolGlobalStats
));
272 memset(&pp_stats
, 0, sizeof(MemPoolStats
));
274 MemPools::GetInstance().flushMeters(); /* recreate TheMeter */
276 /* gather all stats for Totals */
277 iter
= memPoolIterate();
278 while ((pool
= memPoolIterateNext(iter
))) {
279 if (pool
->getStats(&pp_stats
, 1) > 0)
282 memPoolIterateDone(&iter
);
284 stats
->TheMeter
= &TheMeter
;
286 stats
->tot_pools_alloc
= MemPools::GetInstance().poolCount
;
287 stats
->tot_pools_inuse
= pools_inuse
;
288 stats
->tot_pools_mempid
= Pool_id_counter
;
290 stats
->tot_chunks_alloc
= pp_stats
.chunks_alloc
;
291 stats
->tot_chunks_inuse
= pp_stats
.chunks_inuse
;
292 stats
->tot_chunks_partial
= pp_stats
.chunks_partial
;
293 stats
->tot_chunks_free
= pp_stats
.chunks_free
;
294 stats
->tot_items_alloc
= pp_stats
.items_alloc
;
295 stats
->tot_items_inuse
= pp_stats
.items_inuse
;
296 stats
->tot_items_idle
= pp_stats
.items_idle
;
298 stats
->tot_overhead
+= pp_stats
.overhead
+ MemPools::GetInstance().poolCount
* sizeof(MemAllocator
*);
299 stats
->mem_idle_limit
= MemPools::GetInstance().mem_idle_limit
;
304 MemAllocator::MemAllocator(char const *aLabel
) : doZero(true), label(aLabel
)
308 size_t MemAllocator::RoundedSize(size_t s
)
310 return ((s
+ sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*);
314 memPoolInUseCount(MemAllocator
* pool
)
316 return pool
->inUseCount();
320 memPoolsTotalAllocated(void)
322 MemPoolGlobalStats stats
;
323 memPoolGetGlobalStats(&stats
);
324 return stats
.TheMeter
->alloc
.level
;
328 MemAllocatorProxy::alloc()
330 return getAllocator()->alloc();
334 MemAllocatorProxy::freeOne(void *address
)
336 getAllocator()->freeOne(address
);
337 /* TODO: check for empty, and if so, if the default type has altered,
343 MemAllocatorProxy::getAllocator() const
346 theAllocator
= MemPools::GetInstance().create(objectType(), size
);
351 MemAllocatorProxy::inUseCount() const
356 return memPoolInUseCount(theAllocator
);
360 MemAllocatorProxy::objectSize() const
366 MemAllocatorProxy::objectType() const
372 MemAllocatorProxy::getMeter() const
374 return getAllocator()->getMeter();
378 MemAllocatorProxy::getStats(MemPoolStats
* stats
)
380 return getAllocator()->getStats(stats
);
383 MemImplementingAllocator::MemImplementingAllocator(char const *aLabel
, size_t aSize
) : MemAllocator(aLabel
),
388 obj_size(RoundedSize(aSize
))
390 memPID
= ++Pool_id_counter
;
392 MemImplementingAllocator
*last_pool
;
394 assert(aLabel
!= NULL
&& aSize
);
396 for (last_pool
= MemPools::GetInstance().pools
; last_pool
&& last_pool
->next
;)
397 last_pool
= last_pool
->next
;
399 last_pool
->next
= this;
401 MemPools::GetInstance().pools
= this;
404 MemImplementingAllocator::~MemImplementingAllocator()
406 MemImplementingAllocator
*find_pool
, *prev_pool
;
408 /* Abort if the associated pool doesn't exist */
409 assert(MemPools::GetInstance().pools
!= NULL
);
411 /* Pool clean, remove it from List and free */
412 for (find_pool
= MemPools::GetInstance().pools
, prev_pool
= NULL
; (find_pool
&& this != find_pool
); find_pool
= find_pool
->next
)
413 prev_pool
= find_pool
;
415 /* make sure that we found the pool to destroy */
416 assert(find_pool
!= NULL
);
419 prev_pool
->next
= next
;
421 MemPools::GetInstance().pools
= next
;
422 --MemPools::GetInstance().poolCount
;
426 MemImplementingAllocator::getMeter() const
432 MemImplementingAllocator::getMeter()
438 MemImplementingAllocator::objectSize() const