diff options
Diffstat (limited to 'libglusterfs/src/mem-pool.c')
| -rw-r--r-- | libglusterfs/src/mem-pool.c | 188 |
1 files changed, 103 insertions, 85 deletions
diff --git a/libglusterfs/src/mem-pool.c b/libglusterfs/src/mem-pool.c index 0d555020b..b901dd7a8 100644 --- a/libglusterfs/src/mem-pool.c +++ b/libglusterfs/src/mem-pool.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2008-2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include "mem-pool.h" @@ -24,10 +15,12 @@ #include <stdarg.h> #define GF_MEM_POOL_LIST_BOUNDARY (sizeof(struct list_head)) -#define GF_MEM_POOL_PAD_BOUNDARY (GF_MEM_POOL_LIST_BOUNDARY + sizeof(int)) +#define GF_MEM_POOL_PTR (sizeof(struct mem_pool*)) +#define GF_MEM_POOL_PAD_BOUNDARY (GF_MEM_POOL_LIST_BOUNDARY + GF_MEM_POOL_PTR + sizeof(int)) #define mem_pool_chunkhead2ptr(head) ((head) + GF_MEM_POOL_PAD_BOUNDARY) #define mem_pool_ptr2chunkhead(ptr) ((ptr) - GF_MEM_POOL_PAD_BOUNDARY) #define is_mem_chunk_in_use(ptr) (*ptr == 1) +#define mem_pool_from_ptr(ptr) ((ptr) + GF_MEM_POOL_LIST_BOUNDARY) #define GF_MEM_HEADER_SIZE (4 + sizeof (size_t) + sizeof (xlator_t *) + 4 + 8) #define GF_MEM_TRAILER_SIZE 8 @@ -37,37 +30,18 @@ #define GLUSTERFS_ENV_MEM_ACCT_STR "GLUSTERFS_DISABLE_MEM_ACCT" -static int gf_mem_acct_enable = 0; - -int -gf_mem_acct_is_enabled () -{ - return gf_mem_acct_enable; -} - void -gf_mem_acct_enable_set () +gf_mem_acct_enable_set (void *data) { - char *opt = NULL; - long val = -1; - -#ifdef DEBUG - gf_mem_acct_enable = 1; - return; -#endif + glusterfs_ctx_t *ctx = NULL; - opt = getenv (GLUSTERFS_ENV_MEM_ACCT_STR); - - if (!opt) - return; + ctx = data; - val = strtol (opt, NULL, 0); + GF_ASSERT (ctx); - if (val) - gf_mem_acct_enable = 0; - else - gf_mem_acct_enable = 1; + ctx->mem_acct_enable = 1; + return; } void @@ -82,22 +56,17 @@ gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr, ptr = (char *) (*alloc_ptr); - if (!xl) { - GF_ASSERT (0); - } + GF_ASSERT (xl != NULL); - if (!(xl->mem_acct.rec)) { - GF_ASSERT (0); - } + GF_ASSERT (xl->mem_acct.rec != NULL); - if (type > xl->mem_acct.num_types) { - GF_ASSERT (0); - } + GF_ASSERT (type <= xl->mem_acct.num_types); LOCK(&xl->mem_acct.rec[type].lock); { xl->mem_acct.rec[type].size += size; xl->mem_acct.rec[type].num_allocs++; + xl->mem_acct.rec[type].total_allocs++; xl->mem_acct.rec[type].max_size = max (xl->mem_acct.rec[type].max_size, xl->mem_acct.rec[type].size); @@ -131,7 +100,7 @@ __gf_calloc (size_t nmemb, size_t size, uint32_t type) char *ptr = NULL; xlator_t *xl = NULL; - if (!gf_mem_acct_enable) + if (!THIS->ctx->mem_acct_enable) return CALLOC (nmemb, size); xl = THIS; @@ -157,7 +126,7 @@ __gf_malloc (size_t size, uint32_t type) char *ptr = NULL; xlator_t *xl = NULL; - if (!gf_mem_acct_enable) + if (!THIS->ctx->mem_acct_enable) return MALLOC (size); xl = THIS; @@ -182,7 +151,7 @@ __gf_realloc (void *ptr, size_t size) xlator_t *xl = NULL; uint32_t type = 0; - if (!gf_mem_acct_enable) + if (!THIS->ctx->mem_acct_enable) return REALLOC (ptr, size); tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; @@ -255,7 +224,7 @@ __gf_free (void *free_ptr) uint32_t type = 0; xlator_t *xl = NULL; - if (!gf_mem_acct_enable) { + if (!THIS->ctx->mem_acct_enable) { FREE (free_ptr); return; } @@ -265,20 +234,16 @@ __gf_free (void *free_ptr) ptr = (char *)free_ptr - 8 - 4; - if (GF_MEM_HEADER_MAGIC != *(uint32_t *)ptr) { - //Possible corruption, assert here - GF_ASSERT (0); - } + //Possible corruption, assert here + GF_ASSERT (GF_MEM_HEADER_MAGIC == *(uint32_t *)ptr); *(uint32_t *)ptr = 0; ptr = ptr - sizeof(xlator_t *); memcpy (&xl, ptr, sizeof(xlator_t *)); - if (!xl) { - //gf_free expects xl to be available - GF_ASSERT (0); - } + //gf_free expects xl to be available + GF_ASSERT (xl != NULL); if (!xl->mem_acct.rec) { ptr = (char *)free_ptr - GF_MEM_HEADER_SIZE; @@ -291,11 +256,10 @@ __gf_free (void *free_ptr) ptr = ptr - 4; type = *(uint32_t *)ptr; - if (GF_MEM_TRAILER_MAGIC != *(uint32_t *) - ((char *)free_ptr + req_size)) { - // This points to a memory overrun - GF_ASSERT (0); - } + // This points to a memory overrun + GF_ASSERT (GF_MEM_TRAILER_MAGIC == + *(uint32_t *)((char *)free_ptr + req_size)); + *(uint32_t *) ((char *)free_ptr + req_size) = 0; LOCK (&xl->mem_acct.rec[type].lock); @@ -312,16 +276,18 @@ free: struct mem_pool * mem_pool_new_fn (unsigned long sizeof_type, - unsigned long count) + unsigned long count, char *name) { struct mem_pool *mem_pool = NULL; unsigned long padded_sizeof_type = 0; void *pool = NULL; int i = 0; + int ret = 0; struct list_head *list = NULL; + glusterfs_ctx_t *ctx = NULL; if (!sizeof_type || !count) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, "invalid argument"); return NULL; } padded_sizeof_type = sizeof_type + GF_MEM_POOL_PAD_BOUNDARY; @@ -330,8 +296,18 @@ mem_pool_new_fn (unsigned long sizeof_type, if (!mem_pool) return NULL; + ret = gf_asprintf (&mem_pool->name, "%s:%s", THIS->name, name); + if (ret < 0) + return NULL; + + if (!mem_pool->name) { + GF_FREE (mem_pool); + return NULL; + } + LOCK_INIT (&mem_pool->lock); INIT_LIST_HEAD (&mem_pool->list); + INIT_LIST_HEAD (&mem_pool->global_list); mem_pool->padded_sizeof_type = padded_sizeof_type; mem_pool->cold_count = count; @@ -339,6 +315,7 @@ mem_pool_new_fn (unsigned long sizeof_type, pool = GF_CALLOC (count, padded_sizeof_type, gf_common_mt_long); if (!pool) { + GF_FREE (mem_pool->name); GF_FREE (mem_pool); return NULL; } @@ -352,6 +329,14 @@ mem_pool_new_fn (unsigned long sizeof_type, mem_pool->pool = pool; mem_pool->pool_end = pool + (count * (padded_sizeof_type)); + /* add this pool to the global list */ + ctx = THIS->ctx; + if (!ctx) + goto out; + + list_add (&mem_pool->global_list, &ctx->mempool_list); + +out: return mem_pool; } @@ -361,7 +346,7 @@ mem_get0 (struct mem_pool *mem_pool) void *ptr = NULL; if (!mem_pool) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, "invalid argument"); return NULL; } @@ -379,14 +364,16 @@ mem_get (struct mem_pool *mem_pool) struct list_head *list = NULL; void *ptr = NULL; int *in_use = NULL; + struct mem_pool **pool_ptr = NULL; if (!mem_pool) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, "invalid argument"); return NULL; } LOCK (&mem_pool->lock); { + mem_pool->alloc_count++; if (mem_pool->cold_count) { list = mem_pool->list.next; list_del (list); @@ -394,8 +381,12 @@ mem_get (struct mem_pool *mem_pool) mem_pool->hot_count++; mem_pool->cold_count--; + if (mem_pool->max_alloc < mem_pool->hot_count) + mem_pool->max_alloc = mem_pool->hot_count; + ptr = list; - in_use = (ptr + GF_MEM_POOL_LIST_BOUNDARY); + in_use = (ptr + GF_MEM_POOL_LIST_BOUNDARY + + GF_MEM_POOL_PTR); *in_use = 1; goto fwd_addr_out; @@ -404,7 +395,7 @@ mem_get (struct mem_pool *mem_pool) /* This is a problem area. If we've run out of * chunks in our slab above, we need to allocate * enough memory to service this request. - * The problem is, these indvidual chunks will fail + * The problem is, these individual chunks will fail * the first address range check in __is_member. Now, since * we're not allocating a full second slab, we wont have * enough info perform the range check in __is_member. @@ -421,17 +412,22 @@ mem_get (struct mem_pool *mem_pool) * because it is too much work knowing that a better slab * allocator is coming RSN. */ - ptr = MALLOC (mem_pool->real_sizeof_type); + mem_pool->pool_misses++; + mem_pool->curr_stdalloc++; + if (mem_pool->max_stdalloc < mem_pool->curr_stdalloc) + mem_pool->max_stdalloc = mem_pool->curr_stdalloc; + ptr = GF_CALLOC (1, mem_pool->padded_sizeof_type, + gf_common_mt_mem_pool); /* Memory coming from the heap need not be transformed from a * chunkhead to a usable pointer since it is not coming from * the pool. */ - goto unlocked_out; } fwd_addr_out: + pool_ptr = mem_pool_from_ptr (ptr); + *pool_ptr = (struct mem_pool *)mem_pool; ptr = mem_pool_chunkhead2ptr (ptr); -unlocked_out: UNLOCK (&mem_pool->lock); return ptr; @@ -442,7 +438,7 @@ static int __is_member (struct mem_pool *pool, void *ptr) { if (!pool || !ptr) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, "invalid argument"); return -1; } @@ -458,25 +454,41 @@ __is_member (struct mem_pool *pool, void *ptr) void -mem_put (struct mem_pool *pool, void *ptr) +mem_put (void *ptr) { struct list_head *list = NULL; int *in_use = NULL; void *head = NULL; + struct mem_pool **tmp = NULL; + struct mem_pool *pool = NULL; - if (!pool || !ptr) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); + if (!ptr) { + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, "invalid argument"); return; } + list = head = mem_pool_ptr2chunkhead (ptr); + tmp = mem_pool_from_ptr (head); + if (!tmp) { + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, + "ptr header is corrupted"); + return; + } + + pool = *tmp; + if (!pool) { + gf_log_callingfn ("mem-pool", GF_LOG_ERROR, + "mem-pool ptr is NULL"); + return; + } LOCK (&pool->lock); { switch (__is_member (pool, ptr)) { case 1: - list = head = mem_pool_ptr2chunkhead (ptr); - in_use = (head + GF_MEM_POOL_LIST_BOUNDARY); + in_use = (head + GF_MEM_POOL_LIST_BOUNDARY + + GF_MEM_POOL_PTR); if (!is_mem_chunk_in_use(in_use)) { gf_log_callingfn ("mem-pool", GF_LOG_CRITICAL, "mem_put called on freed ptr %p of mem " @@ -506,7 +518,8 @@ mem_put (struct mem_pool *pool, void *ptr) * not have enough info to distinguish between the two * situations. */ - FREE (ptr); + pool->curr_stdalloc--; + GF_FREE (list); break; default: /* log error */ @@ -516,14 +529,19 @@ mem_put (struct mem_pool *pool, void *ptr) UNLOCK (&pool->lock); } - void mem_pool_destroy (struct mem_pool *pool) { if (!pool) return; + gf_log (THIS->name, GF_LOG_INFO, "size=%lu max=%d total=%"PRIu64, + pool->padded_sizeof_type, pool->max_alloc, pool->alloc_count); + + list_del (&pool->global_list); + LOCK_DESTROY (&pool->lock); + GF_FREE (pool->name); GF_FREE (pool->pool); GF_FREE (pool); |
