]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mem/Pool.cc
2 * Copyright (C) 1996-2017 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 calue of defaultIsChunked to override
81 * all pools - including those used before main() starts where
82 * MemPools::GetInstance().setDefaultPoolChunking() can be called.
84 MemPools::MemPools() : pools(NULL
), mem_idle_limit(2 << 20 /* 2 MB */),
85 poolCount(0), defaultIsChunked(USE_CHUNKEDMEMPOOLS
&& !RUNNING_ON_VALGRIND
)
87 char *cfg
= getenv("MEMPOOLS");
89 defaultIsChunked
= atoi(cfg
);
92 MemImplementingAllocator
*
93 MemPools::create(const char *label
, size_t obj_size
)
97 return new MemPoolChunked (label
, obj_size
);
99 return new MemPoolMalloc (label
, obj_size
);
103 MemPools::setDefaultPoolChunking(bool const &aBool
)
105 defaultIsChunked
= aBool
;
109 MemAllocator::objectType() const
115 MemAllocator::inUseCount()
117 return getInUseCount();
121 MemImplementingAllocator::flushMeters()
127 meter
.gb_freed
.count
+= calls
;
132 meter
.gb_allocated
.count
+= calls
;
137 meter
.gb_saved
.count
+= calls
;
143 MemImplementingAllocator::flushMetersFull()
146 getMeter().gb_allocated
.bytes
= getMeter().gb_allocated
.count
* obj_size
;
147 getMeter().gb_saved
.bytes
= getMeter().gb_saved
.count
* obj_size
;
148 getMeter().gb_freed
.bytes
= getMeter().gb_freed
.count
* obj_size
;
152 MemPoolMeter::flush()
157 gb_allocated
.count
= 0;
158 gb_allocated
.bytes
= 0;
159 gb_oallocated
.count
= 0;
160 gb_oallocated
.bytes
= 0;
167 MemPoolMeter::MemPoolMeter()
173 * Updates all pool counters, and recreates TheMeter totals from all pools
176 MemPools::flushMeters()
180 MemPoolIterator
*iter
= memPoolIterate();
181 while (MemImplementingAllocator
*pool
= memPoolIterateNext(iter
)) {
182 pool
->flushMetersFull();
183 // are these TheMeter grow() operations or accumulated volumes ?
184 TheMeter
.alloc
+= pool
->getMeter().alloc
.currentLevel() * pool
->obj_size
;
185 TheMeter
.inuse
+= pool
->getMeter().inuse
.currentLevel() * pool
->obj_size
;
186 TheMeter
.idle
+= pool
->getMeter().idle
.currentLevel() * pool
->obj_size
;
188 TheMeter
.gb_allocated
.count
+= pool
->getMeter().gb_allocated
.count
;
189 TheMeter
.gb_saved
.count
+= pool
->getMeter().gb_saved
.count
;
190 TheMeter
.gb_freed
.count
+= pool
->getMeter().gb_freed
.count
;
191 TheMeter
.gb_allocated
.bytes
+= pool
->getMeter().gb_allocated
.bytes
;
192 TheMeter
.gb_saved
.bytes
+= pool
->getMeter().gb_saved
.bytes
;
193 TheMeter
.gb_freed
.bytes
+= pool
->getMeter().gb_freed
.bytes
;
195 memPoolIterateDone(&iter
);
199 MemImplementingAllocator::alloc()
201 if (++alloc_calls
== FLUSH_LIMIT
)
208 MemImplementingAllocator::freeOne(void *obj
)
211 (void) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(obj
, obj_size
);
212 deallocate(obj
, MemPools::GetInstance().mem_idle_limit
== 0);
217 * Returns all cached frees to their home chunks
218 * If chunks unreferenced age is over, destroys Idle chunk
219 * Flushes meters for a pool
220 * If pool is not specified, iterates through all pools.
221 * When used for all pools, if new_idle_limit is above -1, new
222 * idle memory limit is set before Cleanup. This allows to shrink
223 * memPool memory usage to specified minimum.
226 MemPools::clean(time_t maxage
)
229 if (mem_idle_limit
< 0) // no limit to enforce
233 if (TheMeter
.idle
.currentLevel() > mem_idle_limit
)
236 MemImplementingAllocator
*pool
;
237 MemPoolIterator
*iter
;
238 iter
= memPoolIterate();
239 while ((pool
= memPoolIterateNext(iter
)))
240 if (pool
->idleTrigger(shift
))
242 memPoolIterateDone(&iter
);
245 /* Persistent Pool stats. for GlobalStats accumulation */
246 static MemPoolStats pp_stats
;
249 * Totals statistics is returned
252 memPoolGetGlobalStats(MemPoolGlobalStats
* stats
)
256 MemPoolIterator
*iter
;
258 memset(stats
, 0, sizeof(MemPoolGlobalStats
));
259 memset(&pp_stats
, 0, sizeof(MemPoolStats
));
261 MemPools::GetInstance().flushMeters(); /* recreate TheMeter */
263 /* gather all stats for Totals */
264 iter
= memPoolIterate();
265 while ((pool
= memPoolIterateNext(iter
))) {
266 if (pool
->getStats(&pp_stats
, 1) > 0)
269 memPoolIterateDone(&iter
);
271 stats
->TheMeter
= &TheMeter
;
273 stats
->tot_pools_alloc
= MemPools::GetInstance().poolCount
;
274 stats
->tot_pools_inuse
= pools_inuse
;
275 stats
->tot_pools_mempid
= Pool_id_counter
;
277 stats
->tot_chunks_alloc
= pp_stats
.chunks_alloc
;
278 stats
->tot_chunks_inuse
= pp_stats
.chunks_inuse
;
279 stats
->tot_chunks_partial
= pp_stats
.chunks_partial
;
280 stats
->tot_chunks_free
= pp_stats
.chunks_free
;
281 stats
->tot_items_alloc
= pp_stats
.items_alloc
;
282 stats
->tot_items_inuse
= pp_stats
.items_inuse
;
283 stats
->tot_items_idle
= pp_stats
.items_idle
;
285 stats
->tot_overhead
+= pp_stats
.overhead
+ MemPools::GetInstance().poolCount
* sizeof(MemAllocator
*);
286 stats
->mem_idle_limit
= MemPools::GetInstance().mem_idle_limit
;
291 MemAllocator::MemAllocator(char const *aLabel
) : doZero(true), label(aLabel
)
295 size_t MemAllocator::RoundedSize(size_t s
)
297 return ((s
+ sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*);
301 memPoolsTotalAllocated(void)
303 MemPoolGlobalStats stats
;
304 memPoolGetGlobalStats(&stats
);
305 return stats
.TheMeter
->alloc
.currentLevel();
308 MemImplementingAllocator::MemImplementingAllocator(char const *aLabel
, size_t aSize
) : MemAllocator(aLabel
),
313 obj_size(RoundedSize(aSize
))
315 memPID
= ++Pool_id_counter
;
317 MemImplementingAllocator
*last_pool
;
319 assert(aLabel
!= NULL
&& aSize
);
321 for (last_pool
= MemPools::GetInstance().pools
; last_pool
&& last_pool
->next
;)
322 last_pool
= last_pool
->next
;
324 last_pool
->next
= this;
326 MemPools::GetInstance().pools
= this;
329 MemImplementingAllocator::~MemImplementingAllocator()
331 MemImplementingAllocator
*find_pool
, *prev_pool
;
333 /* Abort if the associated pool doesn't exist */
334 assert(MemPools::GetInstance().pools
!= NULL
);
336 /* Pool clean, remove it from List and free */
337 for (find_pool
= MemPools::GetInstance().pools
, prev_pool
= NULL
; (find_pool
&& this != find_pool
); find_pool
= find_pool
->next
)
338 prev_pool
= find_pool
;
340 /* make sure that we found the pool to destroy */
341 assert(find_pool
!= NULL
);
344 prev_pool
->next
= next
;
346 MemPools::GetInstance().pools
= next
;
347 --MemPools::GetInstance().poolCount
;
351 MemImplementingAllocator::getMeter() const
357 MemImplementingAllocator::getMeter()
363 MemImplementingAllocator::objectSize() const