]> git.ipfire.org Git - thirdparty/squid.git/blob - src/mem/Pool.h
Refactor memory pools statistics gathering (#1186)
[thirdparty/squid.git] / src / mem / Pool.h
1 /*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
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
9 #ifndef _MEM_POOL_H_
10 #define _MEM_POOL_H_
11
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
31 #include "mem/Allocator.h"
32 #include "mem/Meter.h"
33 #include "util.h"
34
35 #include <list>
36 #if HAVE_GNUMALLOC_H
37 #include <gnumalloc.h>
38 #elif HAVE_MALLOC_H
39 #include <malloc.h>
40 #endif
41 #if HAVE_MEMORY_H
42 #include <memory.h>
43 #endif
44
45 #if !M_MMAP_MAX
46 #if USE_DLMALLOC
47 #define M_MMAP_MAX -4
48 #endif
49 #endif
50
51 /// \ingroup MemPoolsAPI
52 #define toMB(size) ( ((double) size) / ((double)(1024*1024)) )
53 /// \ingroup MemPoolsAPI
54 #define toKB(size) ( (size + 1024 - 1) / 1024 )
55
56 /// \ingroup MemPoolsAPI
57 #define MEM_PAGE_SIZE 4096
58 /// \ingroup MemPoolsAPI
59 #define MEM_MIN_FREE 32
60 /// \ingroup MemPoolsAPI
61 #define MEM_MAX_FREE 65535 /* unsigned short is max number of items per chunk */
62
63 class MemImplementingAllocator;
64
65 /// memory usage totals as of latest MemPools::flushMeters() event
66 extern Mem::PoolMeter TheMeter;
67
68 /// \ingroup MemPoolsAPI
69 class MemPools
70 {
71 public:
72 static MemPools &GetInstance();
73 MemPools();
74 void flushMeters();
75
76 /**
77 * Create an allocator with given name to allocate fixed-size objects
78 * of the specified size.
79 */
80 MemImplementingAllocator *create(const char *, size_t);
81
82 /**
83 * Sets upper limit in bytes to amount of free ram kept in pools. This is
84 * not strict upper limit, but a hint. When MemPools are over this limit,
85 * deallocate attempts to release memory to the system instead of pooling.
86 */
87 void setIdleLimit(const ssize_t newLimit) { idleLimit_ = newLimit; }
88 /// \copydoc idleLimit_
89 ssize_t idleLimit() const { return idleLimit_; }
90
91 /**
92 \par
93 * Main cleanup handler. For MemPools to stay within upper idle limits,
94 * this function needs to be called periodically, preferably at some
95 * constant rate, eg. from Squid event. It looks through all pools and
96 * chunks, cleans up internal states and checks for releasable chunks.
97 *
98 \par
99 * Between the calls to this function objects are placed onto internal
100 * cache instead of returning to their home chunks, mainly for speedup
101 * purpose. During that time state of chunk is not known, it is not
102 * known whether chunk is free or in use. This call returns all objects
103 * to their chunks and restores consistency.
104 *
105 \par
106 * Should be called relatively often, as it sorts chunks in suitable
107 * order as to reduce free memory fragmentation and increase chunk
108 * utilisation.
109 * Suitable frequency for cleanup is in range of few tens of seconds to
110 * few minutes, depending of memory activity.
111 *
112 * TODO: DOCS: Re-write this shorter!
113 *
114 \param maxage Release all totally idle chunks that
115 * have not been referenced for maxage seconds.
116 */
117 void clean(time_t maxage);
118
119 void setDefaultPoolChunking(bool const &);
120
121 std::list<MemImplementingAllocator *> pools;
122 bool defaultIsChunked = false;
123
124 private:
125 /// Limits the cumulative size of allocated (but unused) memory in all pools.
126 /// Initial value is 2MB until first configuration,
127 /// See squid.conf memory_pools_limit directive.
128 ssize_t idleLimit_ = (2 << 20);
129 };
130
131 /// \ingroup MemPoolsAPI
132 class MemImplementingAllocator : public Mem::Allocator
133 {
134 public:
135 typedef Mem::PoolMeter PoolMeter; // TODO remove
136
137 MemImplementingAllocator(char const *aLabel, size_t aSize);
138
139 virtual PoolMeter &getMeter();
140 virtual void flushMetersFull();
141 virtual void flushMeters();
142 virtual bool idleTrigger(int shift) const = 0;
143 virtual void clean(time_t maxage) = 0;
144
145 /* Mem::Allocator API */
146 virtual PoolMeter const &getMeter() const;
147 virtual void *alloc();
148 virtual void freeOne(void *);
149 virtual size_t objectSize() const;
150 virtual int getInUseCount() = 0;
151
152 protected:
153 virtual void *allocate() = 0;
154 virtual void deallocate(void *, bool aggressive) = 0;
155 PoolMeter meter;
156 public:
157 size_t alloc_calls;
158 size_t free_calls;
159 size_t saved_calls;
160 size_t obj_size;
161 };
162
163 /// Creates a named MemPool of elements with the given size
164 #define memPoolCreate MemPools::GetInstance().create
165
166 #endif /* _MEM_POOL_H_ */
167