]> git.ipfire.org Git - thirdparty/squid.git/blame - src/mem.cc
Rewrote the confusing comment on cache_mem suggesting that Squid may use
[thirdparty/squid.git] / src / mem.cc
CommitLineData
acf5589a 1
2/*
add2192d 3 * $Id: mem.cc,v 1.62 2002/02/26 15:48:15 adrian Exp $
acf5589a 4 *
7021844c 5 * DEBUG: section 13 High Level Memory Pool Management
acf5589a 6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
acf5589a 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
acf5589a 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
acf5589a 34 */
35
36#include "squid.h"
37
7021844c 38/* module globals */
acf5589a 39
7021844c 40static MemPool *MemPools[MEM_MAX];
acf5589a 41
9fe7e747 42/* string pools */
43#define mem_str_pool_count 3
ec878047 44static const struct {
45 const char *name;
9fe7e747 46 size_t obj_size;
ec878047 47} StrPoolsAttrs[mem_str_pool_count] = {
4b4cd312 48
ec878047 49 {
50 "Short Strings", 36,
51 }, /* to fit rfc1123 and similar */
52 {
53 "Medium Strings", 128,
54 }, /* to fit most urls */
55 {
56 "Long Strings", 512
57 } /* other */
9fe7e747 58};
ec878047 59static struct {
60 MemPool *pool;
61} StrPools[mem_str_pool_count];
9fe7e747 62static MemMeter StrCountMeter;
63static MemMeter StrVolumeMeter;
64
1eb41ae8 65static MemMeter HugeBufCountMeter;
66static MemMeter HugeBufVolumeMeter;
9fe7e747 67
68/* local routines */
69
9fe7e747 70static void
71memStringStats(StoreEntry * sentry)
72{
73 const char *pfmt = "%-20s\t %d\t %d\n";
74 int i;
75 int pooled_count = 0;
76 size_t pooled_volume = 0;
77 /* heading */
ec878047 78 storeAppendPrintf(sentry,
9fe7e747 79 "String Pool\t Impact\t\t\n"
80 " \t (%%strings)\t (%%volume)\n");
81 /* table body */
82 for (i = 0; i < mem_str_pool_count; i++) {
83 const MemPool *pool = StrPools[i].pool;
84 const int plevel = pool->meter.inuse.level;
ec878047 85 storeAppendPrintf(sentry, pfmt,
9fe7e747 86 pool->label,
87 xpercentInt(plevel, StrCountMeter.level),
ec878047 88 xpercentInt(plevel * pool->obj_size, StrVolumeMeter.level));
9fe7e747 89 pooled_count += plevel;
ec878047 90 pooled_volume += plevel * pool->obj_size;
9fe7e747 91 }
92 /* malloc strings */
93 storeAppendPrintf(sentry, pfmt,
94 "Other Strings",
ec878047 95 xpercentInt(StrCountMeter.level - pooled_count, StrCountMeter.level),
96 xpercentInt(StrVolumeMeter.level - pooled_volume, StrVolumeMeter.level));
1eb41ae8 97 storeAppendPrintf(sentry, "\n");
98}
99
100static void
101memBufStats(StoreEntry *sentry)
102{
103 storeAppendPrintf(sentry, "Large buffers: %d (%d KB)\n",
104 HugeBufCountMeter.level,
105 HugeBufVolumeMeter.level / 1024);
9fe7e747 106}
107
acf5589a 108static void
7021844c 109memStats(StoreEntry * sentry)
acf5589a 110{
7021844c 111 storeBuffer(sentry);
b4832aa9 112 memReport(sentry);
9fe7e747 113 memStringStats(sentry);
1eb41ae8 114 memBufStats(sentry);
7021844c 115 storeBufferFlush(sentry);
acf5589a 116}
117
7021844c 118
acf5589a 119/*
9fe7e747 120 * public routines
acf5589a 121 */
122
58a39dc9 123/*
124 * we have a limit on _total_ amount of idle memory so we ignore
125 * max_pages for now
126 */
127void
128memDataInit(mem_type type, const char *name, size_t size, int max_pages_notused)
129{
130 assert(name && size);
131 MemPools[type] = memPoolCreate(name, size);
132}
133
9fe7e747 134
7021844c 135/* find appropriate pool and use it (pools always init buffer with 0s) */
acf5589a 136void *
7021844c 137memAllocate(mem_type type)
acf5589a 138{
7021844c 139 return memPoolAlloc(MemPools[type]);
acf5589a 140}
141
db1cd23c 142/* give memory back to the pool */
acf5589a 143void
db1cd23c 144memFree(void *p, int type)
acf5589a 145{
7021844c 146 memPoolFree(MemPools[type], p);
acf5589a 147}
148
9fe7e747 149/* allocate a variable size buffer using best-fit pool */
150void *
4be8fe59 151memAllocString(size_t net_size, size_t * gross_size)
9fe7e747 152{
153 int i;
154 MemPool *pool = NULL;
155 assert(gross_size);
156 for (i = 0; i < mem_str_pool_count; i++) {
157 if (net_size <= StrPoolsAttrs[i].obj_size) {
ec878047 158 pool = StrPools[i].pool;
9fe7e747 159 break;
160 }
161 }
162 *gross_size = pool ? pool->obj_size : net_size;
163 assert(*gross_size >= net_size);
164 memMeterInc(StrCountMeter);
165 memMeterAdd(StrVolumeMeter, *gross_size);
166 return pool ? memPoolAlloc(pool) : xcalloc(1, net_size);
167}
168
4be8fe59 169/* free buffer allocated with memAllocString() */
9fe7e747 170void
4be8fe59 171memFreeString(size_t size, void *buf)
9fe7e747 172{
173 int i;
174 MemPool *pool = NULL;
175 assert(size && buf);
176 for (i = 0; i < mem_str_pool_count; i++) {
177 if (size <= StrPoolsAttrs[i].obj_size) {
178 assert(size == StrPoolsAttrs[i].obj_size);
179 pool = StrPools[i].pool;
180 break;
181 }
182 }
183 memMeterDec(StrCountMeter);
184 memMeterDel(StrVolumeMeter, size);
185 pool ? memPoolFree(pool, buf) : xfree(buf);
186}
187
1eb41ae8 188/* Find the best fit MEM_X_BUF type */
189static mem_type
190memFindBufSizeType(size_t net_size, size_t * gross_size)
191{
192 mem_type type;
193 size_t size;
194 if (net_size <= 2*1024) {
195 type = MEM_2K_BUF;
196 size = 2*1024;
197 } else if (net_size <= 4*1024) {
198 type = MEM_4K_BUF;
199 size = 4*1024;
200 } else if (net_size <= 8*1024) {
201 type = MEM_8K_BUF;
202 size = 8*1024;
203 } else if (net_size <= 16*1024) {
204 type = MEM_16K_BUF;
205 size = 16*1024;
206 } else if (net_size <= 32*1024) {
207 type = MEM_32K_BUF;
208 size = 32*1024;
209 } else if (net_size <= 64*1024) {
210 type = MEM_64K_BUF;
211 size = 64*1024;
212 } else {
213 type = MEM_NONE;
214 size = net_size;
215 }
216 if (gross_size)
217 *gross_size = size;
218 return type;
219}
220
221/* allocate a variable size buffer using best-fit pool */
222void *
223memAllocBuf(size_t net_size, size_t * gross_size)
224{
225 mem_type type = memFindBufSizeType(net_size, gross_size);
226 if (type != MEM_NONE)
227 return memAllocate(type);
228 else {
229 memMeterInc(HugeBufCountMeter);
230 memMeterAdd(HugeBufVolumeMeter, *gross_size);
231 return xcalloc(1, net_size);
232 }
233}
234
235/* resize a variable sized buffer using best-fit pool */
236void *
237memReallocBuf(void *oldbuf, size_t net_size, size_t * gross_size)
238{
239 /* XXX This can be optimized on very large buffers to use realloc() */
240 int new_gross_size;
241 void *newbuf = memAllocBuf(net_size, &new_gross_size);
242 if (oldbuf) {
243 int data_size = *gross_size;
244 if (data_size > net_size)
245 data_size = net_size;
246 memcpy(newbuf, oldbuf, data_size);
247 memFreeBuf(*gross_size, oldbuf);
248 }
249 *gross_size = new_gross_size;
250 return newbuf;
251}
252
253/* free buffer allocated with memAllocBuf() */
254void
255memFreeBuf(size_t size, void *buf)
256{
257 mem_type type = memFindBufSizeType(size, NULL);
258 if (type != MEM_NONE)
259 memFree(buf, type);
260 else {
261 xfree(buf);
262 memMeterDec(HugeBufCountMeter);
263 memMeterDel(HugeBufVolumeMeter, size);
264 }
265}
266
267
acf5589a 268void
269memInit(void)
270{
9fe7e747 271 int i;
7021844c 272 memInitModule();
273 /* set all pointers to null */
274 memset(MemPools, '\0', sizeof(MemPools));
275 /*
276 * it does not hurt much to have a lot of pools since sizeof(MemPool) is
277 * small; someday we will figure out what to do with all the entries here
278 * that are never used or used only once; perhaps we should simply use
279 * malloc() for those? @?@
280 */
137ee196 281 memDataInit(MEM_2K_BUF, "2K Buffer", 2048, 10);
acf5589a 282 memDataInit(MEM_4K_BUF, "4K Buffer", 4096, 10);
283 memDataInit(MEM_8K_BUF, "8K Buffer", 8192, 10);
58cd5bbd 284 memDataInit(MEM_16K_BUF, "16K Buffer", 16384, 10);
285 memDataInit(MEM_32K_BUF, "32K Buffer", 32768, 10);
286 memDataInit(MEM_64K_BUF, "64K Buffer", 65536, 10);
acf5589a 287 memDataInit(MEM_ACL, "acl", sizeof(acl), 0);
acf5589a 288 memDataInit(MEM_ACL_DENY_INFO_LIST, "acl_deny_info_list",
289 sizeof(acl_deny_info_list), 0);
290 memDataInit(MEM_ACL_IP_DATA, "acl_ip_data", sizeof(acl_ip_data), 0);
291 memDataInit(MEM_ACL_LIST, "acl_list", sizeof(acl_list), 0);
292 memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
293 memDataInit(MEM_ACL_TIME_DATA, "acl_time_data", sizeof(acl_time_data), 0);
94439e4e 294 memDataInit(MEM_AUTH_USER_T, "auth_user_t",
295 sizeof(auth_user_t), 0);
296 memDataInit(MEM_AUTH_USER_HASH, "auth_user_hash_pointer",
297 sizeof(auth_user_hash_pointer), 0);
298 memDataInit(MEM_ACL_PROXY_AUTH_MATCH, "acl_proxy_auth_match_cache",
299 sizeof(acl_proxy_auth_match_cache), 0);
a72fdaa7 300 memDataInit(MEM_ACL_USER_DATA, "acl_user_data",
cf86841e 301 sizeof(acl_user_data), 0);
c68e9c6b 302#if USE_CACHE_DIGESTS
26c2ce6f 303 memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0);
c68e9c6b 304#endif
58cd5bbd 305 memDataInit(MEM_LINK_LIST, "link_list", sizeof(link_list), 10);
acf5589a 306 memDataInit(MEM_DLINK_NODE, "dlink_node", sizeof(dlink_node), 10);
acf5589a 307 memDataInit(MEM_DREAD_CTRL, "dread_ctrl", sizeof(dread_ctrl), 0);
308 memDataInit(MEM_DWRITE_Q, "dwrite_q", sizeof(dwrite_q), 0);
798b0889 309 memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0);
d8b249ef 310 memDataInit(MEM_HTTP_REPLY, "HttpReply", sizeof(HttpReply), 0);
311 memDataInit(MEM_HTTP_HDR_ENTRY, "HttpHeaderEntry", sizeof(HttpHeaderEntry), 0);
7faf2bdb 312 memDataInit(MEM_HTTP_HDR_CC, "HttpHdrCc", sizeof(HttpHdrCc), 0);
eed12adc 313 memDataInit(MEM_HTTP_HDR_RANGE_SPEC, "HttpHdrRangeSpec", sizeof(HttpHdrRangeSpec), 0);
314 memDataInit(MEM_HTTP_HDR_RANGE, "HttpHdrRange", sizeof(HttpHdrRange), 0);
d76fcfa7 315 memDataInit(MEM_HTTP_HDR_CONTENT_RANGE, "HttpHdrContRange", sizeof(HttpHdrContRange), 0);
acf5589a 316 memDataInit(MEM_INTLIST, "intlist", sizeof(intlist), 0);
acf5589a 317 memDataInit(MEM_MEMOBJECT, "MemObject", sizeof(MemObject),
318 Squid_MaxFD >> 3);
acf5589a 319 memDataInit(MEM_MEM_NODE, "mem_node", sizeof(mem_node), 0);
acf5589a 320 memDataInit(MEM_NETDBENTRY, "netdbEntry", sizeof(netdbEntry), 0);
321 memDataInit(MEM_NET_DB_NAME, "net_db_name", sizeof(net_db_name), 0);
acf5589a 322 memDataInit(MEM_RELIST, "relist", sizeof(relist), 0);
323 memDataInit(MEM_REQUEST_T, "request_t", sizeof(request_t),
324 Squid_MaxFD >> 3);
acf5589a 325 memDataInit(MEM_STOREENTRY, "StoreEntry", sizeof(StoreEntry), 0);
acf5589a 326 memDataInit(MEM_WORDLIST, "wordlist", sizeof(wordlist), 0);
59c4d35b 327 memDataInit(MEM_CLIENT_INFO, "ClientInfo", sizeof(ClientInfo), 0);
e55650e3 328 memDataInit(MEM_MD5_DIGEST, "MD5 digest", MD5_DIGEST_CHARS, 0);
c68e9c6b 329 memDataInit(MEM_HELPER_REQUEST, "helper_request",
330 sizeof(helper_request), 0);
94439e4e 331 memDataInit(MEM_HELPER_STATEFUL_REQUEST, "helper_stateful_request",
332 sizeof(helper_stateful_request), 0);
58cd5bbd 333 memDataInit(MEM_TLV, "storeSwapTLV", sizeof(tlv), 0);
58cd5bbd 334 memDataInit(MEM_SWAP_LOG_DATA, "storeSwapLogData", sizeof(storeSwapLogData), 0);
335
58a39dc9 336 /* init string pools */
337 for (i = 0; i < mem_str_pool_count; i++) {
338 StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
339 }
340 cachemgrRegister("mem",
341 "Memory Utilization",
342 memStats, 0, 1);
343}
344
345/*
346 * Test that all entries are initialized
347 */
348void
349memCheckInit(void)
350{
351 mem_type t;
728da2ee 352 for (t = MEM_NONE, t++; t < MEM_MAX; t++) {
d90c79ee 353 if (MEM_DONTFREE == t)
5999b776 354 continue;
acf5589a 355 /*
356 * If you hit this assertion, then you forgot to add a
e13ee7ad 357 * memDataInit() line for type 't'.
acf5589a 358 */
7021844c 359 assert(MemPools[t]);
acf5589a 360 }
361}
362
363void
58a39dc9 364memClean(void)
acf5589a 365{
9fe7e747 366 memCleanModule();
acf5589a 367}
368
acf5589a 369int
370memInUse(mem_type type)
371{
b4832aa9 372 return memPoolInUseCount(MemPools[type]);
acf5589a 373}
374
375/* ick */
376
1eb41ae8 377static void
137ee196 378memFree2K(void *p)
379{
db1cd23c 380 memFree(p, MEM_2K_BUF);
137ee196 381}
382
acf5589a 383void
384memFree4K(void *p)
385{
db1cd23c 386 memFree(p, MEM_4K_BUF);
acf5589a 387}
388
389void
390memFree8K(void *p)
391{
db1cd23c 392 memFree(p, MEM_8K_BUF);
acf5589a 393}
58cd5bbd 394
1eb41ae8 395static void
58cd5bbd 396memFree16K(void *p)
397{
398 memFree(p, MEM_16K_BUF);
399}
400
1eb41ae8 401static void
58cd5bbd 402memFree32K(void *p)
403{
404 memFree(p, MEM_32K_BUF);
405}
406
1eb41ae8 407static void
58cd5bbd 408memFree64K(void *p)
409{
410 memFree(p, MEM_64K_BUF);
411}
1eb41ae8 412
413FREE *
414memFreeBufFunc(size_t size)
415{
416 switch(size)
417 {
418 case 2*1024:
419 return memFree2K;
420 case 4*1024:
421 return memFree4K;
422 case 8*1024:
423 return memFree8K;
424 case 16*1024:
425 return memFree16K;
426 case 32*1024:
427 return memFree32K;
428 case 64*1024:
429 return memFree64K;
430 default:
431 memMeterDec(HugeBufCountMeter);
432 memMeterDel(HugeBufVolumeMeter, size);
433 return xfree;
434 }
435}