From mboxrd@z Thu Jan 1 00:00:00 1970 From: mathieu.desnoyers@efficios.com (Mathieu Desnoyers) Date: Mon, 28 Nov 2011 08:27:37 -0500 Subject: [lttng-dev] [PATCH 10/12] move memory management code out as rculfhash-mm-order.c In-Reply-To: <1322467688-2930-11-git-send-email-laijs@cn.fujitsu.com> References: <1322467688-2930-1-git-send-email-laijs@cn.fujitsu.com> <1322467688-2930-11-git-send-email-laijs@cn.fujitsu.com> Message-ID: <20111128132737.GJ2663@Krystal> * Lai Jiangshan (laijs at cn.fujitsu.com) wrote: > Signed-off-by: Lai Jiangshan Yep, this is clean! :) Merged, thanks! Mathieu > --- > Makefile.am | 5 ++- > rculfhash-internal.h | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ > rculfhash-mm-order.c | 101 ++++++++++++++++++++++++++++++++++++++++++ > rculfhash.c | 119 +++++--------------------------------------------- > urcu/rculfhash.h | 14 +++++- > 5 files changed, 245 insertions(+), 109 deletions(-) > create mode 100644 rculfhash-internal.h > create mode 100644 rculfhash-mm-order.c > > diff --git a/Makefile.am b/Makefile.am > index 1290551..4d3f7bd 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -22,6 +22,7 @@ EXTRA_DIST = $(top_srcdir)/urcu/arch/*.h $(top_srcdir)/urcu/uatomic/*.h \ > gpl-2.0.txt lgpl-2.1.txt lgpl-relicensing.txt \ > README LICENSE compat_arch_x86.c \ > urcu-call-rcu-impl.h urcu-defer-impl.h \ > + rculfhash-internal.h \ > ChangeLog API.txt > > if COMPAT_ARCH > @@ -34,6 +35,8 @@ if COMPAT_FUTEX > COMPAT+=compat_futex.c > endif > > +RCULFHASH=rculfhash.c rculfhash-mm-order.c > + > lib_LTLIBRARIES = liburcu-common.la \ > liburcu.la liburcu-qsbr.la \ > liburcu-mb.la liburcu-signal.la liburcu-bp.la \ > @@ -62,7 +65,7 @@ liburcu_signal_la_LIBADD = liburcu-common.la > liburcu_bp_la_SOURCES = urcu-bp.c urcu-pointer.c $(COMPAT) > liburcu_bp_la_LIBADD = liburcu-common.la > > -liburcu_cds_la_SOURCES = rculfqueue.c rculfstack.c rculfhash.c $(COMPAT) > +liburcu_cds_la_SOURCES = rculfqueue.c rculfstack.c $(RCULFHASH) $(COMPAT) > liburcu_cds_la_LIBADD = liburcu-common.la > > pkgconfigdir = $(libdir)/pkgconfig > diff --git a/rculfhash-internal.h b/rculfhash-internal.h > new file mode 100644 > index 0000000..820e62c > --- /dev/null > +++ b/rculfhash-internal.h > @@ -0,0 +1,115 @@ > +#ifndef _URCU_RCULFHASH_INTERNAL_H > +#define _URCU_RCULFHASH_INTERNAL_H > + > +/* > + * urcu/rculfhash-internal.h > + * > + * Internal header for Lock-Free RCU Hash Table > + * > + * Copyright 2011 - Mathieu Desnoyers > + * Copyright 2011 - Lai Jiangshan > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library 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 > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include > + > +#ifdef DEBUG > +#define dbg_printf(fmt, args...) printf("[debug rculfhash] " fmt, ## args) > +#else > +#define dbg_printf(fmt, args...) > +#endif > + > +#if (CAA_BITS_PER_LONG == 32) > +#define MAX_TABLE_ORDER 32 > +#else > +#define MAX_TABLE_ORDER 64 > +#endif > + > +#ifndef min > +#define min(a, b) ((a) < (b) ? (a) : (b)) > +#endif > + > +#ifndef max > +#define max(a, b) ((a) > (b) ? (a) : (b)) > +#endif > + > +struct ht_items_count; > + > +/* > + * cds_lfht: Top-level data structure representing a lock-free hash > + * table. Defined in the implementation file to make it be an opaque > + * cookie to users. > + */ > +struct cds_lfht { > + unsigned long size; /* always a power of 2, shared (RCU) */ > + int flags; > + > + /* > + * We need to put the work threads offline (QSBR) when taking this > + * mutex, because we use synchronize_rcu within this mutex critical > + * section, which waits on read-side critical sections, and could > + * therefore cause grace-period deadlock if we hold off RCU G.P. > + * completion. > + */ > + pthread_mutex_t resize_mutex; /* resize mutex: add/del mutex */ > + pthread_attr_t *resize_attr; /* Resize threads attributes */ > + unsigned int in_progress_resize, in_progress_destroy; > + unsigned long resize_target; > + int resize_initiated; > + const struct rcu_flavor_struct *flavor; > + > + long count; /* global approximate item count */ > + struct ht_items_count *split_count; /* split item count */ > + > + /* memory management related fields are located at the end */ > + const struct cds_lfht_mm_type *mm; > + > + unsigned long min_alloc_buckets_order; > + unsigned long min_nr_alloc_buckets; > + unsigned long max_nr_buckets; > + > + struct cds_lfht_node *(*bucket_at)(struct cds_lfht *ht, > + unsigned long index); > + > + union { > + /* > + * Contains the per order-index-level bucket node table. > + * The size of each bucket node table is half the number > + * of hashes contained in this order (except for order 0). > + * The minimum allocation buckets size parameter allows > + * combining the bucket node arrays of the lowermost > + * levels to improve cache locality for small index orders. > + */ > + struct cds_lfht_node *tbl_order[MAX_TABLE_ORDER]; > + }; > +}; > + > +extern unsigned int fls_ulong(unsigned long x); > +extern int get_count_order_ulong(unsigned long x); > + > +#ifdef POISON_FREE > +#define poison_free(ptr) \ > + do { \ > + if (ptr) { \ > + memset(ptr, 0x42, sizeof(*(ptr))); \ > + free(ptr); \ > + } \ > + } while (0) > +#else > +#define poison_free(ptr) free(ptr) > +#endif > + > +#endif /* _URCU_RCULFHASH_INTERNAL_H */ > diff --git a/rculfhash-mm-order.c b/rculfhash-mm-order.c > new file mode 100644 > index 0000000..69e2b62 > --- /dev/null > +++ b/rculfhash-mm-order.c > @@ -0,0 +1,101 @@ > +/* > + * rculfhash-mm-order.c > + * > + * Order based memory management for Lock-Free RCU Hash Table > + * > + * Copyright 2011 - Mathieu Desnoyers > + * Copyright 2011 - Lai Jiangshan > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library 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 > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA > + */ > + > +#include > + > +static > +void cds_lfht_alloc_bucket_table(struct cds_lfht *ht, unsigned long order) > +{ > + if (order == 0) { > + ht->tbl_order[0] = calloc(ht->min_nr_alloc_buckets, > + sizeof(struct cds_lfht_node)); > + assert(ht->tbl_order[0]); > + } else if (order > ht->min_alloc_buckets_order) { > + ht->tbl_order[order] = calloc(1UL << (order -1), > + sizeof(struct cds_lfht_node)); > + assert(ht->tbl_order[order]); > + } > + /* Nothing to do for 0 < order && order <= ht->min_alloc_buckets_order */ > +} > + > +/* > + * cds_lfht_free_bucket_table() should be called with decreasing order. > + * When cds_lfht_free_bucket_table(0) is called, it means the whole > + * lfht is destroyed. > + */ > +static > +void cds_lfht_free_bucket_table(struct cds_lfht *ht, unsigned long order) > +{ > + if (order == 0) > + poison_free(ht->tbl_order[0]); > + else if (order > ht->min_alloc_buckets_order) > + poison_free(ht->tbl_order[order]); > + /* Nothing to do for 0 < order && order <= ht->min_alloc_buckets_order */ > +} > + > +static > +struct cds_lfht_node *bucket_at(struct cds_lfht *ht, unsigned long index) > +{ > + unsigned long order; > + > + if (index < ht->min_nr_alloc_buckets) { > + dbg_printf("bucket index %lu order 0 aridx 0\n", index); > + return &ht->tbl_order[0][index]; > + } > + /* > + * equivalent to get_count_order_ulong(index + 1), but optimizes > + * away the non-existing 0 special-case for > + * get_count_order_ulong. > + */ > + order = fls_ulong(index); > + dbg_printf("bucket index %lu order %lu aridx %lu\n", > + index, order, index & ((1UL << (order - 1)) - 1)); > + return &ht->tbl_order[order][index & ((1UL << (order - 1)) - 1)]; > +} > + > +static > +struct cds_lfht *alloc_cds_lfht(unsigned long min_nr_alloc_buckets, > + unsigned long max_nr_buckets) > +{ > + struct cds_lfht *ht; > + > + ht = calloc(1, sizeof(struct cds_lfht)); > + assert(ht); > + > + ht->mm = &cds_lfht_mm_order; > + > + ht->min_nr_alloc_buckets = min_nr_alloc_buckets; > + ht->min_alloc_buckets_order = get_count_order_ulong(min_nr_alloc_buckets); > + ht->max_nr_buckets = max_nr_buckets; > + > + ht->bucket_at = bucket_at; > + > + return ht; > +} > + > +const struct cds_lfht_mm_type cds_lfht_mm_order = { > + .alloc_cds_lfht = alloc_cds_lfht, > + .alloc_bucket_table = cds_lfht_alloc_bucket_table, > + .free_bucket_table = cds_lfht_free_bucket_table, > + .bucket_at = bucket_at, > +}; > diff --git a/rculfhash.c b/rculfhash.c > index 8dc9c59..49c7863 100644 > --- a/rculfhash.c > +++ b/rculfhash.c > @@ -165,15 +165,10 @@ > #include > #include > #include > +#include > #include > #include > > -#ifdef DEBUG > -#define dbg_printf(fmt, args...) printf("[debug rculfhash] " fmt, ## args) > -#else > -#define dbg_printf(fmt, args...) > -#endif > - > /* > * Split-counters lazily update the global counter each 1024 > * addition/removal. It automatically keeps track of resize required. > @@ -191,26 +186,12 @@ > #define MIN_TABLE_ORDER 0 > #define MIN_TABLE_SIZE (1UL << MIN_TABLE_ORDER) > > -#if (CAA_BITS_PER_LONG == 32) > -#define MAX_TABLE_ORDER 32 > -#else > -#define MAX_TABLE_ORDER 64 > -#endif > - > /* > * Minimum number of bucket nodes to touch per thread to parallelize grow/shrink. > */ > #define MIN_PARTITION_PER_THREAD_ORDER 12 > #define MIN_PARTITION_PER_THREAD (1UL << MIN_PARTITION_PER_THREAD_ORDER) > > -#ifndef min > -#define min(a, b) ((a) < (b) ? (a) : (b)) > -#endif > - > -#ifndef max > -#define max(a, b) ((a) > (b) ? (a) : (b)) > -#endif > - > /* > * The removed flag needs to be updated atomically with the pointer. > * It indicates that no node must attach to the node scheduled for > @@ -240,45 +221,6 @@ struct ht_items_count { > } __attribute__((aligned(CAA_CACHE_LINE_SIZE))); > > /* > - * cds_lfht: Top-level data structure representing a lock-free hash > - * table. Defined in the implementation file to make it be an opaque > - * cookie to users. > - */ > -struct cds_lfht { > - unsigned long size; /* always a power of 2, shared (RCU) */ > - int flags; > - > - /* > - * We need to put the work threads offline (QSBR) when taking this > - * mutex, because we use synchronize_rcu within this mutex critical > - * section, which waits on read-side critical sections, and could > - * therefore cause grace-period deadlock if we hold off RCU G.P. > - * completion. > - */ > - pthread_mutex_t resize_mutex; /* resize mutex: add/del mutex */ > - pthread_attr_t *resize_attr; /* Resize threads attributes */ > - unsigned int in_progress_resize, in_progress_destroy; > - unsigned long resize_target; > - int resize_initiated; > - const struct rcu_flavor_struct *flavor; > - > - long count; /* global approximate item count */ > - struct ht_items_count *split_count; /* split item count */ > - > - unsigned long min_alloc_buckets_order; > - unsigned long min_nr_alloc_buckets; > - unsigned long max_nr_buckets; > - /* > - * Contains the per order-index-level bucket node table. The size > - * of each bucket node table is half the number of hashes contained > - * in this order (except for order 0). The minimum allocation size > - * parameter allows combining the bucket node arrays of the lowermost > - * levels to improve cache locality for small index orders. > - */ > - struct cds_lfht_node *tbl[MAX_TABLE_ORDER]; > -}; > - > -/* > * rcu_resize_work: Contains arguments passed to RCU worker thread > * responsible for performing lazy resize. > */ > @@ -505,18 +447,6 @@ int get_count_order_ulong(unsigned long x) > return fls_ulong(x - 1); > } > > -#ifdef POISON_FREE > -#define poison_free(ptr) \ > - do { \ > - if (ptr) { \ > - memset(ptr, 0x42, sizeof(*(ptr))); \ > - free(ptr); \ > - } \ > - } while (0) > -#else > -#define poison_free(ptr) free(ptr) > -#endif > - > static > void cds_lfht_resize_lazy_grow(struct cds_lfht *ht, unsigned long size, int growth); > > @@ -743,16 +673,7 @@ unsigned long _uatomic_xchg_monotonic_increase(unsigned long *ptr, > static > void cds_lfht_alloc_bucket_table(struct cds_lfht *ht, unsigned long order) > { > - if (order == 0) { > - ht->tbl[0] = calloc(ht->min_nr_alloc_buckets, > - sizeof(struct cds_lfht_node)); > - assert(ht->tbl[0]); > - } else if (order > ht->min_alloc_buckets_order) { > - ht->tbl[order] = calloc(1UL << (order -1), > - sizeof(struct cds_lfht_node)); > - assert(ht->tbl[order]); > - } > - /* Nothing to do for 0 < order && order <= ht->min_alloc_buckets_order */ > + return ht->mm->alloc_bucket_table(ht, order); > } > > /* > @@ -763,32 +684,13 @@ void cds_lfht_alloc_bucket_table(struct cds_lfht *ht, unsigned long order) > static > void cds_lfht_free_bucket_table(struct cds_lfht *ht, unsigned long order) > { > - if (order == 0) > - poison_free(ht->tbl[0]); > - else if (order > ht->min_alloc_buckets_order) > - poison_free(ht->tbl[order]); > - /* Nothing to do for 0 < order && order <= ht->min_alloc_buckets_order */ > + return ht->mm->free_bucket_table(ht, order); > } > > static inline > struct cds_lfht_node *bucket_at(struct cds_lfht *ht, unsigned long index) > { > - unsigned long order; > - > - if ((__builtin_constant_p(index) && index == 0) > - || index < ht->min_nr_alloc_buckets) { > - dbg_printf("bucket index %lu order 0 aridx 0\n", index); > - return &ht->tbl[0][index]; > - } > - /* > - * equivalent to get_count_order_ulong(index + 1), but optimizes > - * away the non-existing 0 special-case for > - * get_count_order_ulong. > - */ > - order = fls_ulong(index); > - dbg_printf("bucket index %lu order %lu aridx %lu\n", > - index, order, index & ((1UL << (order - 1)) - 1)); > - return &ht->tbl[order][index & ((1UL << (order - 1)) - 1)]; > + return ht->bucket_at(ht, index); > } > > static inline > @@ -1354,6 +1256,7 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size, > unsigned long min_nr_alloc_buckets, > unsigned long max_nr_buckets, > int flags, > + const struct cds_lfht_mm_type *mm, > const struct rcu_flavor_struct *flavor, > pthread_attr_t *attr) > { > @@ -1368,7 +1271,8 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size, > if (!init_size || (init_size & (init_size - 1))) > return NULL; > > - if (!max_nr_buckets) > + /* max_nr_buckets == 0 for order based mm means infinite */ > + if (mm == &cds_lfht_mm_order && !max_nr_buckets) > max_nr_buckets = 1UL << (MAX_TABLE_ORDER - 1); > > /* max_nr_buckets must be power of two */ > @@ -1379,8 +1283,12 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size, > init_size = max(init_size, MIN_TABLE_SIZE); > max_nr_buckets = max(max_nr_buckets, min_nr_alloc_buckets); > init_size = min(init_size, max_nr_buckets); > - ht = calloc(1, sizeof(struct cds_lfht)); > + > + ht = mm->alloc_cds_lfht(min_nr_alloc_buckets, max_nr_buckets); > assert(ht); > + assert(ht->mm == mm); > + assert(ht->bucket_at == mm->bucket_at); > + > ht->flags = flags; > ht->flavor = flavor; > ht->resize_attr = attr; > @@ -1389,9 +1297,6 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size, > pthread_mutex_init(&ht->resize_mutex, NULL); > order = get_count_order_ulong(init_size); > ht->resize_target = 1UL << order; > - ht->min_nr_alloc_buckets = min_nr_alloc_buckets; > - ht->min_alloc_buckets_order = get_count_order_ulong(min_nr_alloc_buckets); > - ht->max_nr_buckets = max_nr_buckets; > cds_lfht_create_bucket(ht, 1UL << order); > ht->size = 1UL << order; > return ht; > diff --git a/urcu/rculfhash.h b/urcu/rculfhash.h > index a886b04..926aa14 100644 > --- a/urcu/rculfhash.h > +++ b/urcu/rculfhash.h > @@ -95,6 +95,17 @@ enum { > CDS_LFHT_ACCOUNTING = (1U << 1), > }; > > +struct cds_lfht_mm_type { > + struct cds_lfht *(*alloc_cds_lfht)(unsigned long min_nr_alloc_buckets, > + unsigned long max_nr_buckets); > + void (*alloc_bucket_table)(struct cds_lfht *ht, unsigned long order); > + void (*free_bucket_table)(struct cds_lfht *ht, unsigned long order); > + struct cds_lfht_node *(*bucket_at)(struct cds_lfht *ht, > + unsigned long index); > +}; > + > +extern const struct cds_lfht_mm_type cds_lfht_mm_order; > + > /* > * _cds_lfht_new - API used by cds_lfht_new wrapper. Do not use directly. > */ > @@ -102,6 +113,7 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size, > unsigned long min_nr_alloc_buckets, > unsigned long max_nr_buckets, > int flags, > + const struct cds_lfht_mm_type *mm, > const struct rcu_flavor_struct *flavor, > pthread_attr_t *attr); > > @@ -138,7 +150,7 @@ struct cds_lfht *cds_lfht_new(unsigned long init_size, > pthread_attr_t *attr) > { > return _cds_lfht_new(init_size, min_nr_alloc_buckets, max_nr_buckets, > - flags, &rcu_flavor, attr); > + flags, &cds_lfht_mm_order, &rcu_flavor, attr); > } > > /* > -- > 1.7.4.4 > -- Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com