]>
Commit | Line | Data |
---|---|---|
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 | 40 | static MemPool *MemPools[MEM_MAX]; |
acf5589a | 41 | |
9fe7e747 | 42 | /* string pools */ |
43 | #define mem_str_pool_count 3 | |
ec878047 | 44 | static 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 | 59 | static struct { |
60 | MemPool *pool; | |
61 | } StrPools[mem_str_pool_count]; | |
9fe7e747 | 62 | static MemMeter StrCountMeter; |
63 | static MemMeter StrVolumeMeter; | |
64 | ||
1eb41ae8 | 65 | static MemMeter HugeBufCountMeter; |
66 | static MemMeter HugeBufVolumeMeter; | |
9fe7e747 | 67 | |
68 | /* local routines */ | |
69 | ||
9fe7e747 | 70 | static void |
71 | memStringStats(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 | ||
100 | static void | |
101 | memBufStats(StoreEntry *sentry) | |
102 | { | |
103 | storeAppendPrintf(sentry, "Large buffers: %d (%d KB)\n", | |
104 | HugeBufCountMeter.level, | |
105 | HugeBufVolumeMeter.level / 1024); | |
9fe7e747 | 106 | } |
107 | ||
acf5589a | 108 | static void |
7021844c | 109 | memStats(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 | */ | |
127 | void | |
128 | memDataInit(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 | 136 | void * |
7021844c | 137 | memAllocate(mem_type type) |
acf5589a | 138 | { |
7021844c | 139 | return memPoolAlloc(MemPools[type]); |
acf5589a | 140 | } |
141 | ||
db1cd23c | 142 | /* give memory back to the pool */ |
acf5589a | 143 | void |
db1cd23c | 144 | memFree(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 */ |
150 | void * | |
4be8fe59 | 151 | memAllocString(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 | 170 | void |
4be8fe59 | 171 | memFreeString(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 */ |
189 | static mem_type | |
190 | memFindBufSizeType(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 */ | |
222 | void * | |
223 | memAllocBuf(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 */ | |
236 | void * | |
237 | memReallocBuf(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() */ | |
254 | void | |
255 | memFreeBuf(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 | 268 | void |
269 | memInit(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 | */ | |
348 | void | |
349 | memCheckInit(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 | ||
363 | void | |
58a39dc9 | 364 | memClean(void) |
acf5589a | 365 | { |
9fe7e747 | 366 | memCleanModule(); |
acf5589a | 367 | } |
368 | ||
acf5589a | 369 | int |
370 | memInUse(mem_type type) | |
371 | { | |
b4832aa9 | 372 | return memPoolInUseCount(MemPools[type]); |
acf5589a | 373 | } |
374 | ||
375 | /* ick */ | |
376 | ||
1eb41ae8 | 377 | static void |
137ee196 | 378 | memFree2K(void *p) |
379 | { | |
db1cd23c | 380 | memFree(p, MEM_2K_BUF); |
137ee196 | 381 | } |
382 | ||
acf5589a | 383 | void |
384 | memFree4K(void *p) | |
385 | { | |
db1cd23c | 386 | memFree(p, MEM_4K_BUF); |
acf5589a | 387 | } |
388 | ||
389 | void | |
390 | memFree8K(void *p) | |
391 | { | |
db1cd23c | 392 | memFree(p, MEM_8K_BUF); |
acf5589a | 393 | } |
58cd5bbd | 394 | |
1eb41ae8 | 395 | static void |
58cd5bbd | 396 | memFree16K(void *p) |
397 | { | |
398 | memFree(p, MEM_16K_BUF); | |
399 | } | |
400 | ||
1eb41ae8 | 401 | static void |
58cd5bbd | 402 | memFree32K(void *p) |
403 | { | |
404 | memFree(p, MEM_32K_BUF); | |
405 | } | |
406 | ||
1eb41ae8 | 407 | static void |
58cd5bbd | 408 | memFree64K(void *p) |
409 | { | |
410 | memFree(p, MEM_64K_BUF); | |
411 | } | |
1eb41ae8 | 412 | |
413 | FREE * | |
414 | memFreeBufFunc(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 | } |