MemPool.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: MemPool.c,v 1.20 1999/01/19 20:43:45 wessels Exp $
  3.  *
  4.  * DEBUG: section 63    Low Level Memory Pool Management
  5.  * AUTHOR: Alex Rousskov
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #include "Stack.h"
  36. #define MB ((size_t)1024*1024)
  37. /* module globals */
  38. /* huge constant to set mem_idle_limit to "unlimited" */
  39. static const size_t mem_unlimited_size = 2 * 1024 * MB;
  40. /* we cannot keep idle more than this limit */
  41. static size_t mem_idle_limit = 0;
  42. /* memory pool accounting */
  43. static MemPoolMeter TheMeter;
  44. static gb_t mem_traffic_volume =
  45. {0, 0};
  46. static Stack Pools;
  47. /* local prototypes */
  48. static void memShrink(size_t new_limit);
  49. static void memPoolDescribe(const MemPool * pool);
  50. static void memPoolShrink(MemPool * pool, size_t new_limit);
  51. static double
  52. toMB(size_t size)
  53. {
  54.     return ((double) size) / MB;
  55. }
  56. static size_t
  57. toKB(size_t size)
  58. {
  59.     return (size + 1024 - 1) / 1024;
  60. }
  61. /* Initialization */
  62. void
  63. memConfigure(void)
  64. {
  65.     size_t new_pool_limit = mem_idle_limit;
  66.     /* set to configured value first */
  67. #if PURIFY
  68.     debug(63, 1) ("Disabling Memory pools under purifyn");
  69.     Config.onoff.mem_pools = 0;
  70. #endif
  71.     if (!Config.onoff.mem_pools)
  72. new_pool_limit = 0;
  73.     else if (Config.MemPools.limit > 0)
  74. new_pool_limit = Config.MemPools.limit;
  75.     else
  76. new_pool_limit = mem_unlimited_size;
  77.     /* shrink memory pools if needed */
  78.     if (TheMeter.idle.level > new_pool_limit) {
  79. debug(63, 1) ("Shrinking idle mem pools to %.2f MBn", toMB(new_pool_limit));
  80. memShrink(new_pool_limit);
  81.     }
  82.     assert(TheMeter.idle.level <= new_pool_limit);
  83.     mem_idle_limit = new_pool_limit;
  84. }
  85. void
  86. memInitModule(void)
  87. {
  88.     memset(&TheMeter, 0, sizeof(TheMeter));
  89.     stackInit(&Pools);
  90.     debug(63, 1) ("Memory pools are '%s'; limit: %.2f MBn",
  91. (Config.onoff.mem_pools ? "on" : "off"), toMB(mem_idle_limit));
  92. }
  93. void
  94. memCleanModule(void)
  95. {
  96.     int i;
  97.     int dirty_count = 0;
  98.     for (i = 0; i < Pools.count; i++) {
  99. MemPool *pool = Pools.items[i];
  100. if (memPoolInUseCount(pool)) {
  101.     memPoolDescribe(pool);
  102.     dirty_count++;
  103. } else {
  104.     memPoolDestroy(pool);
  105.     Pools.items[i] = NULL;
  106. }
  107.     }
  108.     if (dirty_count)
  109. debug(63, 2) ("memCleanModule: %d pools are left dirtyn", dirty_count);
  110.     /* we clean the stack anyway */
  111.     stackClean(&Pools);
  112. }
  113. static void
  114. memShrink(size_t new_limit)
  115. {
  116.     size_t start_limit = TheMeter.idle.level;
  117.     int i;
  118.     assert(start_limit >= 0 && new_limit >= 0);
  119.     debug(63, 1) ("memShrink: started with %d KB goal: %d KBn",
  120. toKB(TheMeter.idle.level), toKB(new_limit));
  121.     /* first phase: cut proportionally to the pool idle size */
  122.     for (i = 0; i < Pools.count && TheMeter.idle.level > new_limit; ++i) {
  123. MemPool *pool = Pools.items[i];
  124. const size_t target_pool_size = (size_t) ((double) pool->meter.idle.level * new_limit) / start_limit;
  125. memPoolShrink(pool, target_pool_size);
  126.     }
  127.     debug(63, 1) ("memShrink: 1st phase done with %d KB leftn", toKB(TheMeter.idle.level));
  128.     /* second phase: cut to 0 */
  129.     for (i = 0; i < Pools.count && TheMeter.idle.level > new_limit; ++i)
  130. memPoolShrink(Pools.items[i], 0);
  131.     debug(63, 1) ("memShrink: 2nd phase done with %d KB leftn", toKB(TheMeter.idle.level));
  132.     assert(TheMeter.idle.level <= new_limit); /* paranoid */
  133. }
  134. /* MemPoolMeter */
  135. static void
  136. memPoolMeterReport(const MemPoolMeter * pm, size_t obj_size,
  137.     int alloc_count, int inuse_count, int idle_count, StoreEntry * e)
  138. {
  139.     assert(pm);
  140.     storeAppendPrintf(e, "%dt %dt %dt %.2ft %dt %dt %dt %dt %dt %dt %dt %dt %dt %dt %dn",
  141.     /* alloc */
  142. alloc_count,
  143. toKB(obj_size * pm->alloc.level),
  144. toKB(obj_size * pm->alloc.hwater_level),
  145. (double) ((squid_curtime - pm->alloc.hwater_stamp) / 3600.),
  146. xpercentInt(obj_size * pm->alloc.level, TheMeter.alloc.level),
  147.     /* in use */
  148. inuse_count,
  149. toKB(obj_size * pm->inuse.level),
  150. toKB(obj_size * pm->inuse.hwater_level),
  151. xpercentInt(pm->inuse.level, pm->alloc.level),
  152.     /* idle */
  153. idle_count,
  154. toKB(obj_size * pm->idle.level),
  155. toKB(obj_size * pm->idle.hwater_level),
  156.     /* (int)rint(xpercent(pm->idle.level, pm->alloc.level)), */
  157.     /* saved */
  158. xpercentInt(pm->saved.count, mem_traffic_volume.count),
  159. xpercentInt(obj_size * gb_to_double(&pm->saved), gb_to_double(&mem_traffic_volume)),
  160. xpercentInt(pm->saved.count, pm->total.count));
  161. }
  162. /* MemMeter */
  163. void
  164. memMeterSyncHWater(MemMeter * m)
  165. {
  166.     assert(m);
  167.     if (m->hwater_level < m->level) {
  168. m->hwater_level = m->level;
  169. m->hwater_stamp = squid_curtime;
  170.     }
  171. }
  172. /* MemPool */
  173. MemPool *
  174. memPoolCreate(const char *label, size_t obj_size)
  175. {
  176.     MemPool *pool = xcalloc(1, sizeof(MemPool));
  177.     assert(label && obj_size);
  178.     pool->label = label;
  179.     pool->obj_size = obj_size;
  180.     stackInit(&pool->pstack);
  181.     /* other members are set to 0 */
  182.     stackPush(&Pools, pool);
  183.     return pool;
  184. }
  185. /*
  186.  * warning: we do not clean this entry from Pools stack assuming memPoolDestroy
  187.  * is used at the end of the program only
  188.  */
  189. void
  190. memPoolDestroy(MemPool * pool)
  191. {
  192.     assert(pool);
  193.     stackClean(&pool->pstack);
  194.     xfree(pool);
  195. }
  196. void *
  197. memPoolAlloc(MemPool * pool)
  198. {
  199.     assert(pool);
  200.     memMeterInc(pool->meter.inuse);
  201.     gb_inc(&pool->meter.total, 1);
  202.     gb_inc(&TheMeter.total, pool->obj_size);
  203.     memMeterAdd(TheMeter.inuse, pool->obj_size);
  204.     gb_inc(&mem_traffic_volume, pool->obj_size);
  205.     if (pool->pstack.count) {
  206. assert(pool->meter.idle.level);
  207. memMeterDec(pool->meter.idle);
  208. memMeterDel(TheMeter.idle, pool->obj_size);
  209. gb_inc(&pool->meter.saved, 1);
  210. gb_inc(&TheMeter.saved, pool->obj_size);
  211. return stackPop(&pool->pstack);
  212.     } else {
  213. assert(!pool->meter.idle.level);
  214. memMeterInc(pool->meter.alloc);
  215. memMeterAdd(TheMeter.alloc, pool->obj_size);
  216. return xcalloc(1, pool->obj_size);
  217.     }
  218. }
  219. void
  220. memPoolFree(MemPool * pool, void *obj)
  221. {
  222.     assert(pool && obj);
  223.     memMeterDec(pool->meter.inuse);
  224.     memMeterDel(TheMeter.inuse, pool->obj_size);
  225.     if (TheMeter.idle.level + pool->obj_size <= mem_idle_limit) {
  226. memMeterInc(pool->meter.idle);
  227. memMeterAdd(TheMeter.idle, pool->obj_size);
  228. memset(obj, 0, pool->obj_size);
  229. stackPush(&pool->pstack, obj);
  230.     } else {
  231. memMeterDec(pool->meter.alloc);
  232. memMeterDel(TheMeter.alloc, pool->obj_size);
  233. xfree(obj);
  234.     }
  235.     assert(pool->meter.idle.level <= pool->meter.alloc.level);
  236. }
  237. static void
  238. memPoolShrink(MemPool * pool, size_t new_limit)
  239. {
  240.     assert(pool);
  241.     assert(new_limit >= 0);
  242.     while (pool->meter.idle.level > new_limit && pool->pstack.count > 0) {
  243. memMeterDec(pool->meter.alloc);
  244. memMeterDec(pool->meter.idle);
  245. memMeterDel(TheMeter.idle, pool->obj_size);
  246. memMeterDel(TheMeter.alloc, pool->obj_size);
  247. xfree(stackPop(&pool->pstack));
  248.     }
  249.     assert(pool->meter.idle.level <= new_limit); /* paranoid */
  250. }
  251. int
  252. memPoolWasUsed(const MemPool * pool)
  253. {
  254.     assert(pool);
  255.     return pool->meter.alloc.hwater_level > 0;
  256. }
  257. int
  258. memPoolInUseCount(const MemPool * pool)
  259. {
  260.     assert(pool);
  261.     return pool->meter.inuse.level;
  262. }
  263. size_t
  264. memPoolInUseSize(const MemPool * pool)
  265. {
  266.     assert(pool);
  267.     return pool->obj_size * pool->meter.inuse.level;
  268. }
  269. /* to-do: make debug level a parameter? */
  270. static void
  271. memPoolDescribe(const MemPool * pool)
  272. {
  273.     assert(pool);
  274.     debug(63, 2) ("%-20s: %6d x %4d bytes = %5d KBn",
  275. pool->label, memPoolInUseCount(pool), pool->obj_size,
  276. toKB(memPoolInUseSize(pool)));
  277. }
  278. size_t
  279. memTotalAllocated(void)
  280. {
  281.     return TheMeter.alloc.level;
  282. }
  283. void
  284. memPoolReport(const MemPool * pool, StoreEntry * e)
  285. {
  286.     assert(pool);
  287.     storeAppendPrintf(e, "%-20st %4dt ",
  288. pool->label, pool->obj_size);
  289.     memPoolMeterReport(&pool->meter, pool->obj_size,
  290. pool->meter.alloc.level, pool->meter.inuse.level, pool->meter.idle.level,
  291. e);
  292. }
  293. void
  294. memReport(StoreEntry * e)
  295. {
  296.     size_t overhd_size = 0;
  297.     int alloc_count = 0;
  298.     int inuse_count = 0;
  299.     int idle_count = 0;
  300.     int i;
  301.     /* caption */
  302.     storeAppendPrintf(e, "Current memory usage:n");
  303.     /* heading */
  304.     storeAppendPrintf(e, "Poolt Obj Sizet"
  305. "Allocatedttttt In Usetttt Idlettt Allocations Savedtt Hit Ratetn"
  306. " t (bytes)t"
  307. "(#)t (KB)t high (KB)t high (hrs)t impact (%%total)t"
  308. "(#)t (KB)t high (KB)t portion (%%alloc)t"
  309. "(#)t (KB)t high (KB)t"
  310. "(%%number)t (%%volume)t"
  311. "(%%number)"
  312. "n");
  313.     /* main table */
  314.     for (i = 0; i < Pools.count; i++) {
  315. const MemPool *pool = Pools.items[i];
  316. if (memPoolWasUsed(pool)) {
  317.     memPoolReport(pool, e);
  318.     alloc_count += pool->meter.alloc.level;
  319.     inuse_count += pool->meter.inuse.level;
  320.     idle_count += pool->meter.idle.level;
  321. }
  322. overhd_size += sizeof(MemPool) + sizeof(MemPool *) +
  323.     strlen(pool->label) + 1 +
  324.     pool->pstack.capacity * sizeof(void *);
  325.     }
  326.     overhd_size += sizeof(Pools) + Pools.capacity * sizeof(MemPool *);
  327.     /* totals */
  328.     storeAppendPrintf(e, "%-20st %-4st ", "Total", "-");
  329.     memPoolMeterReport(&TheMeter, 1, alloc_count, inuse_count, idle_count, e);
  330.     storeAppendPrintf(e, "Cumulative allocated volume: %sn", gb_to_str(&mem_traffic_volume));
  331.     /* overhead */
  332.     storeAppendPrintf(e, "Current overhead: %d bytes (%.3f%%)n",
  333. overhd_size, xpercent(overhd_size, TheMeter.inuse.level));
  334.     /* limits */
  335.     storeAppendPrintf(e, "Idle pool limit: %.2f MBn", toMB(mem_idle_limit));
  336. }