]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mem/Pool.cc
2bb40647a10919b1319029ed558304b2cb0a5da0
2 * Copyright (C) 1996-2018 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
15 #include "mem/PoolChunked.h"
16 #include "mem/PoolMalloc.h"
21 #define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */
23 extern time_t squid_curtime
;
25 static MemPoolMeter TheMeter
;
26 static MemPoolIterator Iterator
;
27 static int Pool_id_counter
= 0;
30 MemPools::GetInstance()
32 // We must initialize on first use (which may happen during static
33 // initialization) and preserve until the last user is gone (which
34 // may happen long after main() exit). We currently preserve forever.
35 static MemPools
*Instance
= new MemPools
;
42 Iterator
.pool
= MemPools::GetInstance().pools
;
47 memPoolIterateDone(MemPoolIterator
** iter
)
54 MemImplementingAllocator
*
55 memPoolIterateNext(MemPoolIterator
* iter
)
57 MemImplementingAllocator
*pool
;
64 iter
->pool
= pool
->next
;
69 MemPools::setIdleLimit(ssize_t new_idle_limit
)
71 mem_idle_limit
= new_idle_limit
;
75 MemPools::idleLimit() const
77 return mem_idle_limit
;
80 /* Change the default value of defaultIsChunked to override
81 * all pools - including those used before main() starts where
82 * MemPools::GetInstance().setDefaultPoolChunking() can be called.
86 if (char *cfg
= getenv("MEMPOOLS"))
87 defaultIsChunked
= atoi(cfg
);
90 MemImplementingAllocator
*
91 MemPools::create(const char *label
, size_t obj_size
)
95 return new MemPoolChunked (label
, obj_size
);
97 return new MemPoolMalloc (label
, obj_size
);
101 MemPools::setDefaultPoolChunking(bool const &aBool
)
103 defaultIsChunked
= aBool
;
107 MemAllocator::objectType() const
113 MemAllocator::inUseCount()
115 return getInUseCount();
119 MemImplementingAllocator::flushMeters()
125 meter
.gb_freed
.count
+= calls
;
130 meter
.gb_allocated
.count
+= calls
;
135 meter
.gb_saved
.count
+= calls
;
141 MemImplementingAllocator::flushMetersFull()
144 getMeter().gb_allocated
.bytes
= getMeter().gb_allocated
.count
* obj_size
;
145 getMeter().gb_saved
.bytes
= getMeter().gb_saved
.count
* obj_size
;
146 getMeter().gb_freed
.bytes
= getMeter().gb_freed
.count
* obj_size
;
150 MemPoolMeter::flush()
155 gb_allocated
.count
= 0;
156 gb_allocated
.bytes
= 0;
157 gb_oallocated
.count
= 0;
158 gb_oallocated
.bytes
= 0;
165 MemPoolMeter::MemPoolMeter()
171 * Updates all pool counters, and recreates TheMeter totals from all pools
174 MemPools::flushMeters()
178 MemPoolIterator
*iter
= memPoolIterate();
179 while (MemImplementingAllocator
*pool
= memPoolIterateNext(iter
)) {
180 pool
->flushMetersFull();
181 // are these TheMeter grow() operations or accumulated volumes ?
182 TheMeter
.alloc
+= pool
->getMeter().alloc
.currentLevel() * pool
->obj_size
;
183 TheMeter
.inuse
+= pool
->getMeter().inuse
.currentLevel() * pool
->obj_size
;
184 TheMeter
.idle
+= pool
->getMeter().idle
.currentLevel() * pool
->obj_size
;
186 TheMeter
.gb_allocated
.count
+= pool
->getMeter().gb_allocated
.count
;
187 TheMeter
.gb_saved
.count
+= pool
->getMeter().gb_saved
.count
;
188 TheMeter
.gb_freed
.count
+= pool
->getMeter().gb_freed
.count
;
189 TheMeter
.gb_allocated
.bytes
+= pool
->getMeter().gb_allocated
.bytes
;
190 TheMeter
.gb_saved
.bytes
+= pool
->getMeter().gb_saved
.bytes
;
191 TheMeter
.gb_freed
.bytes
+= pool
->getMeter().gb_freed
.bytes
;
193 memPoolIterateDone(&iter
);
197 MemImplementingAllocator::alloc()
199 if (++alloc_calls
== FLUSH_LIMIT
)
206 MemImplementingAllocator::freeOne(void *obj
)
209 (void) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(obj
, obj_size
);
210 deallocate(obj
, MemPools::GetInstance().mem_idle_limit
== 0);
215 * Returns all cached frees to their home chunks
216 * If chunks unreferenced age is over, destroys Idle chunk
217 * Flushes meters for a pool
218 * If pool is not specified, iterates through all pools.
219 * When used for all pools, if new_idle_limit is above -1, new
220 * idle memory limit is set before Cleanup. This allows to shrink
221 * memPool memory usage to specified minimum.
224 MemPools::clean(time_t maxage
)
227 if (mem_idle_limit
< 0) // no limit to enforce
231 if (TheMeter
.idle
.currentLevel() > mem_idle_limit
)
234 MemImplementingAllocator
*pool
;
235 MemPoolIterator
*iter
;
236 iter
= memPoolIterate();
237 while ((pool
= memPoolIterateNext(iter
)))
238 if (pool
->idleTrigger(shift
))
240 memPoolIterateDone(&iter
);
243 /* Persistent Pool stats. for GlobalStats accumulation */
244 static MemPoolStats pp_stats
;
247 * Totals statistics is returned
250 memPoolGetGlobalStats(MemPoolGlobalStats
* stats
)
254 MemPoolIterator
*iter
;
256 memset(stats
, 0, sizeof(MemPoolGlobalStats
));
257 memset(&pp_stats
, 0, sizeof(MemPoolStats
));
259 MemPools::GetInstance().flushMeters(); /* recreate TheMeter */
261 /* gather all stats for Totals */
262 iter
= memPoolIterate();
263 while ((pool
= memPoolIterateNext(iter
))) {
264 if (pool
->getStats(&pp_stats
, 1) > 0)
267 memPoolIterateDone(&iter
);
269 stats
->TheMeter
= &TheMeter
;
271 stats
->tot_pools_alloc
= MemPools::GetInstance().poolCount
;
272 stats
->tot_pools_inuse
= pools_inuse
;
273 stats
->tot_pools_mempid
= Pool_id_counter
;
275 stats
->tot_chunks_alloc
= pp_stats
.chunks_alloc
;
276 stats
->tot_chunks_inuse
= pp_stats
.chunks_inuse
;
277 stats
->tot_chunks_partial
= pp_stats
.chunks_partial
;
278 stats
->tot_chunks_free
= pp_stats
.chunks_free
;
279 stats
->tot_items_alloc
= pp_stats
.items_alloc
;
280 stats
->tot_items_inuse
= pp_stats
.items_inuse
;
281 stats
->tot_items_idle
= pp_stats
.items_idle
;
283 stats
->tot_overhead
+= pp_stats
.overhead
+ MemPools::GetInstance().poolCount
* sizeof(MemAllocator
*);
284 stats
->mem_idle_limit
= MemPools::GetInstance().mem_idle_limit
;
289 MemAllocator::MemAllocator(char const *aLabel
) : doZero(true), label(aLabel
)
293 size_t MemAllocator::RoundedSize(size_t s
)
295 return ((s
+ sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*);
299 memPoolsTotalAllocated(void)
301 MemPoolGlobalStats stats
;
302 memPoolGetGlobalStats(&stats
);
303 return stats
.TheMeter
->alloc
.currentLevel();
306 MemImplementingAllocator::MemImplementingAllocator(char const *aLabel
, size_t aSize
) : MemAllocator(aLabel
),
311 obj_size(RoundedSize(aSize
))
313 memPID
= ++Pool_id_counter
;
315 MemImplementingAllocator
*last_pool
;
317 assert(aLabel
!= NULL
&& aSize
);
319 for (last_pool
= MemPools::GetInstance().pools
; last_pool
&& last_pool
->next
;)
320 last_pool
= last_pool
->next
;
322 last_pool
->next
= this;
324 MemPools::GetInstance().pools
= this;
327 MemImplementingAllocator::~MemImplementingAllocator()
329 MemImplementingAllocator
*find_pool
, *prev_pool
;
331 /* Abort if the associated pool doesn't exist */
332 assert(MemPools::GetInstance().pools
!= NULL
);
334 /* Pool clean, remove it from List and free */
335 for (find_pool
= MemPools::GetInstance().pools
, prev_pool
= NULL
; (find_pool
&& this != find_pool
); find_pool
= find_pool
->next
)
336 prev_pool
= find_pool
;
338 /* make sure that we found the pool to destroy */
339 assert(find_pool
!= NULL
);
342 prev_pool
->next
= next
;
344 MemPools::GetInstance().pools
= next
;
345 --MemPools::GetInstance().poolCount
;
349 MemImplementingAllocator::getMeter() const
355 MemImplementingAllocator::getMeter()
361 MemImplementingAllocator::objectSize() const