Home | History | Annotate | Line # | Download | only in mm
pool-debug.c revision 1.1.1.2
      1      1.1  haad /*	$NetBSD: pool-debug.c,v 1.1.1.2 2009/12/02 00:26:09 haad Exp $	*/
      2      1.1  haad 
      3      1.1  haad /*
      4      1.1  haad  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
      5      1.1  haad  * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
      6      1.1  haad  *
      7      1.1  haad  * This file is part of the device-mapper userspace tools.
      8      1.1  haad  *
      9      1.1  haad  * This copyrighted material is made available to anyone wishing to use,
     10      1.1  haad  * modify, copy, or redistribute it subject to the terms and conditions
     11      1.1  haad  * of the GNU Lesser General Public License v.2.1.
     12      1.1  haad  *
     13      1.1  haad  * You should have received a copy of the GNU Lesser General Public License
     14      1.1  haad  * along with this program; if not, write to the Free Software Foundation,
     15      1.1  haad  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16      1.1  haad  */
     17      1.1  haad 
     18      1.1  haad #include "dmlib.h"
     19  1.1.1.2  haad #include <assert.h>
     20      1.1  haad 
     21      1.1  haad struct block {
     22      1.1  haad 	struct block *next;
     23      1.1  haad 	size_t size;
     24      1.1  haad 	void *data;
     25      1.1  haad };
     26      1.1  haad 
     27      1.1  haad typedef struct {
     28      1.1  haad 	unsigned block_serialno;	/* Non-decreasing serialno of block */
     29      1.1  haad 	unsigned blocks_allocated;	/* Current number of blocks allocated */
     30      1.1  haad 	unsigned blocks_max;	/* Max no of concurrently-allocated blocks */
     31      1.1  haad 	unsigned int bytes, maxbytes;
     32      1.1  haad } pool_stats;
     33      1.1  haad 
     34      1.1  haad struct dm_pool {
     35  1.1.1.2  haad 	struct dm_list list;
     36      1.1  haad 	const char *name;
     37  1.1.1.2  haad 	void *orig_pool;	/* to pair it with first allocation call */
     38      1.1  haad 
     39      1.1  haad 	int begun;
     40      1.1  haad 	struct block *object;
     41      1.1  haad 
     42      1.1  haad 	struct block *blocks;
     43      1.1  haad 	struct block *tail;
     44      1.1  haad 
     45      1.1  haad 	pool_stats stats;
     46      1.1  haad };
     47      1.1  haad 
     48      1.1  haad /* by default things come out aligned for doubles */
     49      1.1  haad #define DEFAULT_ALIGNMENT __alignof__ (double)
     50      1.1  haad 
     51  1.1.1.2  haad struct dm_pool *dm_pool_create(const char *name, size_t chunk_hint)
     52      1.1  haad {
     53      1.1  haad 	struct dm_pool *mem = dm_malloc(sizeof(*mem));
     54      1.1  haad 
     55      1.1  haad 	if (!mem) {
     56      1.1  haad 		log_error("Couldn't create memory pool %s (size %"
     57      1.1  haad 			  PRIsize_t ")", name, sizeof(*mem));
     58      1.1  haad 		return NULL;
     59      1.1  haad 	}
     60      1.1  haad 
     61      1.1  haad 	mem->name = name;
     62      1.1  haad 	mem->begun = 0;
     63      1.1  haad 	mem->object = 0;
     64      1.1  haad 	mem->blocks = mem->tail = NULL;
     65      1.1  haad 
     66      1.1  haad 	mem->stats.block_serialno = 0;
     67      1.1  haad 	mem->stats.blocks_allocated = 0;
     68      1.1  haad 	mem->stats.blocks_max = 0;
     69      1.1  haad 	mem->stats.bytes = 0;
     70      1.1  haad 	mem->stats.maxbytes = 0;
     71      1.1  haad 
     72  1.1.1.2  haad 	mem->orig_pool = mem;
     73  1.1.1.2  haad 
     74      1.1  haad #ifdef DEBUG_POOL
     75      1.1  haad 	log_debug("Created mempool %s", name);
     76      1.1  haad #endif
     77      1.1  haad 
     78  1.1.1.2  haad 	dm_list_add(&_dm_pools, &mem->list);
     79      1.1  haad 	return mem;
     80      1.1  haad }
     81      1.1  haad 
     82      1.1  haad static void _free_blocks(struct dm_pool *p, struct block *b)
     83      1.1  haad {
     84      1.1  haad 	struct block *n;
     85      1.1  haad 
     86      1.1  haad 	while (b) {
     87      1.1  haad 		p->stats.bytes -= b->size;
     88      1.1  haad 		p->stats.blocks_allocated--;
     89      1.1  haad 
     90      1.1  haad 		n = b->next;
     91      1.1  haad 		dm_free(b->data);
     92      1.1  haad 		dm_free(b);
     93      1.1  haad 		b = n;
     94      1.1  haad 	}
     95      1.1  haad }
     96      1.1  haad 
     97      1.1  haad static void _pool_stats(struct dm_pool *p, const char *action)
     98      1.1  haad {
     99      1.1  haad #ifdef DEBUG_POOL
    100      1.1  haad 	log_debug("%s mempool %s: %u/%u bytes, %u/%u blocks, "
    101      1.1  haad 		  "%u allocations)", action, p->name, p->stats.bytes,
    102      1.1  haad 		  p->stats.maxbytes, p->stats.blocks_allocated,
    103      1.1  haad 		  p->stats.blocks_max, p->stats.block_serialno);
    104      1.1  haad #else
    105      1.1  haad 	;
    106      1.1  haad #endif
    107      1.1  haad }
    108      1.1  haad 
    109      1.1  haad void dm_pool_destroy(struct dm_pool *p)
    110      1.1  haad {
    111      1.1  haad 	_pool_stats(p, "Destroying");
    112      1.1  haad 	_free_blocks(p, p->blocks);
    113  1.1.1.2  haad 	dm_list_del(&p->list);
    114      1.1  haad 	dm_free(p);
    115      1.1  haad }
    116      1.1  haad 
    117      1.1  haad void *dm_pool_alloc(struct dm_pool *p, size_t s)
    118      1.1  haad {
    119      1.1  haad 	return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
    120      1.1  haad }
    121      1.1  haad 
    122      1.1  haad static void _append_block(struct dm_pool *p, struct block *b)
    123      1.1  haad {
    124      1.1  haad 	if (p->tail) {
    125      1.1  haad 		p->tail->next = b;
    126      1.1  haad 		p->tail = b;
    127      1.1  haad 	} else
    128      1.1  haad 		p->blocks = p->tail = b;
    129      1.1  haad 
    130      1.1  haad 	p->stats.block_serialno++;
    131      1.1  haad 	p->stats.blocks_allocated++;
    132      1.1  haad 	if (p->stats.blocks_allocated > p->stats.blocks_max)
    133      1.1  haad 		p->stats.blocks_max = p->stats.blocks_allocated;
    134      1.1  haad 
    135      1.1  haad 	p->stats.bytes += b->size;
    136      1.1  haad 	if (p->stats.bytes > p->stats.maxbytes)
    137      1.1  haad 		p->stats.maxbytes = p->stats.bytes;
    138      1.1  haad }
    139      1.1  haad 
    140      1.1  haad static struct block *_new_block(size_t s, unsigned alignment)
    141      1.1  haad {
    142      1.1  haad 	/* FIXME: I'm currently ignoring the alignment arg. */
    143      1.1  haad 	size_t len = sizeof(struct block) + s;
    144      1.1  haad 	struct block *b = dm_malloc(len);
    145      1.1  haad 
    146      1.1  haad 	/*
    147      1.1  haad 	 * Too lazy to implement alignment for debug version, and
    148      1.1  haad 	 * I don't think LVM will use anything but default
    149      1.1  haad 	 * align.
    150      1.1  haad 	 */
    151      1.1  haad 	assert(alignment == DEFAULT_ALIGNMENT);
    152      1.1  haad 
    153      1.1  haad 	if (!b) {
    154  1.1.1.2  haad 		log_error("Out of memory");
    155      1.1  haad 		return NULL;
    156      1.1  haad 	}
    157      1.1  haad 
    158      1.1  haad 	if (!(b->data = dm_malloc(s))) {
    159  1.1.1.2  haad 		log_error("Out of memory");
    160      1.1  haad 		dm_free(b);
    161      1.1  haad 		return NULL;
    162      1.1  haad 	}
    163      1.1  haad 
    164      1.1  haad 	b->next = NULL;
    165      1.1  haad 	b->size = s;
    166      1.1  haad 
    167      1.1  haad 	return b;
    168      1.1  haad }
    169      1.1  haad 
    170      1.1  haad void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
    171      1.1  haad {
    172      1.1  haad 	struct block *b = _new_block(s, alignment);
    173      1.1  haad 
    174      1.1  haad 	if (!b)
    175      1.1  haad 		return NULL;
    176      1.1  haad 
    177      1.1  haad 	_append_block(p, b);
    178      1.1  haad 
    179      1.1  haad 	return b->data;
    180      1.1  haad }
    181      1.1  haad 
    182      1.1  haad void dm_pool_empty(struct dm_pool *p)
    183      1.1  haad {
    184      1.1  haad 	_pool_stats(p, "Emptying");
    185      1.1  haad 	_free_blocks(p, p->blocks);
    186      1.1  haad 	p->blocks = p->tail = NULL;
    187      1.1  haad }
    188      1.1  haad 
    189      1.1  haad void dm_pool_free(struct dm_pool *p, void *ptr)
    190      1.1  haad {
    191      1.1  haad 	struct block *b, *prev = NULL;
    192      1.1  haad 
    193      1.1  haad 	_pool_stats(p, "Freeing (before)");
    194      1.1  haad 
    195      1.1  haad 	for (b = p->blocks; b; b = b->next) {
    196      1.1  haad 		if (b->data == ptr)
    197      1.1  haad 			break;
    198      1.1  haad 		prev = b;
    199      1.1  haad 	}
    200      1.1  haad 
    201      1.1  haad 	/*
    202      1.1  haad 	 * If this fires then you tried to free a
    203      1.1  haad 	 * pointer that either wasn't from this
    204      1.1  haad 	 * pool, or isn't the start of a block.
    205      1.1  haad 	 */
    206      1.1  haad 	assert(b);
    207      1.1  haad 
    208      1.1  haad 	_free_blocks(p, b);
    209      1.1  haad 
    210      1.1  haad 	if (prev) {
    211      1.1  haad 		p->tail = prev;
    212      1.1  haad 		prev->next = NULL;
    213      1.1  haad 	} else
    214      1.1  haad 		p->blocks = p->tail = NULL;
    215      1.1  haad 
    216      1.1  haad 	_pool_stats(p, "Freeing (after)");
    217      1.1  haad }
    218      1.1  haad 
    219      1.1  haad int dm_pool_begin_object(struct dm_pool *p, size_t init_size)
    220      1.1  haad {
    221      1.1  haad 	assert(!p->begun);
    222      1.1  haad 	p->begun = 1;
    223      1.1  haad 	return 1;
    224      1.1  haad }
    225      1.1  haad 
    226      1.1  haad int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
    227      1.1  haad {
    228      1.1  haad 	struct block *new;
    229  1.1.1.2  haad 	size_t new_size;
    230  1.1.1.2  haad 
    231  1.1.1.2  haad 	if (!delta)
    232  1.1.1.2  haad 		delta = strlen(extra);
    233      1.1  haad 
    234      1.1  haad 	assert(p->begun);
    235      1.1  haad 
    236      1.1  haad 	if (p->object)
    237  1.1.1.2  haad 		new_size = delta + p->object->size;
    238  1.1.1.2  haad 	else
    239  1.1.1.2  haad 		new_size = delta;
    240      1.1  haad 
    241  1.1.1.2  haad 	if (!(new = _new_block(new_size, DEFAULT_ALIGNMENT))) {
    242  1.1.1.2  haad 		log_error("Couldn't extend object.");
    243      1.1  haad 		return 0;
    244      1.1  haad 	}
    245      1.1  haad 
    246      1.1  haad 	if (p->object) {
    247      1.1  haad 		memcpy(new->data, p->object->data, p->object->size);
    248      1.1  haad 		dm_free(p->object->data);
    249      1.1  haad 		dm_free(p->object);
    250      1.1  haad 	}
    251      1.1  haad 	p->object = new;
    252      1.1  haad 
    253  1.1.1.2  haad 	memcpy(new->data + new_size - delta, extra, delta);
    254      1.1  haad 
    255      1.1  haad 	return 1;
    256      1.1  haad }
    257      1.1  haad 
    258      1.1  haad void *dm_pool_end_object(struct dm_pool *p)
    259      1.1  haad {
    260      1.1  haad 	assert(p->begun);
    261      1.1  haad 	_append_block(p, p->object);
    262      1.1  haad 
    263      1.1  haad 	p->begun = 0;
    264      1.1  haad 	p->object = NULL;
    265      1.1  haad 	return p->tail->data;
    266      1.1  haad }
    267      1.1  haad 
    268      1.1  haad void dm_pool_abandon_object(struct dm_pool *p)
    269      1.1  haad {
    270      1.1  haad 	assert(p->begun);
    271      1.1  haad 	dm_free(p->object);
    272      1.1  haad 	p->begun = 0;
    273      1.1  haad 	p->object = NULL;
    274      1.1  haad }
    275