]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/mem/Pool.cc
2 * Copyright (C) 1996-2022 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 * AUTHOR: Alex Rousskov, Andres Kroonmaa, Robert Collins
14 #include "mem/PoolChunked.h"
15 #include "mem/PoolMalloc.h"
20 #define FLUSH_LIMIT 1000 /* Flush memPool counters to memMeters after flush limit calls */
22 extern time_t squid_curtime
;
24 static MemPoolMeter TheMeter
;
25 static MemPoolIterator Iterator
;
26 static int Pool_id_counter
= 0;
29 MemPools::GetInstance()
31 // We must initialize on first use (which may happen during static
32 // initialization) and preserve until the last user is gone (which
33 // may happen long after main() exit). We currently preserve forever.
34 static MemPools
*Instance
= new MemPools
;
41 Iterator
.pool
= MemPools::GetInstance().pools
;
46 memPoolIterateDone(MemPoolIterator
** iter
)
48 assert(iter
!= nullptr);
49 Iterator
.pool
= nullptr;
53 MemImplementingAllocator
*
54 memPoolIterateNext(MemPoolIterator
* iter
)
56 MemImplementingAllocator
*pool
;
57 assert(iter
!= nullptr);
63 iter
->pool
= pool
->next
;
68 MemPools::setIdleLimit(ssize_t new_idle_limit
)
70 mem_idle_limit
= new_idle_limit
;
74 MemPools::idleLimit() const
76 return mem_idle_limit
;
79 /* Change the default value of defaultIsChunked to override
80 * all pools - including those used before main() starts where
81 * MemPools::GetInstance().setDefaultPoolChunking() can be called.
85 if (char *cfg
= getenv("MEMPOOLS"))
86 defaultIsChunked
= atoi(cfg
);
89 MemImplementingAllocator
*
90 MemPools::create(const char *label
, size_t obj_size
)
94 return new MemPoolChunked (label
, obj_size
);
96 return new MemPoolMalloc (label
, obj_size
);
100 MemPools::setDefaultPoolChunking(bool const &aBool
)
102 defaultIsChunked
= aBool
;
106 MemAllocator::objectType() const
112 MemAllocator::inUseCount()
114 return getInUseCount();
118 MemImplementingAllocator::flushMeters()
124 meter
.gb_freed
.count
+= calls
;
129 meter
.gb_allocated
.count
+= calls
;
134 meter
.gb_saved
.count
+= calls
;
140 MemImplementingAllocator::flushMetersFull()
143 getMeter().gb_allocated
.bytes
= getMeter().gb_allocated
.count
* obj_size
;
144 getMeter().gb_saved
.bytes
= getMeter().gb_saved
.count
* obj_size
;
145 getMeter().gb_freed
.bytes
= getMeter().gb_freed
.count
* obj_size
;
149 MemPoolMeter::flush()
154 gb_allocated
.count
= 0;
155 gb_allocated
.bytes
= 0;
156 gb_oallocated
.count
= 0;
157 gb_oallocated
.bytes
= 0;
164 MemPoolMeter::MemPoolMeter()
170 * Updates all pool counters, and recreates TheMeter totals from all pools
173 MemPools::flushMeters()
177 MemPoolIterator
*iter
= memPoolIterate();
178 while (MemImplementingAllocator
*pool
= memPoolIterateNext(iter
)) {
179 pool
->flushMetersFull();
180 // are these TheMeter grow() operations or accumulated volumes ?
181 TheMeter
.alloc
+= pool
->getMeter().alloc
.currentLevel() * pool
->obj_size
;
182 TheMeter
.inuse
+= pool
->getMeter().inuse
.currentLevel() * pool
->obj_size
;
183 TheMeter
.idle
+= pool
->getMeter().idle
.currentLevel() * pool
->obj_size
;
185 TheMeter
.gb_allocated
.count
+= pool
->getMeter().gb_allocated
.count
;
186 TheMeter
.gb_saved
.count
+= pool
->getMeter().gb_saved
.count
;
187 TheMeter
.gb_freed
.count
+= pool
->getMeter().gb_freed
.count
;
188 TheMeter
.gb_allocated
.bytes
+= pool
->getMeter().gb_allocated
.bytes
;
189 TheMeter
.gb_saved
.bytes
+= pool
->getMeter().gb_saved
.bytes
;
190 TheMeter
.gb_freed
.bytes
+= pool
->getMeter().gb_freed
.bytes
;
192 memPoolIterateDone(&iter
);
196 MemImplementingAllocator::alloc()
198 if (++alloc_calls
== FLUSH_LIMIT
)
205 MemImplementingAllocator::freeOne(void *obj
)
207 assert(obj
!= nullptr);
208 (void) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(obj
, obj_size
);
209 deallocate(obj
, MemPools::GetInstance().mem_idle_limit
== 0);
214 * Returns all cached frees to their home chunks
215 * If chunks unreferenced age is over, destroys Idle chunk
216 * Flushes meters for a pool
217 * If pool is not specified, iterates through all pools.
218 * When used for all pools, if new_idle_limit is above -1, new
219 * idle memory limit is set before Cleanup. This allows to shrink
220 * memPool memory usage to specified minimum.
223 MemPools::clean(time_t maxage
)
226 if (mem_idle_limit
< 0) // no limit to enforce
230 if (TheMeter
.idle
.currentLevel() > mem_idle_limit
)
233 MemImplementingAllocator
*pool
;
234 MemPoolIterator
*iter
;
235 iter
= memPoolIterate();
236 while ((pool
= memPoolIterateNext(iter
)))
237 if (pool
->idleTrigger(shift
))
239 memPoolIterateDone(&iter
);
242 /* Persistent Pool stats. for GlobalStats accumulation */
243 static MemPoolStats pp_stats
;
246 * Totals statistics is returned
249 memPoolGetGlobalStats(MemPoolGlobalStats
* stats
)
253 MemPoolIterator
*iter
;
255 memset(stats
, 0, sizeof(MemPoolGlobalStats
));
256 memset(&pp_stats
, 0, sizeof(MemPoolStats
));
258 MemPools::GetInstance().flushMeters(); /* recreate TheMeter */
260 /* gather all stats for Totals */
261 iter
= memPoolIterate();
262 while ((pool
= memPoolIterateNext(iter
))) {
263 if (pool
->getStats(&pp_stats
, 1) > 0)
266 memPoolIterateDone(&iter
);
268 stats
->TheMeter
= &TheMeter
;
270 stats
->tot_pools_alloc
= MemPools::GetInstance().poolCount
;
271 stats
->tot_pools_inuse
= pools_inuse
;
272 stats
->tot_pools_mempid
= Pool_id_counter
;
274 stats
->tot_chunks_alloc
= pp_stats
.chunks_alloc
;
275 stats
->tot_chunks_inuse
= pp_stats
.chunks_inuse
;
276 stats
->tot_chunks_partial
= pp_stats
.chunks_partial
;
277 stats
->tot_chunks_free
= pp_stats
.chunks_free
;
278 stats
->tot_items_alloc
= pp_stats
.items_alloc
;
279 stats
->tot_items_inuse
= pp_stats
.items_inuse
;
280 stats
->tot_items_idle
= pp_stats
.items_idle
;
282 stats
->tot_overhead
+= pp_stats
.overhead
+ MemPools::GetInstance().poolCount
* sizeof(MemAllocator
*);
283 stats
->mem_idle_limit
= MemPools::GetInstance().mem_idle_limit
;
288 MemAllocator::MemAllocator(char const *aLabel
) : doZero(true), label(aLabel
)
292 size_t MemAllocator::RoundedSize(size_t s
)
294 return ((s
+ sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*);
298 memPoolsTotalAllocated(void)
300 MemPoolGlobalStats stats
;
301 memPoolGetGlobalStats(&stats
);
302 return stats
.TheMeter
->alloc
.currentLevel();
305 MemImplementingAllocator::MemImplementingAllocator(char const *aLabel
, size_t aSize
) : MemAllocator(aLabel
),
310 obj_size(RoundedSize(aSize
))
312 memPID
= ++Pool_id_counter
;
314 MemImplementingAllocator
*last_pool
;
316 assert(aLabel
!= nullptr && aSize
);
318 for (last_pool
= MemPools::GetInstance().pools
; last_pool
&& last_pool
->next
;)
319 last_pool
= last_pool
->next
;
321 last_pool
->next
= this;
323 MemPools::GetInstance().pools
= this;
326 MemImplementingAllocator::~MemImplementingAllocator()
328 MemImplementingAllocator
*find_pool
, *prev_pool
;
330 /* Abort if the associated pool doesn't exist */
331 assert(MemPools::GetInstance().pools
!= nullptr );
333 /* Pool clean, remove it from List and free */
334 for (find_pool
= MemPools::GetInstance().pools
, prev_pool
= nullptr; (find_pool
&& this != find_pool
); find_pool
= find_pool
->next
)
335 prev_pool
= find_pool
;
337 /* make sure that we found the pool to destroy */
338 assert(find_pool
!= nullptr);
341 prev_pool
->next
= next
;
343 MemPools::GetInstance().pools
= next
;
344 --MemPools::GetInstance().poolCount
;
348 MemImplementingAllocator::getMeter() const
354 MemImplementingAllocator::getMeter()
360 MemImplementingAllocator::objectSize() const