]> git.ipfire.org Git - thirdparty/squid.git/blame - src/mem/old_api.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / mem / old_api.cc
CommitLineData
acf5589a 1/*
bbc27441 2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
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.
acf5589a 7 */
8
bbc27441
AJ
9/* DEBUG: section 13 High Level Memory Pool Management */
10
582c2af2 11#include "squid.h"
7f0b3324 12#include "acl/AclDenyInfoList.h"
6be70545 13#include "acl/AclNameList.h"
d8403776 14#include "CacheDigest.h"
1c898d4c 15#include "ClientInfo.h"
65914896 16#include "disk.h"
7a9b4357 17#include "dlink.h"
6be70545 18#include "event.h"
602d9612 19#include "icmp/net_db.h"
582c2af2 20#include "md5.h"
ed6e9fb9 21#include "mem/forward.h"
f327361e 22#include "mem/Pool.h"
582c2af2 23#include "MemBuf.h"
d96ceb8e 24#include "memMeter.h"
582c2af2 25#include "mgr/Registration.h"
3ebc8300 26#include "RegexList.h"
4d5904f7 27#include "SquidConfig.h"
41c97755 28#include "SquidList.h"
582c2af2 29#include "SquidTime.h"
e6ccf245 30#include "Store.h"
c21ad0f5 31#include "StoreEntryStream.h"
acf5589a 32
27e059d4 33#include <iomanip>
27e059d4 34#include <ostream>
27e059d4 35
8a89c28f
FC
36/* forward declarations */
37static void memFree2K(void *);
38static void memFree4K(void *);
39static void memFree8K(void *);
40static void memFree16K(void *);
41static void memFree32K(void *);
42static void memFree64K(void *);
43
7021844c 44/* module globals */
43d1bbe4 45const size_t squidSystemPageSize=getpagesize();
acf5589a 46
d96ceb8e 47/* local prototypes */
c21ad0f5 48static void memStringStats(std::ostream &);
d96ceb8e 49
50/* module locals */
04eb0689 51static MemAllocator *MemPools[MEM_MAX];
d96ceb8e 52static double xm_time = 0;
53static double xm_deltat = 0;
acf5589a 54
b5a644fc
FC
55/* all pools are ready to be used */
56static bool MemIsInitialized = false;
57
9fe7e747 58/* string pools */
867c718d 59#define mem_str_pool_count 6
62e76326 60
b5a644fc
FC
61// 4 bytes bigger than the biggest string pool size
62// which is in turn calculated from SmallestStringBeforeMemIsInitialized
867c718d 63static const size_t SmallestStringBeforeMemIsInitialized = 1024*16+4;
b5a644fc 64
26ac0430 65static const struct {
ec878047 66 const char *name;
9fe7e747 67 size_t obj_size;
62e76326 68}
69
70StrPoolsAttrs[mem_str_pool_count] = {
71
26ac0430
AJ
72 {
73 "Short Strings", MemAllocator::RoundedSize(36),
f53969cc 74 }, /* to fit rfc1123 and similar */
26ac0430
AJ
75 {
76 "Medium Strings", MemAllocator::RoundedSize(128),
f53969cc 77 }, /* to fit most urls */
26ac0430 78 {
867c718d
FC
79 "Long Strings", MemAllocator::RoundedSize(512),
80 },
81 {
82 "1KB Strings", MemAllocator::RoundedSize(1024),
83 },
84 {
85 "4KB Strings", MemAllocator::RoundedSize(4*1024),
86 },
87 {
88 "16KB Strings",
b5a644fc 89 MemAllocator::RoundedSize(SmallestStringBeforeMemIsInitialized-4)
867c718d 90 }
26ac0430
AJ
91};
92
93static struct {
b001e822 94 MemAllocator *pool;
62e76326 95}
96
97StrPools[mem_str_pool_count];
9fe7e747 98static MemMeter StrCountMeter;
99static MemMeter StrVolumeMeter;
100
1eb41ae8 101static MemMeter HugeBufCountMeter;
102static MemMeter HugeBufVolumeMeter;
9fe7e747 103
104/* local routines */
105
9fe7e747 106static void
c21ad0f5 107memStringStats(std::ostream &stream)
9fe7e747 108{
9fe7e747 109 int i;
110 int pooled_count = 0;
111 size_t pooled_volume = 0;
112 /* heading */
35268c70 113 stream << "String Pool\t Impact\t\t\n \t (%strings)\t (%volume)\n";
9fe7e747 114 /* table body */
62e76326 115
89235243 116 for (i = 0; i < mem_str_pool_count; ++i) {
b001e822 117 const MemAllocator *pool = StrPools[i].pool;
118 const int plevel = pool->getMeter().inuse.level;
c21ad0f5 119 stream << std::setw(20) << std::left << pool->objectType();
120 stream << std::right << "\t " << xpercentInt(plevel, StrCountMeter.level);
121 stream << "\t " << xpercentInt(plevel * pool->objectSize(), StrVolumeMeter.level) << "\n";
62e76326 122 pooled_count += plevel;
b001e822 123 pooled_volume += plevel * pool->objectSize();
9fe7e747 124 }
62e76326 125
9fe7e747 126 /* malloc strings */
c21ad0f5 127 stream << std::setw(20) << std::left << "Other Strings";
128
129 stream << std::right << "\t ";
62e76326 130
c21ad0f5 131 stream << xpercentInt(StrCountMeter.level - pooled_count, StrCountMeter.level) << "\t ";
132
133 stream << xpercentInt(StrVolumeMeter.level - pooled_volume, StrVolumeMeter.level) << "\n\n";
1eb41ae8 134}
135
136static void
c21ad0f5 137memBufStats(std::ostream & stream)
1eb41ae8 138{
c21ad0f5 139 stream << "Large buffers: " <<
f53969cc
SM
140 HugeBufCountMeter.level << " (" <<
141 HugeBufVolumeMeter.level / 1024 << " KB)\n";
9fe7e747 142}
143
528b2c61 144void
145Mem::Stats(StoreEntry * sentry)
acf5589a 146{
c21ad0f5 147 StoreEntryStream stream(sentry);
148 Report(stream);
149 memStringStats(stream);
150 memBufStats(stream);
b4bab919 151#if WITH_VALGRIND
152 if (RUNNING_ON_VALGRIND) {
26ac0430
AJ
153 long int leaked = 0, dubious = 0, reachable = 0, suppressed = 0;
154 stream << "Valgrind Report:\n";
155 stream << "Type\tAmount\n";
e0236918 156 debugs(13, DBG_IMPORTANT, "Asking valgrind for memleaks");
26ac0430 157 VALGRIND_DO_LEAK_CHECK;
e0236918 158 debugs(13, DBG_IMPORTANT, "Getting valgrind statistics");
26ac0430
AJ
159 VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed);
160 stream << "Leaked\t" << leaked << "\n";
161 stream << "Dubious\t" << dubious << "\n";
162 stream << "Reachable\t" << reachable << "\n";
163 stream << "Suppressed\t" << suppressed << "\n";
b4bab919 164 }
165#endif
c21ad0f5 166 stream.flush();
acf5589a 167}
168
169/*
9fe7e747 170 * public routines
acf5589a 171 */
172
58a39dc9 173/*
b74cf25f
AJ
174 * we have a limit on _total_ amount of idle memory so we ignore max_pages for now.
175 * Will ignore repeated calls for the same pool type.
176 *
177 * Relies on Mem::Init() having been called beforehand.
58a39dc9 178 */
179void
3b08e399 180memDataInit(mem_type type, const char *name, size_t size, int max_pages_notused, bool doZero)
58a39dc9 181{
182 assert(name && size);
b74cf25f
AJ
183
184 if (MemPools[type] != NULL)
185 return;
186
04eb0689 187 MemPools[type] = memPoolCreate(name, size);
3b08e399 188 MemPools[type]->zeroBlocks(doZero);
58a39dc9 189}
190
7021844c 191/* find appropriate pool and use it (pools always init buffer with 0s) */
acf5589a 192void *
7021844c 193memAllocate(mem_type type)
acf5589a 194{
92b77cf7 195 assert(MemPools[type]);
b001e822 196 return MemPools[type]->alloc();
acf5589a 197}
198
db1cd23c 199/* give memory back to the pool */
acf5589a 200void
db1cd23c 201memFree(void *p, int type)
acf5589a 202{
92b77cf7 203 assert(MemPools[type]);
dc47f531 204 MemPools[type]->freeOne(p);
acf5589a 205}
206
b5a644fc 207/* allocate a variable size buffer using best-fit string pool */
9fe7e747 208void *
4be8fe59 209memAllocString(size_t net_size, size_t * gross_size)
9fe7e747 210{
b001e822 211 MemAllocator *pool = NULL;
9fe7e747 212 assert(gross_size);
62e76326 213
b5a644fc
FC
214 // if pools are not yet ready, make sure that
215 // the requested size is not poolable so that the right deallocator
216 // will be used
217 if (!MemIsInitialized && net_size < SmallestStringBeforeMemIsInitialized)
d3a30598 218 net_size = SmallestStringBeforeMemIsInitialized;
b5a644fc
FC
219
220 unsigned int i;
89235243 221 for (i = 0; i < mem_str_pool_count; ++i) {
62e76326 222 if (net_size <= StrPoolsAttrs[i].obj_size) {
223 pool = StrPools[i].pool;
224 break;
225 }
9fe7e747 226 }
62e76326 227
e231a8ce 228 *gross_size = pool ? StrPoolsAttrs[i].obj_size : net_size;
9fe7e747 229 assert(*gross_size >= net_size);
b5a644fc 230 // may forget [de]allocations until MemIsInitialized
9fe7e747 231 memMeterInc(StrCountMeter);
232 memMeterAdd(StrVolumeMeter, *gross_size);
b001e822 233 return pool ? pool->alloc() : xcalloc(1, net_size);
9fe7e747 234}
235
0353e724 236size_t
237memStringCount()
238{
239 size_t result = 0;
240
241 for (int counter = 0; counter < mem_str_pool_count; ++counter)
242 result += memPoolInUseCount(StrPools[counter].pool);
243
244 return result;
245}
246
4be8fe59 247/* free buffer allocated with memAllocString() */
9fe7e747 248void
4be8fe59 249memFreeString(size_t size, void *buf)
9fe7e747 250{
b001e822 251 MemAllocator *pool = NULL;
b5a644fc
FC
252 assert(buf);
253
254 if (MemIsInitialized) {
255 for (unsigned int i = 0; i < mem_str_pool_count; ++i) {
256 if (size <= StrPoolsAttrs[i].obj_size) {
257 assert(size == StrPoolsAttrs[i].obj_size);
258 pool = StrPools[i].pool;
259 break;
260 }
62e76326 261 }
9fe7e747 262 }
62e76326 263
b5a644fc 264 // may forget [de]allocations until MemIsInitialized
9fe7e747 265 memMeterDec(StrCountMeter);
266 memMeterDel(StrVolumeMeter, size);
dc47f531 267 pool ? pool->freeOne(buf) : xfree(buf);
9fe7e747 268}
269
1eb41ae8 270/* Find the best fit MEM_X_BUF type */
271static mem_type
272memFindBufSizeType(size_t net_size, size_t * gross_size)
273{
274 mem_type type;
275 size_t size;
62e76326 276
fa80a8ef 277 if (net_size <= 2 * 1024) {
62e76326 278 type = MEM_2K_BUF;
279 size = 2 * 1024;
fa80a8ef 280 } else if (net_size <= 4 * 1024) {
62e76326 281 type = MEM_4K_BUF;
282 size = 4 * 1024;
fa80a8ef 283 } else if (net_size <= 8 * 1024) {
62e76326 284 type = MEM_8K_BUF;
285 size = 8 * 1024;
fa80a8ef 286 } else if (net_size <= 16 * 1024) {
62e76326 287 type = MEM_16K_BUF;
288 size = 16 * 1024;
fa80a8ef 289 } else if (net_size <= 32 * 1024) {
62e76326 290 type = MEM_32K_BUF;
291 size = 32 * 1024;
fa80a8ef 292 } else if (net_size <= 64 * 1024) {
62e76326 293 type = MEM_64K_BUF;
294 size = 64 * 1024;
1eb41ae8 295 } else {
62e76326 296 type = MEM_NONE;
297 size = net_size;
1eb41ae8 298 }
62e76326 299
1eb41ae8 300 if (gross_size)
62e76326 301 *gross_size = size;
302
1eb41ae8 303 return type;
304}
305
306/* allocate a variable size buffer using best-fit pool */
307void *
308memAllocBuf(size_t net_size, size_t * gross_size)
309{
310 mem_type type = memFindBufSizeType(net_size, gross_size);
62e76326 311
1eb41ae8 312 if (type != MEM_NONE)
62e76326 313 return memAllocate(type);
1eb41ae8 314 else {
62e76326 315 memMeterInc(HugeBufCountMeter);
316 memMeterAdd(HugeBufVolumeMeter, *gross_size);
317 return xcalloc(1, net_size);
1eb41ae8 318 }
319}
320
321/* resize a variable sized buffer using best-fit pool */
322void *
323memReallocBuf(void *oldbuf, size_t net_size, size_t * gross_size)
324{
325 /* XXX This can be optimized on very large buffers to use realloc() */
edce4d98 326 /* TODO: if the existing gross size is >= new gross size, do nothing */
e6ccf245 327 size_t new_gross_size;
1eb41ae8 328 void *newbuf = memAllocBuf(net_size, &new_gross_size);
62e76326 329
1eb41ae8 330 if (oldbuf) {
62e76326 331 size_t data_size = *gross_size;
332
333 if (data_size > net_size)
334 data_size = net_size;
335
336 memcpy(newbuf, oldbuf, data_size);
337
338 memFreeBuf(*gross_size, oldbuf);
1eb41ae8 339 }
62e76326 340
1eb41ae8 341 *gross_size = new_gross_size;
342 return newbuf;
343}
344
345/* free buffer allocated with memAllocBuf() */
346void
347memFreeBuf(size_t size, void *buf)
348{
349 mem_type type = memFindBufSizeType(size, NULL);
62e76326 350
1eb41ae8 351 if (type != MEM_NONE)
62e76326 352 memFree(buf, type);
1eb41ae8 353 else {
62e76326 354 xfree(buf);
355 memMeterDec(HugeBufCountMeter);
356 memMeterDel(HugeBufVolumeMeter, size);
1eb41ae8 357 }
358}
359
f53969cc 360static double clean_interval = 15.0; /* time to live of idle chunk before release */
d96ceb8e 361
362void
528b2c61 363Mem::CleanIdlePools(void *unused)
d96ceb8e 364{
b001e822 365 MemPools::GetInstance().clean(static_cast<time_t>(clean_interval));
528b2c61 366 eventAdd("memPoolCleanIdlePools", CleanIdlePools, NULL, clean_interval, 1);
d96ceb8e 367}
368
d96ceb8e 369void
370memConfigure(void)
371{
70be1349 372 int64_t new_pool_limit;
62e76326 373
09c5ae5a 374 /** Set to configured value first */
d96ceb8e 375 if (!Config.onoff.mem_pools)
62e76326 376 new_pool_limit = 0;
d96ceb8e 377 else if (Config.MemPools.limit > 0)
62e76326 378 new_pool_limit = Config.MemPools.limit;
89646bd7 379 else {
c8768728 380 if (Config.MemPools.limit == 0)
e0236918 381 debugs(13, DBG_IMPORTANT, "memory_pools_limit 0 has been chagned to memory_pools_limit none. Please update your config");
89646bd7
HN
382 new_pool_limit = -1;
383 }
d96ceb8e 384
af00d03d 385#if 0
09c5ae5a 386 /** \par
af00d03d 387 * DPW 2007-04-12
388 * No debugging here please because this method is called before
389 * the debug log is configured and we'll get the message on
390 * stderr when doing things like 'squid -k reconfigure'
391 */
b001e822 392 if (MemPools::GetInstance().idleLimit() > new_pool_limit)
e0236918 393 debugs(13, DBG_IMPORTANT, "Shrinking idle mem pools to "<< std::setprecision(3) << toMB(new_pool_limit) << " MB");
af00d03d 394#endif
62e76326 395
b001e822 396 MemPools::GetInstance().setIdleLimit(new_pool_limit);
d96ceb8e 397}
1eb41ae8 398
528b2c61 399/* XXX make these classes do their own memory management */
400#include "HttpHdrContRange.h"
401
acf5589a 402void
528b2c61 403Mem::Init(void)
acf5589a 404{
9fe7e747 405 int i;
d96ceb8e 406
09c5ae5a 407 /** \par
33135cfb 408 * NOTE: Mem::Init() is called before the config file is parsed
409 * and before the debugging module has been initialized. Any
410 * debug messages here at level 0 or 1 will always be printed
411 * on stderr.
412 */
d96ceb8e 413
09c5ae5a
AJ
414 /** \par
415 * Set all pointers to null. */
7021844c 416 memset(MemPools, '\0', sizeof(MemPools));
09c5ae5a
AJ
417 /**
418 * Then initialize all pools.
419 * \par
420 * Starting with generic 2kB - 64kB buffr pools, then specific object types.
421 * \par
422 * It does not hurt much to have a lot of pools since sizeof(MemPool) is
7021844c 423 * small; someday we will figure out what to do with all the entries here
424 * that are never used or used only once; perhaps we should simply use
425 * malloc() for those? @?@
426 */
60da11d3 427 memDataInit(MEM_2K_BUF, "2K Buffer", 2048, 10, false);
428 memDataInit(MEM_4K_BUF, "4K Buffer", 4096, 10, false);
429 memDataInit(MEM_8K_BUF, "8K Buffer", 8192, 10, false);
430 memDataInit(MEM_16K_BUF, "16K Buffer", 16384, 10, false);
431 memDataInit(MEM_32K_BUF, "32K Buffer", 32768, 10, false);
432 memDataInit(MEM_64K_BUF, "64K Buffer", 65536, 10, false);
7f0b3324
FC
433 memDataInit(MEM_ACL_DENY_INFO_LIST, "AclDenyInfoList",
434 sizeof(AclDenyInfoList), 0);
6be70545 435 memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(AclNameList), 0);
c68e9c6b 436#if USE_CACHE_DIGESTS
62e76326 437
26c2ce6f 438 memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0);
c68e9c6b 439#endif
62e76326 440
58cd5bbd 441 memDataInit(MEM_LINK_LIST, "link_list", sizeof(link_list), 10);
acf5589a 442 memDataInit(MEM_DLINK_NODE, "dlink_node", sizeof(dlink_node), 10);
acf5589a 443 memDataInit(MEM_DREAD_CTRL, "dread_ctrl", sizeof(dread_ctrl), 0);
444 memDataInit(MEM_DWRITE_Q, "dwrite_q", sizeof(dwrite_q), 0);
d76fcfa7 445 memDataInit(MEM_HTTP_HDR_CONTENT_RANGE, "HttpHdrContRange", sizeof(HttpHdrContRange), 0);
acf5589a 446 memDataInit(MEM_NETDBENTRY, "netdbEntry", sizeof(netdbEntry), 0);
447 memDataInit(MEM_NET_DB_NAME, "net_db_name", sizeof(net_db_name), 0);
3ebc8300 448 memDataInit(MEM_RELIST, "RegexList", sizeof(RegexList), 0);
59c4d35b 449 memDataInit(MEM_CLIENT_INFO, "ClientInfo", sizeof(ClientInfo), 0);
c3031d67 450 memDataInit(MEM_MD5_DIGEST, "MD5 digest", SQUID_MD5_DIGEST_LENGTH, 0);
b001e822 451 MemPools[MEM_MD5_DIGEST]->setChunkSize(512 * 1024);
58cd5bbd 452
09c5ae5a 453 /** Lastly init the string pools. */
89235243 454 for (i = 0; i < mem_str_pool_count; ++i) {
04eb0689 455 StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
3b08e399 456 StrPools[i].pool->zeroBlocks(false);
e231a8ce 457
b001e822 458 if (StrPools[i].pool->objectSize() != StrPoolsAttrs[i].obj_size)
e0236918 459 debugs(13, DBG_IMPORTANT, "Notice: " << StrPoolsAttrs[i].name << " is " << StrPools[i].pool->objectSize() << " bytes instead of requested " << StrPoolsAttrs[i].obj_size << " bytes");
58a39dc9 460 }
ea391f18 461
b5a644fc 462 MemIsInitialized = true;
ed6e9fb9
AJ
463
464 // finally register with the cache manager
465 Mgr::RegisterAction("mem", "Memory Utilization", Mem::Stats, 0, 1);
62ee09ca 466}
62e76326 467
97244680 468void
469Mem::Report()
470{
471 debugs(13, 3, "Memory pools are '" <<
26ac0430
AJ
472 (Config.onoff.mem_pools ? "on" : "off") << "'; limit: " <<
473 std::setprecision(3) << toMB(MemPools::GetInstance().idleLimit()) <<
474 " MB");
97244680 475}
476
e6ccf245 477mem_type &operator++ (mem_type &aMem)
478{
1f1ae50a 479 int tmp = (int)aMem;
480 aMem = (mem_type)(++tmp);
e6ccf245 481 return aMem;
482}
483
58a39dc9 484/*
485 * Test that all entries are initialized
486 */
487void
488memCheckInit(void)
489{
92b77cf7 490 mem_type t = MEM_NONE;
62e76326 491
92b77cf7 492 while (++t < MEM_DONTFREE) {
62e76326 493 /*
494 * If you hit this assertion, then you forgot to add a
495 * memDataInit() line for type 't'.
92b77cf7 496 * Or placed the pool type in the wrong section of the enum list.
62e76326 497 */
498 assert(MemPools[t]);
acf5589a 499 }
500}
501
502void
58a39dc9 503memClean(void)
acf5589a 504{
d96ceb8e 505 MemPoolGlobalStats stats;
f5f9e44c
AR
506 if (Config.MemPools.limit > 0) // do not reset if disabled or same
507 MemPools::GetInstance().setIdleLimit(0);
b001e822 508 MemPools::GetInstance().clean(0);
d96ceb8e 509 memPoolGetGlobalStats(&stats);
62e76326 510
d96ceb8e 511 if (stats.tot_items_inuse)
bf8fe701 512 debugs(13, 2, "memCleanModule: " << stats.tot_items_inuse <<
513 " items in " << stats.tot_chunks_inuse << " chunks and " <<
514 stats.tot_pools_inuse << " pools are left dirty");
acf5589a 515}
516
acf5589a 517int
518memInUse(mem_type type)
519{
b4832aa9 520 return memPoolInUseCount(MemPools[type]);
acf5589a 521}
522
523/* ick */
524
e4ae841b 525void
137ee196 526memFree2K(void *p)
527{
db1cd23c 528 memFree(p, MEM_2K_BUF);
137ee196 529}
530
acf5589a 531void
532memFree4K(void *p)
533{
db1cd23c 534 memFree(p, MEM_4K_BUF);
acf5589a 535}
536
537void
538memFree8K(void *p)
539{
db1cd23c 540 memFree(p, MEM_8K_BUF);
acf5589a 541}
58cd5bbd 542
e4ae841b 543void
58cd5bbd 544memFree16K(void *p)
545{
546 memFree(p, MEM_16K_BUF);
547}
548
e4ae841b 549void
58cd5bbd 550memFree32K(void *p)
551{
552 memFree(p, MEM_32K_BUF);
553}
554
e4ae841b 555void
58cd5bbd 556memFree64K(void *p)
557{
558 memFree(p, MEM_64K_BUF);
559}
1eb41ae8 560
59a09b98
FC
561static void
562cxx_xfree(void * ptr)
563{
f673997d 564 xfree(ptr);
59a09b98
FC
565}
566
1eb41ae8 567FREE *
568memFreeBufFunc(size_t size)
569{
fa80a8ef 570 switch (size) {
62e76326 571
fa80a8ef 572 case 2 * 1024:
62e76326 573 return memFree2K;
574
fa80a8ef 575 case 4 * 1024:
62e76326 576 return memFree4K;
577
fa80a8ef 578 case 8 * 1024:
62e76326 579 return memFree8K;
580
fa80a8ef 581 case 16 * 1024:
62e76326 582 return memFree16K;
583
fa80a8ef 584 case 32 * 1024:
62e76326 585 return memFree32K;
586
fa80a8ef 587 case 64 * 1024:
62e76326 588 return memFree64K;
589
1eb41ae8 590 default:
62e76326 591 memMeterDec(HugeBufCountMeter);
592 memMeterDel(HugeBufVolumeMeter, size);
59a09b98 593 return cxx_xfree;
1eb41ae8 594 }
595}
d96ceb8e 596
597/* MemPoolMeter */
598
528b2c61 599void
c21ad0f5 600Mem::PoolReport(const MemPoolStats * mp_st, const MemPoolMeter * AllMeter, std::ostream &stream)
d96ceb8e 601{
60eed7c2 602 int excess = 0;
d96ceb8e 603 int needed = 0;
604 MemPoolMeter *pm = mp_st->meter;
eecdacf6 605 const char *delim = "\t ";
d96ceb8e 606
903a6eec 607 stream.setf(std::ios_base::fixed);
eecdacf6 608 stream << std::setw(20) << std::left << mp_st->label << delim;
609 stream << std::setw(4) << std::right << mp_st->obj_size << delim;
d96ceb8e 610
611 /* Chunks */
d96ceb8e 612 if (mp_st->chunk_capacity) {
3b32112a
A
613 stream << std::setw(4) << toKB(mp_st->obj_size * mp_st->chunk_capacity) << delim;
614 stream << std::setw(4) << mp_st->chunk_capacity << delim;
333c86f5 615
62e76326 616 needed = mp_st->items_inuse / mp_st->chunk_capacity;
617
618 if (mp_st->items_inuse % mp_st->chunk_capacity)
89235243 619 ++needed;
62e76326 620
621 excess = mp_st->chunks_inuse - needed;
62e76326 622
3b32112a
A
623 stream << std::setw(4) << mp_st->chunks_alloc << delim;
624 stream << std::setw(4) << mp_st->chunks_inuse << delim;
625 stream << std::setw(4) << mp_st->chunks_free << delim;
626 stream << std::setw(4) << mp_st->chunks_partial << delim;
627 stream << std::setprecision(3) << xpercent(excess, needed) << delim;
333c86f5 628 } else {
3b32112a
A
629 stream << delim;
630 stream << delim;
631 stream << delim;
632 stream << delim;
633 stream << delim;
634 stream << delim;
635 stream << delim;
333c86f5 636 }
62e76326 637 /*
638 * Fragmentation calculation:
639 * needed = inuse.level / chunk_capacity
640 * excess = used - needed
641 * fragmentation = excess / needed * 100%
642 *
643 * Fragm = (alloced - (inuse / obj_ch) ) / alloced
644 */
c21ad0f5 645 /* allocated */
eecdacf6 646 stream << mp_st->items_alloc << delim;
647 stream << toKB(mp_st->obj_size * pm->alloc.level) << delim;
648 stream << toKB(mp_st->obj_size * pm->alloc.hwater_level) << delim;
649 stream << std::setprecision(2) << ((squid_curtime - pm->alloc.hwater_stamp) / 3600.) << delim;
650 stream << std::setprecision(3) << xpercent(mp_st->obj_size * pm->alloc.level, AllMeter->alloc.level) << delim;
c21ad0f5 651 /* in use */
eecdacf6 652 stream << mp_st->items_inuse << delim;
653 stream << toKB(mp_st->obj_size * pm->inuse.level) << delim;
654 stream << toKB(mp_st->obj_size * pm->inuse.hwater_level) << delim;
655 stream << std::setprecision(2) << ((squid_curtime - pm->inuse.hwater_stamp) / 3600.) << delim;
656 stream << std::setprecision(3) << xpercent(pm->inuse.level, pm->alloc.level) << delim;
c21ad0f5 657 /* idle */
eecdacf6 658 stream << mp_st->items_idle << delim;
659 stream << toKB(mp_st->obj_size * pm->idle.level) << delim;
660 stream << toKB(mp_st->obj_size * pm->idle.hwater_level) << delim;
c21ad0f5 661 /* saved */
eecdacf6 662 stream << (int)pm->gb_saved.count << delim;
903a6eec
HN
663 stream << std::setprecision(3) << xpercent(pm->gb_saved.count, AllMeter->gb_allocated.count) << delim;
664 stream << std::setprecision(3) << xpercent(pm->gb_saved.bytes, AllMeter->gb_allocated.bytes) << delim;
665 stream << std::setprecision(3) << xdiv(pm->gb_allocated.count - pm->gb_oallocated.count, xm_deltat) << "\n";
666 pm->gb_oallocated.count = pm->gb_allocated.count;
d96ceb8e 667}
668
729102f4 669static int
670MemPoolReportSorter(const void *a, const void *b)
671{
672 const MemPoolStats *A = (MemPoolStats *) a;
673 const MemPoolStats *B = (MemPoolStats *) b;
674
675 // use this to sort on %Total Allocated
676 //
677 double pa = (double) A->obj_size * A->meter->alloc.level;
678 double pb = (double) B->obj_size * B->meter->alloc.level;
679
680 if (pa > pb)
681 return -1;
682
683 if (pb > pa)
684 return 1;
685
686#if 0
687 // use this to sort on In Use high(hrs)
688 //
689 if (A->meter->inuse.hwater_stamp > B->meter->inuse.hwater_stamp)
690 return -1;
691
692 if (B->meter->inuse.hwater_stamp > A->meter->inuse.hwater_stamp)
693 return 1;
694
695#endif
696
697 return 0;
698}
699
d96ceb8e 700void
c21ad0f5 701Mem::Report(std::ostream &stream)
d96ceb8e 702{
703 static char buf[64];
704 static MemPoolStats mp_stats;
705 static MemPoolGlobalStats mp_total;
706 int not_used = 0;
707 MemPoolIterator *iter;
b001e822 708 MemAllocator *pool;
d96ceb8e 709
710 /* caption */
c21ad0f5 711 stream << "Current memory usage:\n";
d96ceb8e 712 /* heading */
c21ad0f5 713 stream << "Pool\t Obj Size\t"
f53969cc
SM
714 "Chunks\t\t\t\t\t\t\t"
715 "Allocated\t\t\t\t\t"
716 "In Use\t\t\t\t\t"
717 "Idle\t\t\t"
718 "Allocations Saved\t\t\t"
719 "Rate\t"
720 "\n"
721 " \t (bytes)\t"
722 "KB/ch\t obj/ch\t"
723 "(#)\t used\t free\t part\t %Frag\t "
724 "(#)\t (KB)\t high (KB)\t high (hrs)\t %Tot\t"
725 "(#)\t (KB)\t high (KB)\t high (hrs)\t %alloc\t"
726 "(#)\t (KB)\t high (KB)\t"
727 "(#)\t %cnt\t %vol\t"
728 "(#)/sec\t"
729 "\n";
d96ceb8e 730 xm_deltat = current_dtime - xm_time;
731 xm_time = current_dtime;
732
733 /* Get stats for Totals report line */
734 memPoolGetGlobalStats(&mp_total);
735
729102f4 736 MemPoolStats *sortme = (MemPoolStats *) xcalloc(mp_total.tot_pools_alloc ,sizeof(*sortme));
737 int npools = 0;
738
d96ceb8e 739 /* main table */
740 iter = memPoolIterate();
62e76326 741
d96ceb8e 742 while ((pool = memPoolIterateNext(iter))) {
b001e822 743 pool->getStats(&mp_stats);
62e76326 744
f53969cc 745 if (!mp_stats.pool) /* pool destroyed */
62e76326 746 continue;
747
f412b2d6
FC
748 if (mp_stats.pool->getMeter().gb_allocated.count > 0) {
749 /* this pool has been used */
750 sortme[npools] = mp_stats;
751 ++npools;
752 } else {
89235243 753 ++not_used;
f412b2d6 754 }
d96ceb8e 755 }
62e76326 756
d96ceb8e 757 memPoolIterateDone(&iter);
758
729102f4 759 qsort(sortme, npools, sizeof(*sortme), MemPoolReportSorter);
760
89235243 761 for (int i = 0; i< npools; ++i) {
c21ad0f5 762 PoolReport(&sortme[i], mp_total.TheMeter, stream);
729102f4 763 }
764
765 xfree(sortme);
766
d96ceb8e 767 mp_stats.pool = NULL;
768 mp_stats.label = "Total";
769 mp_stats.meter = mp_total.TheMeter;
770 mp_stats.obj_size = 1;
771 mp_stats.chunk_capacity = 0;
772 mp_stats.chunk_size = 0;
773 mp_stats.chunks_alloc = mp_total.tot_chunks_alloc;
774 mp_stats.chunks_inuse = mp_total.tot_chunks_inuse;
775 mp_stats.chunks_partial = mp_total.tot_chunks_partial;
776 mp_stats.chunks_free = mp_total.tot_chunks_free;
777 mp_stats.items_alloc = mp_total.tot_items_alloc;
778 mp_stats.items_inuse = mp_total.tot_items_inuse;
779 mp_stats.items_idle = mp_total.tot_items_idle;
780 mp_stats.overhead = mp_total.tot_overhead;
781
c21ad0f5 782 PoolReport(&mp_stats, mp_total.TheMeter, stream);
d96ceb8e 783
784 /* Cumulative */
903a6eec 785 stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.TheMeter->gb_allocated.bytes) << "\n";
d96ceb8e 786 /* overhead */
c21ad0f5 787 stream << "Current overhead: " << mp_total.tot_overhead << " bytes (" <<
f53969cc 788 std::setprecision(3) << xpercent(mp_total.tot_overhead, mp_total.TheMeter->inuse.level) << "%)\n";
d96ceb8e 789 /* limits */
89646bd7
HN
790 if (mp_total.mem_idle_limit >= 0)
791 stream << "Idle pool limit: " << std::setprecision(2) << toMB(mp_total.mem_idle_limit) << " MB\n";
d96ceb8e 792 /* limits */
c21ad0f5 793 stream << "Total Pools created: " << mp_total.tot_pools_alloc << "\n";
794 stream << "Pools ever used: " << mp_total.tot_pools_alloc - not_used << " (shown above)\n";
795 stream << "Currently in use: " << mp_total.tot_pools_inuse << "\n";
d96ceb8e 796}
f53969cc 797