]> git.ipfire.org Git - thirdparty/squid.git/blame - include/MemPool.h
Disable memory pools by default
[thirdparty/squid.git] / include / MemPool.h
CommitLineData
d96ceb8e 1#ifndef _MEM_POOLS_H_
2#define _MEM_POOLS_H_
3
63be0a78 4/**
5 \defgroup MemPoolsAPI Memory Management (Memory Pool Allocator)
6 \ingroup Components
7 *
8 *\par
9 * MemPools are a pooled memory allocator running on top of malloc(). It's
10 * purpose is to reduce memory fragmentation and provide detailed statistics
11 * on memory consumption.
12 *
13 \par
14 * Preferably all memory allocations in Squid should be done using MemPools
15 * or one of the types built on top of it (i.e. cbdata).
16 *
17 \note Usually it is better to use cbdata types as these gives you additional
18 * safeguards in references and typechecking. However, for high usage pools where
19 * the cbdata functionality of cbdata is not required directly using a MemPool
20 * might be the way to go.
21 */
22
d96ceb8e 23#include "config.h"
d96ceb8e 24#include "util.h"
83d8f9f4 25
d96ceb8e 26#include "memMeter.h"
b001e822 27#include "splay.h"
d96ceb8e 28
29#if HAVE_GNUMALLOC_H
30#include <gnumalloc.h>
482aa790 31#elif HAVE_MALLOC_H
d96ceb8e 32#include <malloc.h>
33#endif
34
35#if HAVE_MEMORY_H
36#include <memory.h>
37#endif
38
39#if !M_MMAP_MAX
40#if USE_DLMALLOC
41#define M_MMAP_MAX -4
42#endif
43#endif
44
63be0a78 45/// \ingroup MemPoolsAPI
d96ceb8e 46#define MB ((size_t)1024*1024)
63be0a78 47/// \ingroup MemPoolsAPI
d96ceb8e 48#define mem_unlimited_size 2 * 1024 * MB
63be0a78 49/// \ingroup MemPoolsAPI
d96ceb8e 50#define toMB(size) ( ((double) size) / MB )
63be0a78 51/// \ingroup MemPoolsAPI
d96ceb8e 52#define toKB(size) ( (size + 1024 - 1) / 1024 )
53
63be0a78 54/// \ingroup MemPoolsAPI
d96ceb8e 55#define MEM_PAGE_SIZE 4096
63be0a78 56/// \ingroup MemPoolsAPI
d96ceb8e 57#define MEM_CHUNK_SIZE 4096 * 4
63be0a78 58/// \ingroup MemPoolsAPI
d96ceb8e 59#define MEM_CHUNK_MAX_SIZE 256 * 1024 /* 2MB */
63be0a78 60/// \ingroup MemPoolsAPI
d96ceb8e 61#define MEM_MIN_FREE 32
63be0a78 62/// \ingroup MemPoolsAPI
d96ceb8e 63#define MEM_MAX_FREE 65535 /* ushort is max number of items per chunk */
64
b001e822 65class MemImplementingAllocator;
66class MemChunk;
67class MemPoolStats;
83d8f9f4 68
63be0a78 69/// \ingroup MemPoolsAPI
70/// \todo Kill this typedef for C++
d96ceb8e 71typedef struct _MemPoolGlobalStats MemPoolGlobalStats;
83d8f9f4 72
63be0a78 73/// \ingroup MemPoolsAPI
b001e822 74class MemPoolIterator
83d8f9f4 75{
c5dd4956 76public:
b001e822 77 MemImplementingAllocator *pool;
d96ceb8e 78 MemPoolIterator * next;
79};
80
63be0a78 81/**
82 \ingroup MemPoolsAPI
83 * Object to track per-pool cumulative counters
84 */
b001e822 85class mgb_t
83d8f9f4 86{
c5dd4956
AJ
87public:
88 mgb_t() : count(0), bytes(0) {}
d96ceb8e 89 double count;
90 double bytes;
b001e822 91};
d96ceb8e 92
63be0a78 93/**
94 \ingroup MemPoolsAPI
95 * Object to track per-pool memory usage (alloc = inuse+idle)
96 */
b001e822 97class MemPoolMeter
83d8f9f4 98{
c5dd4956 99public:
b001e822 100 void flush();
d96ceb8e 101 MemMeter alloc;
102 MemMeter inuse;
103 MemMeter idle;
63be0a78 104
105 /** account Allocations */
106 mgb_t gb_saved;
107
108 /** history Allocations */
109 mgb_t gb_osaved;
110
111 /** account Free calls */
112 mgb_t gb_freed;
d96ceb8e 113};
114
b001e822 115class MemImplementingAllocator;
116
63be0a78 117/// \ingroup MemPoolsAPI
c5dd4956 118class MemPools
b001e822 119{
c5dd4956 120public:
b001e822 121 static MemPools &GetInstance();
122 MemPools();
123 void init();
124 void flushMeters();
63be0a78 125
126 /**
127 \param label Name for the pool. Displayed in stats.
128 \param obj_size Size of elements in MemPool.
129 */
b001e822 130 MemImplementingAllocator * create(const char *label, size_t obj_size);
63be0a78 131
132 /**
133 \param label Name for the pool. Displayed in stats.
134 \param obj_size Size of elements in MemPool.
135 \param chunked ??
136 */
b001e822 137 MemImplementingAllocator * create(const char *label, size_t obj_size, bool const chunked);
63be0a78 138
139 /**
140 * Sets upper limit in bytes to amount of free ram kept in pools. This is
141 * not strict upper limit, but a hint. When MemPools are over this limit,
142 * totally free chunks are immediately considered for release. Otherwise
143 * only chunks that have not been referenced for a long time are checked.
144 */
b001e822 145 void setIdleLimit(size_t new_idle_limit);
63be0a78 146
871899ca 147 size_t idleLimit() const;
63be0a78 148
149 /**
150 \par
151 * Main cleanup handler. For MemPools to stay within upper idle limits,
152 * this function needs to be called periodically, preferrably at some
153 * constant rate, eg. from Squid event. It looks through all pools and
154 * chunks, cleans up internal states and checks for releasable chunks.
155 *
156 \par
157 * Between the calls to this function objects are placed onto internal
158 * cache instead of returning to their home chunks, mainly for speedup
159 * purpose. During that time state of chunk is not known, it is not
160 * known whether chunk is free or in use. This call returns all objects
161 * to their chunks and restores consistency.
162 *
163 \par
164 * Should be called relatively often, as it sorts chunks in suitable
165 * order as to reduce free memory fragmentation and increase chunk
166 * utilisation.
167 * Suitable frequency for cleanup is in range of few tens of seconds to
168 * few minutes, depending of memory activity.
169 *
170 \todo DOCS: Re-write this shorter!
171 *
172 \param maxage Release all totally idle chunks that
173 * have not been referenced for maxage seconds.
174 */
b001e822 175 void clean(time_t maxage);
63be0a78 176
b001e822 177 void setDefaultPoolChunking(bool const &);
178 MemImplementingAllocator *pools;
179 int mem_idle_limit;
180 int poolCount;
181 bool defaultIsChunked;
c5dd4956 182private:
b001e822 183 static MemPools *Instance;
184};
185
63be0a78 186/**
187 \ingroup MemPoolsAPI
188 * a pool is a [growing] space for objects of the same size
189 */
b001e822 190class MemAllocator
191{
192public:
193 MemAllocator (char const *aLabel);
194 virtual ~MemAllocator() {}
63be0a78 195
196 /**
197 \param stats Object to be filled with statistical data about pool.
198 \retval Number of objects in use, ie. allocated.
199 */
b001e822 200 virtual int getStats(MemPoolStats * stats) = 0;
63be0a78 201
b001e822 202 virtual MemPoolMeter const &getMeter() const = 0;
63be0a78 203
204 /**
205 * Allocate one element from the pool
206 */
b001e822 207 virtual void *alloc() = 0;
63be0a78 208
209 /**
210 * Free a element allocated by MemAllocator::alloc()
211 */
dc47f531 212 virtual void freeOne(void *) = 0;
63be0a78 213
b001e822 214 virtual char const *objectType() const;
215 virtual size_t objectSize() const = 0;
9f9e06f3 216 virtual int getInUseCount() = 0;
60da11d3 217 void zeroOnPush(bool doIt);
a3efa961 218 int inUseCount();
63be0a78 219
220 /**
221 * Allows you tune chunk size of pooling. Objects are allocated in chunks
222 * instead of individually. This conserves memory, reduces fragmentation.
223 * Because of that memory can be freed also only in chunks. Therefore
224 * there is tradeoff between memory conservation due to chunking and free
225 * memory fragmentation.
226 *
227 \note As a general guideline, increase chunk size only for pools that keep
228 * very many items for relatively long time.
229 */
04eb0689 230 virtual void setChunkSize(size_t chunksize) {}
cb6d4984 231
63be0a78 232 /**
233 \param minSize Minimum size needed to be allocated.
234 \retval n Smallest size divisible by sizeof(void*)
235 */
cb6d4984 236 static size_t RoundedSize(size_t minSize);
63be0a78 237
60da11d3 238protected:
239 bool doZeroOnPush;
63be0a78 240
b001e822 241private:
242 const char *label;
243};
244
63be0a78 245/**
246 \ingroup MemPoolsAPI
247 * Support late binding of pool type for allocator agnostic classes
248 */
b001e822 249class MemAllocatorProxy
83d8f9f4 250{
c5dd4956 251public:
b001e822 252 inline MemAllocatorProxy(char const *aLabel, size_t const &);
63be0a78 253
254 /**
255 * Allocate one element from the pool
256 */
b001e822 257 void *alloc();
63be0a78 258
259 /**
260 * Free a element allocated by MemAllocatorProxy::alloc()
261 */
dc47f531 262 void freeOne(void *);
63be0a78 263
b001e822 264 int inUseCount() const;
265 size_t objectSize() const;
266 MemPoolMeter const &getMeter() const;
63be0a78 267
268 /**
269 \param stats Object to be filled with statistical data about pool.
270 \retval Number of objects in use, ie. allocated.
271 */
b001e822 272 int getStats(MemPoolStats * stats);
63be0a78 273
b001e822 274 char const * objectType() const;
c5dd4956 275private:
b001e822 276 MemAllocator *getAllocator() const;
d96ceb8e 277 const char *label;
b001e822 278 size_t size;
279 mutable MemAllocator *theAllocator;
280};
63be0a78 281
b001e822 282/* help for classes */
63be0a78 283
284/**
285 \ingroup MemPoolsAPI
286 \hideinitializer
c5dd4956 287 *
63be0a78 288 * This macro is intended for use within the declaration of a class.
289 */
b001e822 290#define MEMPROXY_CLASS(CLASS) \
b001e822 291 inline void *operator new(size_t); \
292 inline void operator delete(void *); \
293 static inline MemAllocatorProxy &Pool()
294
63be0a78 295/**
296 \ingroup MemPoolsAPI
297 \hideinitializer
c5dd4956 298 *
63be0a78 299 * This macro is intended for use within the .h or .cci of a class as appropriate.
300 */
b001e822 301#define MEMPROXY_CLASS_INLINE(CLASS) \
302MemAllocatorProxy& CLASS::Pool() \
303{ \
304 static MemAllocatorProxy thePool(#CLASS, sizeof (CLASS)); \
305 return thePool; \
306} \
307\
308void * \
309CLASS::operator new (size_t byteCount) \
310{ \
311 /* derived classes with different sizes must implement their own new */ \
312 assert (byteCount == sizeof (CLASS)); \
313\
314 return Pool().alloc(); \
315} \
316\
317void \
318CLASS::operator delete (void *address) \
319{ \
dc47f531 320 Pool().freeOne(address); \
b001e822 321}
322
63be0a78 323/// \ingroup MemPoolsAPI
b001e822 324class MemImplementingAllocator : public MemAllocator
325{
c5dd4956 326public:
b001e822 327 MemImplementingAllocator(char const *aLabel, size_t aSize);
328 virtual MemPoolMeter const &getMeter() const;
329 virtual MemPoolMeter &getMeter();
330 virtual void flushMetersFull();
331 virtual void flushMeters();
63be0a78 332
333 /**
334 * Allocate one element from the pool
335 */
b001e822 336 virtual void *alloc();
63be0a78 337
338 /**
339 * Free a element allocated by MemImplementingAllocator::alloc()
340 */
dc47f531 341 virtual void freeOne(void *);
63be0a78 342
b001e822 343 virtual bool idleTrigger(int shift) const = 0;
344 virtual void clean(time_t maxage) = 0;
63be0a78 345 /** Hint to the allocator - may be ignored */
b001e822 346 virtual void setChunkSize(size_t chunksize) {}
347 virtual size_t objectSize() const;
9f9e06f3 348 virtual int getInUseCount() = 0;
c5dd4956 349protected:
b001e822 350 virtual void *allocate() = 0;
351 virtual void deallocate(void *) = 0;
c5dd4956 352private:
b001e822 353 MemPoolMeter meter;
c5dd4956 354public:
b001e822 355 MemImplementingAllocator *next;
c5dd4956 356public:
b001e822 357 size_t alloc_calls;
358 size_t free_calls;
d96ceb8e 359 size_t obj_size;
b001e822 360};
361
63be0a78 362/// \ingroup MemPoolsAPI
b001e822 363class MemPool : public MemImplementingAllocator
364{
c5dd4956 365public:
b001e822 366 friend class MemChunk;
367 MemPool(const char *label, size_t obj_size);
368 ~MemPool();
369 void convertFreeCacheToChunkFreeCache();
370 virtual void clean(time_t maxage);
63be0a78 371
372 /**
373 \param stats Object to be filled with statistical data about pool.
374 \retval Number of objects in use, ie. allocated.
375 */
b001e822 376 virtual int getStats(MemPoolStats * stats);
63be0a78 377
b001e822 378 void createChunk();
379 void *get();
380 void push(void *obj);
9f9e06f3 381 virtual int getInUseCount();
c5dd4956 382protected:
b001e822 383 virtual void *allocate();
384 virtual void deallocate(void *);
c5dd4956 385public:
63be0a78 386 /**
387 * Allows you tune chunk size of pooling. Objects are allocated in chunks
388 * instead of individually. This conserves memory, reduces fragmentation.
389 * Because of that memory can be freed also only in chunks. Therefore
390 * there is tradeoff between memory conservation due to chunking and free
391 * memory fragmentation.
392 *
393 \note As a general guideline, increase chunk size only for pools that keep
394 * very many items for relatively long time.
395 */
b001e822 396 virtual void setChunkSize(size_t chunksize);
63be0a78 397
b001e822 398 virtual bool idleTrigger(int shift) const;
399
d96ceb8e 400 size_t chunk_size;
401 int chunk_capacity;
402 int memPID;
403 int chunkCount;
d96ceb8e 404 size_t inuse;
405 size_t idle;
406 void *freeCache;
407 MemChunk *nextFreeChunk;
408 MemChunk *Chunks;
b001e822 409 Splay<MemChunk *> allChunks;
410};
411
63be0a78 412/// \ingroup MemPoolsAPI
b001e822 413class MemMalloc : public MemImplementingAllocator
414{
c5dd4956 415public:
b001e822 416 MemMalloc(char const *label, size_t aSize);
417 virtual bool idleTrigger(int shift) const;
418 virtual void clean(time_t maxage);
63be0a78 419
420 /**
421 \param stats Object to be filled with statistical data about pool.
422 \retval Number of objects in use, ie. allocated.
423 */
b001e822 424 virtual int getStats(MemPoolStats * stats);
63be0a78 425
9f9e06f3 426 virtual int getInUseCount();
c5dd4956 427protected:
b001e822 428 virtual void *allocate();
429 virtual void deallocate(void *);
c5dd4956 430private:
9f9e06f3 431 int inuse;
d96ceb8e 432};
433
63be0a78 434/// \ingroup MemPoolsAPI
b001e822 435class MemChunk
83d8f9f4 436{
c5dd4956 437public:
b001e822 438 MemChunk(MemPool *pool);
439 ~MemChunk();
d96ceb8e 440 void *freeList;
441 void *objCache;
442 int inuse_count;
443 MemChunk *nextFreeChunk;
444 MemChunk *next;
445 time_t lastref;
b001e822 446 MemPool *pool;
d96ceb8e 447};
448
63be0a78 449/// \ingroup MemPoolsAPI
b001e822 450class MemPoolStats
83d8f9f4 451{
c5dd4956 452public:
b001e822 453 MemAllocator *pool;
d96ceb8e 454 const char *label;
455 MemPoolMeter *meter;
456 int obj_size;
457 int chunk_capacity;
458 int chunk_size;
459
460 int chunks_alloc;
461 int chunks_inuse;
462 int chunks_partial;
463 int chunks_free;
464
465 int items_alloc;
466 int items_inuse;
467 int items_idle;
468
469 int overhead;
470};
471
63be0a78 472/// \ingroup MemPoolsAPI
473/// \todo Classify and add constructor/destructor to initialize properly.
c5dd4956 474struct _MemPoolGlobalStats {
d96ceb8e 475 MemPoolMeter *TheMeter;
476
477 int tot_pools_alloc;
478 int tot_pools_inuse;
479 int tot_pools_mempid;
480
481 int tot_chunks_alloc;
482 int tot_chunks_inuse;
483 int tot_chunks_partial;
484 int tot_chunks_free;
485
486 int tot_items_alloc;
487 int tot_items_inuse;
488 int tot_items_idle;
489
490 int tot_overhead;
491 int mem_idle_limit;
492};
493
63be0a78 494/// \ingroup MemPoolsAPI
04eb0689 495#define memPoolCreate MemPools::GetInstance().create
496
d96ceb8e 497/* Allocator API */
63be0a78 498/**
499 \ingroup MemPoolsAPI
500 * Initialise iteration through all of the pools.
501 \retval Iterator for use by memPoolIterateNext() and memPoolIterateDone()
502 */
b001e822 503extern MemPoolIterator * memPoolIterate(void);
63be0a78 504
505/**
506 \ingroup MemPoolsAPI
507 * Get next pool pointer, until getting NULL pointer.
508 */
b001e822 509extern MemImplementingAllocator * memPoolIterateNext(MemPoolIterator * iter);
63be0a78 510
511/**
512 \ingroup MemPoolsAPI
513 * Should be called after finished with iterating through all pools.
514 */
b001e822 515extern void memPoolIterateDone(MemPoolIterator ** iter);
d96ceb8e 516
63be0a78 517/**
518 \ingroup MemPoolsAPI
519 \todo Stats API - not sured how to refactor yet
520 *
521 * Fills MemPoolGlobalStats with statistical data about overall
522 * usage for all pools.
523 *
524 \retval Number of pools that have at least one object in use.
525 * Ie. number of dirty pools.
526 */
b001e822 527extern int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
d96ceb8e 528
63be0a78 529/// \ingroup MemPoolsAPI
b001e822 530extern int memPoolInUseCount(MemAllocator *);
63be0a78 531/// \ingroup MemPoolsAPI
b001e822 532extern int memPoolsTotalAllocated(void);
d96ceb8e 533
b001e822 534MemAllocatorProxy::MemAllocatorProxy(char const *aLabel, size_t const &aSize) : label (aLabel), size(aSize), theAllocator (NULL)
535{
536}
d96ceb8e 537
d96ceb8e 538
539#endif /* _MEM_POOLS_H_ */