]> git.ipfire.org Git - thirdparty/squid.git/blame - src/mem/Pool.h
Maintenance: Remove FIXME and \todo labels (#647)
[thirdparty/squid.git] / src / mem / Pool.h
CommitLineData
5c193dec 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
5c193dec
AJ
3 *
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.
7 */
8
8cfaefed
HN
9#ifndef _MEM_POOL_H_
10#define _MEM_POOL_H_
d96ceb8e 11
63be0a78 12/**
13 \defgroup MemPoolsAPI Memory Management (Memory Pool Allocator)
14 \ingroup Components
15 *
16 *\par
17 * MemPools are a pooled memory allocator running on top of malloc(). It's
18 * purpose is to reduce memory fragmentation and provide detailed statistics
19 * on memory consumption.
20 *
21 \par
22 * Preferably all memory allocations in Squid should be done using MemPools
23 * or one of the types built on top of it (i.e. cbdata).
24 *
25 \note Usually it is better to use cbdata types as these gives you additional
26 * safeguards in references and typechecking. However, for high usage pools where
27 * the cbdata functionality of cbdata is not required directly using a MemPool
28 * might be the way to go.
29 */
30
9663db1c 31#include "mem/Meter.h"
ed6e9fb9 32#include "util.h"
d96ceb8e 33
34#if HAVE_GNUMALLOC_H
35#include <gnumalloc.h>
482aa790 36#elif HAVE_MALLOC_H
d96ceb8e 37#include <malloc.h>
38#endif
d96ceb8e 39#if HAVE_MEMORY_H
40#include <memory.h>
41#endif
42
43#if !M_MMAP_MAX
44#if USE_DLMALLOC
45#define M_MMAP_MAX -4
46#endif
47#endif
48
63be0a78 49/// \ingroup MemPoolsAPI
c63f0322 50#define toMB(size) ( ((double) size) / ((double)(1024*1024)) )
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_MIN_FREE 32
63be0a78 58/// \ingroup MemPoolsAPI
f53969cc 59#define MEM_MAX_FREE 65535 /* unsigned short is max number of items per chunk */
d96ceb8e 60
b001e822 61class MemImplementingAllocator;
b001e822 62class MemPoolStats;
83d8f9f4 63
63be0a78 64/// \ingroup MemPoolsAPI
9837567d 65/// TODO: Kill this typedef for C++
d96ceb8e 66typedef struct _MemPoolGlobalStats MemPoolGlobalStats;
83d8f9f4 67
63be0a78 68/// \ingroup MemPoolsAPI
b001e822 69class MemPoolIterator
83d8f9f4 70{
c5dd4956 71public:
b001e822 72 MemImplementingAllocator *pool;
d96ceb8e 73 MemPoolIterator * next;
74};
75
63be0a78 76/**
77 \ingroup MemPoolsAPI
78 * Object to track per-pool cumulative counters
79 */
b001e822 80class mgb_t
83d8f9f4 81{
c5dd4956
AJ
82public:
83 mgb_t() : count(0), bytes(0) {}
d96ceb8e 84 double count;
85 double bytes;
b001e822 86};
d96ceb8e 87
63be0a78 88/**
89 \ingroup MemPoolsAPI
90 * Object to track per-pool memory usage (alloc = inuse+idle)
91 */
b001e822 92class MemPoolMeter
83d8f9f4 93{
c5dd4956 94public:
903a6eec 95 MemPoolMeter();
b001e822 96 void flush();
9663db1c
AJ
97
98 Mem::Meter alloc;
99 Mem::Meter inuse;
100 Mem::Meter idle;
63be0a78 101
63be0a78 102 /** history Allocations */
903a6eec
HN
103 mgb_t gb_allocated;
104 mgb_t gb_oallocated;
105
106 /** account Saved Allocations */
107 mgb_t gb_saved;
63be0a78 108
109 /** account Free calls */
110 mgb_t gb_freed;
d96ceb8e 111};
112
b001e822 113class MemImplementingAllocator;
114
63be0a78 115/// \ingroup MemPoolsAPI
c5dd4956 116class MemPools
b001e822 117{
c5dd4956 118public:
b001e822 119 static MemPools &GetInstance();
120 MemPools();
b001e822 121 void flushMeters();
63be0a78 122
123 /**
f53969cc
SM
124 \param label Name for the pool. Displayed in stats.
125 \param obj_size Size of elements in MemPool.
63be0a78 126 */
b001e822 127 MemImplementingAllocator * create(const char *label, size_t obj_size);
63be0a78 128
63be0a78 129 /**
130 * Sets upper limit in bytes to amount of free ram kept in pools. This is
131 * not strict upper limit, but a hint. When MemPools are over this limit,
132 * totally free chunks are immediately considered for release. Otherwise
133 * only chunks that have not been referenced for a long time are checked.
134 */
89646bd7
HN
135 void setIdleLimit(ssize_t new_idle_limit);
136 ssize_t idleLimit() const;
63be0a78 137
138 /**
139 \par
140 * Main cleanup handler. For MemPools to stay within upper idle limits,
2f8abb64 141 * this function needs to be called periodically, preferably at some
63be0a78 142 * constant rate, eg. from Squid event. It looks through all pools and
143 * chunks, cleans up internal states and checks for releasable chunks.
144 *
145 \par
146 * Between the calls to this function objects are placed onto internal
147 * cache instead of returning to their home chunks, mainly for speedup
148 * purpose. During that time state of chunk is not known, it is not
149 * known whether chunk is free or in use. This call returns all objects
150 * to their chunks and restores consistency.
151 *
152 \par
153 * Should be called relatively often, as it sorts chunks in suitable
154 * order as to reduce free memory fragmentation and increase chunk
155 * utilisation.
156 * Suitable frequency for cleanup is in range of few tens of seconds to
157 * few minutes, depending of memory activity.
158 *
9837567d 159 * TODO: DOCS: Re-write this shorter!
63be0a78 160 *
161 \param maxage Release all totally idle chunks that
162 * have not been referenced for maxage seconds.
163 */
b001e822 164 void clean(time_t maxage);
63be0a78 165
b001e822 166 void setDefaultPoolChunking(bool const &);
2414910d
AJ
167
168 MemImplementingAllocator *pools = nullptr;
169 ssize_t mem_idle_limit = (2 << 20) /* 2MB */;
170 int poolCount = 0;
171 bool defaultIsChunked = false;
b001e822 172};
173
63be0a78 174/**
175 \ingroup MemPoolsAPI
176 * a pool is a [growing] space for objects of the same size
177 */
b001e822 178class MemAllocator
179{
180public:
181 MemAllocator (char const *aLabel);
182 virtual ~MemAllocator() {}
63be0a78 183
184 /**
f53969cc
SM
185 \param stats Object to be filled with statistical data about pool.
186 \retval Number of objects in use, ie. allocated.
63be0a78 187 */
8cfaefed 188 virtual int getStats(MemPoolStats * stats, int accumulate = 0) = 0;
63be0a78 189
b001e822 190 virtual MemPoolMeter const &getMeter() const = 0;
63be0a78 191
192 /**
193 * Allocate one element from the pool
194 */
b001e822 195 virtual void *alloc() = 0;
63be0a78 196
197 /**
198 * Free a element allocated by MemAllocator::alloc()
199 */
dc47f531 200 virtual void freeOne(void *) = 0;
63be0a78 201
b001e822 202 virtual char const *objectType() const;
203 virtual size_t objectSize() const = 0;
9f9e06f3 204 virtual int getInUseCount() = 0;
3b08e399 205 void zeroBlocks(bool doIt) {doZero = doIt;}
a3efa961 206 int inUseCount();
63be0a78 207
208 /**
209 * Allows you tune chunk size of pooling. Objects are allocated in chunks
210 * instead of individually. This conserves memory, reduces fragmentation.
211 * Because of that memory can be freed also only in chunks. Therefore
212 * there is tradeoff between memory conservation due to chunking and free
213 * memory fragmentation.
214 *
215 \note As a general guideline, increase chunk size only for pools that keep
216 * very many items for relatively long time.
217 */
ced8def3 218 virtual void setChunkSize(size_t) {}
cb6d4984 219
63be0a78 220 /**
f53969cc 221 \param minSize Minimum size needed to be allocated.
63be0a78 222 \retval n Smallest size divisible by sizeof(void*)
223 */
cb6d4984 224 static size_t RoundedSize(size_t minSize);
63be0a78 225
60da11d3 226protected:
3b08e399
AJ
227 /** Whether to zero memory on initial allocation and on return to the pool.
228 *
229 * We do this on some pools because many object constructors are/were incomplete
230 * and we are afraid some code may use the object after free.
231 * These probems are becoming less common, so when possible set this to false.
232 */
233 bool doZero;
63be0a78 234
b001e822 235private:
236 const char *label;
237};
238
63be0a78 239/// \ingroup MemPoolsAPI
b001e822 240class MemImplementingAllocator : public MemAllocator
241{
c5dd4956 242public:
b001e822 243 MemImplementingAllocator(char const *aLabel, size_t aSize);
2be7332c 244 virtual ~MemImplementingAllocator();
b001e822 245 virtual MemPoolMeter const &getMeter() const;
246 virtual MemPoolMeter &getMeter();
247 virtual void flushMetersFull();
248 virtual void flushMeters();
63be0a78 249
250 /**
251 * Allocate one element from the pool
252 */
b001e822 253 virtual void *alloc();
63be0a78 254
255 /**
256 * Free a element allocated by MemImplementingAllocator::alloc()
257 */
dc47f531 258 virtual void freeOne(void *);
63be0a78 259
b001e822 260 virtual bool idleTrigger(int shift) const = 0;
261 virtual void clean(time_t maxage) = 0;
b001e822 262 virtual size_t objectSize() const;
9f9e06f3 263 virtual int getInUseCount() = 0;
c5dd4956 264protected:
b001e822 265 virtual void *allocate() = 0;
2be7332c 266 virtual void deallocate(void *, bool aggressive) = 0;
b001e822 267 MemPoolMeter meter;
8cfaefed 268 int memPID;
c5dd4956 269public:
b001e822 270 MemImplementingAllocator *next;
c5dd4956 271public:
b001e822 272 size_t alloc_calls;
273 size_t free_calls;
903a6eec 274 size_t saved_calls;
d96ceb8e 275 size_t obj_size;
b001e822 276};
277
63be0a78 278/// \ingroup MemPoolsAPI
b001e822 279class MemPoolStats
83d8f9f4 280{
c5dd4956 281public:
b001e822 282 MemAllocator *pool;
d96ceb8e 283 const char *label;
284 MemPoolMeter *meter;
285 int obj_size;
286 int chunk_capacity;
287 int chunk_size;
288
289 int chunks_alloc;
290 int chunks_inuse;
291 int chunks_partial;
292 int chunks_free;
293
294 int items_alloc;
295 int items_inuse;
296 int items_idle;
297
298 int overhead;
299};
300
63be0a78 301/// \ingroup MemPoolsAPI
9837567d 302/// TODO: Classify and add constructor/destructor to initialize properly.
c5dd4956 303struct _MemPoolGlobalStats {
d96ceb8e 304 MemPoolMeter *TheMeter;
305
306 int tot_pools_alloc;
307 int tot_pools_inuse;
308 int tot_pools_mempid;
309
310 int tot_chunks_alloc;
311 int tot_chunks_inuse;
312 int tot_chunks_partial;
313 int tot_chunks_free;
314
315 int tot_items_alloc;
316 int tot_items_inuse;
317 int tot_items_idle;
318
319 int tot_overhead;
89646bd7 320 ssize_t mem_idle_limit;
d96ceb8e 321};
322
63be0a78 323/// \ingroup MemPoolsAPI
a8ef0b3f 324/// Creates a named MemPool of elements with the given size
04eb0689 325#define memPoolCreate MemPools::GetInstance().create
326
d96ceb8e 327/* Allocator API */
63be0a78 328/**
329 \ingroup MemPoolsAPI
330 * Initialise iteration through all of the pools.
a8ef0b3f 331 * \returns Iterator for use by memPoolIterateNext() and memPoolIterateDone()
63be0a78 332 */
b001e822 333extern MemPoolIterator * memPoolIterate(void);
63be0a78 334
335/**
336 \ingroup MemPoolsAPI
337 * Get next pool pointer, until getting NULL pointer.
338 */
b001e822 339extern MemImplementingAllocator * memPoolIterateNext(MemPoolIterator * iter);
63be0a78 340
341/**
342 \ingroup MemPoolsAPI
343 * Should be called after finished with iterating through all pools.
344 */
b001e822 345extern void memPoolIterateDone(MemPoolIterator ** iter);
d96ceb8e 346
63be0a78 347/**
348 \ingroup MemPoolsAPI
63be0a78 349 *
a8ef0b3f 350 * Fills a MemPoolGlobalStats with statistical data about overall
63be0a78 351 * usage for all pools.
352 *
a8ef0b3f
AJ
353 * \param stats Object to be filled with statistical data.
354 *
355 * \return Number of pools that have at least one object in use.
63be0a78 356 * Ie. number of dirty pools.
357 */
b001e822 358extern int memPoolGetGlobalStats(MemPoolGlobalStats * stats);
d96ceb8e 359
63be0a78 360/// \ingroup MemPoolsAPI
b001e822 361extern int memPoolsTotalAllocated(void);
d96ceb8e 362
8cfaefed 363#endif /* _MEM_POOL_H_ */
f53969cc 364