Home | History | Annotate | Line # | Download | only in mm
pool-debug.c revision 1.1
      1  1.1  haad /*	$NetBSD: pool-debug.c,v 1.1 2008/12/22 00:18:34 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  haad 
     20  1.1  haad struct block {
     21  1.1  haad 	struct block *next;
     22  1.1  haad 	size_t size;
     23  1.1  haad 	void *data;
     24  1.1  haad };
     25  1.1  haad 
     26  1.1  haad typedef struct {
     27  1.1  haad 	unsigned block_serialno;	/* Non-decreasing serialno of block */
     28  1.1  haad 	unsigned blocks_allocated;	/* Current number of blocks allocated */
     29  1.1  haad 	unsigned blocks_max;	/* Max no of concurrently-allocated blocks */
     30  1.1  haad 	unsigned int bytes, maxbytes;
     31  1.1  haad } pool_stats;
     32  1.1  haad 
     33  1.1  haad struct dm_pool {
     34  1.1  haad 	const char *name;
     35  1.1  haad 
     36  1.1  haad 	int begun;
     37  1.1  haad 	struct block *object;
     38  1.1  haad 
     39  1.1  haad 	struct block *blocks;
     40  1.1  haad 	struct block *tail;
     41  1.1  haad 
     42  1.1  haad 	pool_stats stats;
     43  1.1  haad };
     44  1.1  haad 
     45  1.1  haad /* by default things come out aligned for doubles */
     46  1.1  haad #define DEFAULT_ALIGNMENT __alignof__ (double)
     47  1.1  haad 
     48  1.1  haad struct pool *dm_pool_create(const char *name, size_t chunk_hint)
     49  1.1  haad {
     50  1.1  haad 	struct dm_pool *mem = dm_malloc(sizeof(*mem));
     51  1.1  haad 
     52  1.1  haad 	if (!mem) {
     53  1.1  haad 		log_error("Couldn't create memory pool %s (size %"
     54  1.1  haad 			  PRIsize_t ")", name, sizeof(*mem));
     55  1.1  haad 		return NULL;
     56  1.1  haad 	}
     57  1.1  haad 
     58  1.1  haad 	mem->name = name;
     59  1.1  haad 	mem->begun = 0;
     60  1.1  haad 	mem->object = 0;
     61  1.1  haad 	mem->blocks = mem->tail = NULL;
     62  1.1  haad 
     63  1.1  haad 	mem->stats.block_serialno = 0;
     64  1.1  haad 	mem->stats.blocks_allocated = 0;
     65  1.1  haad 	mem->stats.blocks_max = 0;
     66  1.1  haad 	mem->stats.bytes = 0;
     67  1.1  haad 	mem->stats.maxbytes = 0;
     68  1.1  haad 
     69  1.1  haad #ifdef DEBUG_POOL
     70  1.1  haad 	log_debug("Created mempool %s", name);
     71  1.1  haad #endif
     72  1.1  haad 
     73  1.1  haad 	return mem;
     74  1.1  haad }
     75  1.1  haad 
     76  1.1  haad static void _free_blocks(struct dm_pool *p, struct block *b)
     77  1.1  haad {
     78  1.1  haad 	struct block *n;
     79  1.1  haad 
     80  1.1  haad 	while (b) {
     81  1.1  haad 		p->stats.bytes -= b->size;
     82  1.1  haad 		p->stats.blocks_allocated--;
     83  1.1  haad 
     84  1.1  haad 		n = b->next;
     85  1.1  haad 		dm_free(b->data);
     86  1.1  haad 		dm_free(b);
     87  1.1  haad 		b = n;
     88  1.1  haad 	}
     89  1.1  haad }
     90  1.1  haad 
     91  1.1  haad static void _pool_stats(struct dm_pool *p, const char *action)
     92  1.1  haad {
     93  1.1  haad #ifdef DEBUG_POOL
     94  1.1  haad 	log_debug("%s mempool %s: %u/%u bytes, %u/%u blocks, "
     95  1.1  haad 		  "%u allocations)", action, p->name, p->stats.bytes,
     96  1.1  haad 		  p->stats.maxbytes, p->stats.blocks_allocated,
     97  1.1  haad 		  p->stats.blocks_max, p->stats.block_serialno);
     98  1.1  haad #else
     99  1.1  haad 	;
    100  1.1  haad #endif
    101  1.1  haad }
    102  1.1  haad 
    103  1.1  haad void dm_pool_destroy(struct dm_pool *p)
    104  1.1  haad {
    105  1.1  haad 	_pool_stats(p, "Destroying");
    106  1.1  haad 	_free_blocks(p, p->blocks);
    107  1.1  haad 	dm_free(p);
    108  1.1  haad }
    109  1.1  haad 
    110  1.1  haad void *dm_pool_alloc(struct dm_pool *p, size_t s)
    111  1.1  haad {
    112  1.1  haad 	return dm_pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
    113  1.1  haad }
    114  1.1  haad 
    115  1.1  haad static void _append_block(struct dm_pool *p, struct block *b)
    116  1.1  haad {
    117  1.1  haad 	if (p->tail) {
    118  1.1  haad 		p->tail->next = b;
    119  1.1  haad 		p->tail = b;
    120  1.1  haad 	} else
    121  1.1  haad 		p->blocks = p->tail = b;
    122  1.1  haad 
    123  1.1  haad 	p->stats.block_serialno++;
    124  1.1  haad 	p->stats.blocks_allocated++;
    125  1.1  haad 	if (p->stats.blocks_allocated > p->stats.blocks_max)
    126  1.1  haad 		p->stats.blocks_max = p->stats.blocks_allocated;
    127  1.1  haad 
    128  1.1  haad 	p->stats.bytes += b->size;
    129  1.1  haad 	if (p->stats.bytes > p->stats.maxbytes)
    130  1.1  haad 		p->stats.maxbytes = p->stats.bytes;
    131  1.1  haad }
    132  1.1  haad 
    133  1.1  haad static struct block *_new_block(size_t s, unsigned alignment)
    134  1.1  haad {
    135  1.1  haad 	static const char *_oom = "Out of memory";
    136  1.1  haad 
    137  1.1  haad 	/* FIXME: I'm currently ignoring the alignment arg. */
    138  1.1  haad 	size_t len = sizeof(struct block) + s;
    139  1.1  haad 	struct block *b = dm_malloc(len);
    140  1.1  haad 
    141  1.1  haad 	/*
    142  1.1  haad 	 * Too lazy to implement alignment for debug version, and
    143  1.1  haad 	 * I don't think LVM will use anything but default
    144  1.1  haad 	 * align.
    145  1.1  haad 	 */
    146  1.1  haad 	assert(alignment == DEFAULT_ALIGNMENT);
    147  1.1  haad 
    148  1.1  haad 	if (!b) {
    149  1.1  haad 		log_err(_oom);
    150  1.1  haad 		return NULL;
    151  1.1  haad 	}
    152  1.1  haad 
    153  1.1  haad 	if (!(b->data = dm_malloc(s))) {
    154  1.1  haad 		log_err(_oom);
    155  1.1  haad 		dm_free(b);
    156  1.1  haad 		return NULL;
    157  1.1  haad 	}
    158  1.1  haad 
    159  1.1  haad 	b->next = NULL;
    160  1.1  haad 	b->size = s;
    161  1.1  haad 
    162  1.1  haad 	return b;
    163  1.1  haad }
    164  1.1  haad 
    165  1.1  haad void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
    166  1.1  haad {
    167  1.1  haad 	struct block *b = _new_block(s, alignment);
    168  1.1  haad 
    169  1.1  haad 	if (!b)
    170  1.1  haad 		return NULL;
    171  1.1  haad 
    172  1.1  haad 	_append_block(p, b);
    173  1.1  haad 
    174  1.1  haad 	return b->data;
    175  1.1  haad }
    176  1.1  haad 
    177  1.1  haad void dm_pool_empty(struct dm_pool *p)
    178  1.1  haad {
    179  1.1  haad 	_pool_stats(p, "Emptying");
    180  1.1  haad 	_free_blocks(p, p->blocks);
    181  1.1  haad 	p->blocks = p->tail = NULL;
    182  1.1  haad }
    183  1.1  haad 
    184  1.1  haad void dm_pool_free(struct dm_pool *p, void *ptr)
    185  1.1  haad {
    186  1.1  haad 	struct block *b, *prev = NULL;
    187  1.1  haad 
    188  1.1  haad 	_pool_stats(p, "Freeing (before)");
    189  1.1  haad 
    190  1.1  haad 	for (b = p->blocks; b; b = b->next) {
    191  1.1  haad 		if (b->data == ptr)
    192  1.1  haad 			break;
    193  1.1  haad 		prev = b;
    194  1.1  haad 	}
    195  1.1  haad 
    196  1.1  haad 	/*
    197  1.1  haad 	 * If this fires then you tried to free a
    198  1.1  haad 	 * pointer that either wasn't from this
    199  1.1  haad 	 * pool, or isn't the start of a block.
    200  1.1  haad 	 */
    201  1.1  haad 	assert(b);
    202  1.1  haad 
    203  1.1  haad 	_free_blocks(p, b);
    204  1.1  haad 
    205  1.1  haad 	if (prev) {
    206  1.1  haad 		p->tail = prev;
    207  1.1  haad 		prev->next = NULL;
    208  1.1  haad 	} else
    209  1.1  haad 		p->blocks = p->tail = NULL;
    210  1.1  haad 
    211  1.1  haad 	_pool_stats(p, "Freeing (after)");
    212  1.1  haad }
    213  1.1  haad 
    214  1.1  haad int dm_pool_begin_object(struct dm_pool *p, size_t init_size)
    215  1.1  haad {
    216  1.1  haad 	assert(!p->begun);
    217  1.1  haad 	p->begun = 1;
    218  1.1  haad 	return 1;
    219  1.1  haad }
    220  1.1  haad 
    221  1.1  haad int dm_pool_grow_object(struct dm_pool *p, const void *extra, size_t delta)
    222  1.1  haad {
    223  1.1  haad 	struct block *new;
    224  1.1  haad 	size_t size = delta ? : strlen(extra);
    225  1.1  haad 
    226  1.1  haad 	assert(p->begun);
    227  1.1  haad 
    228  1.1  haad 	if (p->object)
    229  1.1  haad 		size += p->object->size;
    230  1.1  haad 
    231  1.1  haad 	if (!(new = _new_block(size, DEFAULT_ALIGNMENT))) {
    232  1.1  haad 		log_err("Couldn't extend object.");
    233  1.1  haad 		return 0;
    234  1.1  haad 	}
    235  1.1  haad 
    236  1.1  haad 	if (p->object) {
    237  1.1  haad 		memcpy(new->data, p->object->data, p->object->size);
    238  1.1  haad 		dm_free(p->object->data);
    239  1.1  haad 		dm_free(p->object);
    240  1.1  haad 	}
    241  1.1  haad 	p->object = new;
    242  1.1  haad 
    243  1.1  haad 	memcpy(new->data + size - delta, extra, delta);
    244  1.1  haad 
    245  1.1  haad 	return 1;
    246  1.1  haad }
    247  1.1  haad 
    248  1.1  haad void *dm_pool_end_object(struct dm_pool *p)
    249  1.1  haad {
    250  1.1  haad 	assert(p->begun);
    251  1.1  haad 	_append_block(p, p->object);
    252  1.1  haad 
    253  1.1  haad 	p->begun = 0;
    254  1.1  haad 	p->object = NULL;
    255  1.1  haad 	return p->tail->data;
    256  1.1  haad }
    257  1.1  haad 
    258  1.1  haad void dm_pool_abandon_object(struct dm_pool *p)
    259  1.1  haad {
    260  1.1  haad 	assert(p->begun);
    261  1.1  haad 	dm_free(p->object);
    262  1.1  haad 	p->begun = 0;
    263  1.1  haad 	p->object = NULL;
    264  1.1  haad }
    265