[ltt-dev] [PATCH 06/10 round10] add LFHT_MEMORY_CHUNK low level memory management

Lai Jiangshan laijs at cn.fujitsu.com
Wed Nov 16 01:48:21 EST 2011


The old memory mangement is named as LFHT_MEMORY_ORDER.

Signed-off-by: Lai Jiangshan <laijs at cn.fujitsu.com>
---
 rculfhash.c |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 111 insertions(+), 5 deletions(-)

diff --git a/rculfhash.c b/rculfhash.c
index b7be893..ae1177f 100644
--- a/rculfhash.c
+++ b/rculfhash.c
@@ -172,6 +172,10 @@
 #define dbg_printf(fmt, args...)
 #endif
 
+#if !defined(LFHT_MEMORY_ORDER) && !defined(LFHT_MEMORY_CHUNK)
+#define LFHT_MEMORY_ORDER
+#endif
+
 /*
  * Split-counters lazily update the global counter each 1024
  * addition/removal. It automatically keeps track of resize required.
@@ -195,6 +199,8 @@
 #define MAX_TABLE_ORDER			64
 #endif
 
+#define MAX_CHUNK_TABLE			(1UL << 10)
+
 /*
  * Minimum number of bucket nodes to touch per thread to parallelize grow/shrink.
  */
@@ -247,6 +253,7 @@ struct rcu_table {
 	unsigned long resize_target;
 	int resize_initiated;
 
+#ifdef LFHT_MEMORY_ORDER
 	/*
 	 * Contains the per order-index-level bucket node table. The size
 	 * of each bucket node table is half the number of hashes contained
@@ -255,6 +262,7 @@ struct rcu_table {
 	 * levels to improve cache locality for small index orders.
 	 */
 	struct cds_lfht_node *tbl[MAX_TABLE_ORDER];
+#endif
 };
 
 /*
@@ -289,6 +297,16 @@ struct cds_lfht {
 	pthread_attr_t *resize_attr;	/* Resize threads attributes */
 	long count;			/* global approximate item count */
 	struct ht_items_count *split_count;	/* split item count */
+
+#ifdef LFHT_MEMORY_CHUNK
+	/*
+	 * Contains the bucket node chunks. The size of each bucket node
+	 * chunk is ->min_alloc_size(avoid to alloc chunks with different
+	 * size). chunks improve cache locality for small index orders
+	 * and improve lookup_bucket() for the archs without hardware fls().
+	 */
+	struct cds_lfht_node *tbl[0];
+#endif
 };
 
 /*
@@ -753,6 +771,93 @@ unsigned long _uatomic_xchg_monotonic_increase(unsigned long *ptr,
 	return old2;
 }
 
+#ifdef LFHT_MEMORY_CHUNK
+static
+struct cds_lfht *_cds_lfht_alloc(unsigned long min_alloc_size,
+		unsigned long max_size)
+{
+	struct cds_lfht *ht;
+
+	min_alloc_size = max(min_alloc_size, max_size / MAX_CHUNK_TABLE);
+	ht = calloc(1, sizeof(struct cds_lfht) +
+			sizeof(ht->tbl[0]) * (max_size / min_alloc_size));
+	assert(ht);
+
+	ht->min_alloc_size = min_alloc_size;
+	ht->min_alloc_order = get_count_order_ulong(min_alloc_size);
+	ht->max_size = max_size;
+
+	return ht;
+}
+
+static
+void cds_lfht_alloc_bucket_table(struct cds_lfht *ht, unsigned long order)
+{
+	if (order == 0) {
+		ht->tbl[0] = calloc(ht->min_alloc_size,
+			sizeof(struct cds_lfht_node));
+		assert(ht->tbl[0]);
+	} else if (order > ht->min_alloc_order) {
+		unsigned long i, len = 1UL << (order - 1 - ht->min_alloc_order);
+
+		for (i = len; i < 2 * len; i++) {
+			ht->tbl[i] = calloc(ht->min_alloc_size,
+				sizeof(struct cds_lfht_node));
+			assert(ht->tbl[i]);
+		}
+	}
+	/* Nothing to do for 0 < order && order <= ht->min_alloc_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[0]);
+	else if (order > ht->min_alloc_order) {
+		unsigned long i, len = 1UL << (order - 1 - ht->min_alloc_order);
+
+		for (i = len; i < 2 * len; i++)
+			poison_free(ht->tbl[i]);
+	}
+	/* Nothing to do for 0 < order && order <= ht->min_alloc_order */
+}
+
+static inline
+struct cds_lfht_node *bucket_at(struct cds_lfht *ht, unsigned long index)
+{
+	unsigned long chunk, offset;
+
+	if (__builtin_constant_p(index) && index == 0)
+		return &ht->tbl[0][0];
+
+	chunk = index >> ht->min_alloc_order;
+	offset = index & (ht->min_alloc_size - 1);
+	return &ht->tbl[chunk][offset];
+}
+#else
+/* LFHT_MEMORY_ORDER */
+static
+struct cds_lfht *_cds_lfht_alloc(unsigned long min_alloc_size,
+		unsigned long max_size)
+{
+	struct cds_lfht *ht;
+
+	ht = calloc(1, sizeof(struct cds_lfht));
+	assert(ht);
+
+	ht->min_alloc_size = min_alloc_size;
+	ht->min_alloc_order = get_count_order_ulong(min_alloc_size);
+	ht->max_size = max_size;
+
+	return ht;
+}
+
 static
 void cds_lfht_alloc_bucket_table(struct cds_lfht *ht, unsigned long order)
 {
@@ -803,6 +908,7 @@ struct cds_lfht_node *bucket_at(struct cds_lfht *ht, unsigned long index)
 		   index, order, index & ((1UL << (order - 1)) - 1));
 	return &ht->t.tbl[order][index & ((1UL << (order - 1)) - 1)];
 }
+#endif
 
 static inline
 struct cds_lfht_node *lookup_bucket(struct cds_lfht *ht, unsigned long size,
@@ -1376,8 +1482,11 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size,
 	if (!init_size || (init_size & (init_size - 1)))
 		return NULL;
 
+#ifdef LFHT_MEMORY_ORDER
+	/* max_size == 0 for LFHT_MEMORY_ORDER means infinite max_size. */
 	if (!max_size)
 		max_size = 1UL << (MAX_TABLE_ORDER - 1);
+#endif
 
 	/* max_size must be power of two */
 	if (!max_size || (max_size & (max_size - 1)))
@@ -1387,8 +1496,8 @@ struct cds_lfht *_cds_lfht_new(unsigned long init_size,
 	init_size = max(init_size, MIN_TABLE_SIZE);
 	max_size = max(max_size, min_alloc_size);
 	init_size = min(init_size, max_size);
-	ht = calloc(1, sizeof(struct cds_lfht));
-	assert(ht);
+
+	ht = _cds_lfht_alloc(min_alloc_size, max_size);
 	ht->flags = flags;
 	ht->cds_lfht_call_rcu = cds_lfht_call_rcu;
 	ht->cds_lfht_synchronize_rcu = cds_lfht_synchronize_rcu;
@@ -1404,9 +1513,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->t.resize_target = 1UL << order;
-	ht->min_alloc_size = min_alloc_size;
-	ht->min_alloc_order = get_count_order_ulong(min_alloc_size);
-	ht->max_size = max_size;
 	cds_lfht_create_bucket(ht, 1UL << order);
 	ht->t.size = 1UL << order;
 	return ht;
-- 
1.7.4.4





More information about the lttng-dev mailing list