2
0
Эх сурвалжийг харах

reduce memory size and increase locality for small maps

Nicolas Cannasse 2 жил өмнө
parent
commit
71b4f050dc
2 өөрчлөгдсөн 58 нэмэгдсэн , 37 устгасан
  1. 4 6
      src/std/maps.c
  2. 54 31
      src/std/maps.h

+ 4 - 6
src/std/maps.c

@@ -20,6 +20,9 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include <hl.h>
+#ifdef HL_VCC
+#	pragma warning(disable:4034) // sizeof(void) == 0
+#endif
 
 #define H_SIZE_INIT 3
 
@@ -138,7 +141,6 @@ static int hl_freelist_get( hl_free_list *f ) {
 
 typedef struct {
 	int key;
-	int next;
 } hl_hi_entry;
 
 typedef struct {
@@ -162,7 +164,6 @@ typedef struct {
 
 typedef struct {
 	int64 key;
-	int next;
 } hl_hi64_entry;
 
 typedef struct {
@@ -185,7 +186,6 @@ typedef struct {
 
 typedef struct {
 	unsigned int hash;
-	int next;
 } hl_hb_entry;
 
 typedef struct {
@@ -207,9 +207,7 @@ typedef struct {
 
 // ----- OBJECT MAP ---------------------------------
 
-typedef struct {
-	int next;
-} hl_ho_entry;
+typedef void hl_ho_entry;
 
 typedef struct {
 	vdynamic *key;

+ 54 - 31
src/std/maps.h

@@ -7,9 +7,13 @@
 #define t_map _MNAME(_map)
 #define t_entry _MNAME(_entry)
 #define t_value _MNAME(_value)
+#define _MLIMIT 128
+#define _MINDEX(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((char*)(m)->cells)[ckey] : ((int*)(m)->cells)[ckey])
+#define _MNEXT(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((char*)(m)->nexts)[ckey] : ((int*)(m)->nexts)[ckey])
 
 typedef struct {
-	int *cells;
+	void *cells;
+	void *nexts;
 	t_entry *entries;
 	t_value *values;
 	hl_free_list lfree;
@@ -27,14 +31,15 @@ HL_PRIM t_map *_MNAME(alloc)() {
 static vdynamic **_MNAME(find)( t_map *m, t_key key ) {
 	int c, ckey;
 	unsigned int hash;
-	if( !m->entries ) return NULL;
+
+	if( !m->values ) return NULL;
 	hash = _MNAME(hash)(key);
 	ckey = hash % ((unsigned)m->ncells);
-	c = m->cells[ckey];
+	c = _MINDEX(m,ckey);
 	while( c >= 0 ) {
 		if( _MMATCH(c) )
 			return &m->values[c].value;
-		c = m->entries[c].next;
+		c = _MNEXT(m,c);
 	}
 	return NULL;
 }
@@ -44,15 +49,15 @@ static void _MNAME(resize)( t_map *m );
 static void _MNAME(set_impl)( t_map *m, t_key key, vdynamic *value ) {
 	int c, ckey = 0;
 	unsigned int hash = _MNAME(hash)(key);
-	if( m->entries ) {
+	if( m->values ) {
 		ckey = hash % ((unsigned)m->ncells);
-		c = m->cells[ckey];
+		c = _MINDEX(m,ckey);
 		while( c >= 0 ) {
 			if( _MMATCH(c) ) {
 				m->values[c].value = value;
 				return;
 			}
-			c = m->entries[c].next;
+			c = _MNEXT(m,c);
 		}
 	}
 	c = hl_freelist_get(&m->lfree);
@@ -62,8 +67,13 @@ static void _MNAME(set_impl)( t_map *m, t_key key, vdynamic *value ) {
 		c = hl_freelist_get(&m->lfree);
 	}
 	_MSET(c);
-	m->entries[c].next = m->cells[ckey];
-	m->cells[ckey] = c;
+	if( m->maxentries < _MLIMIT ) {
+		((char*)m->nexts)[c] = ((char*)m->cells)[ckey];
+		((char*)m->cells)[ckey] = (char)c;
+	} else {
+		((int*)m->nexts)[c] = ((int*)m->cells)[ckey];
+		((int*)m->cells)[ckey] = c;
+	}
 	m->values[c].value = value;
 	m->nentries++;
 }
@@ -82,35 +92,40 @@ static void _MNAME(resize)( t_map *m ) {
 	while( H_PRIMES[i] < ncells ) i++;
 	ncells = H_PRIMES[i];
 
+	int ksize = nentries < _MLIMIT ? 1 : sizeof(int);
 	m->entries = (t_entry*)hl_gc_alloc_noptr(nentries * sizeof(t_entry));
 	m->values = (t_value*)hl_gc_alloc_raw(nentries * sizeof(t_value));
 	m->maxentries = nentries;
 
-	if( old.ncells == ncells ) {
+	if( old.ncells == ncells && (nentries < _MLIMIT || old.maxentries >= _MLIMIT) ) {
 		// simply expand
+		m->nexts = hl_gc_alloc_noptr(nentries * ksize);
 		memcpy(m->entries,old.entries,old.maxentries * sizeof(t_entry));
 		memcpy(m->values,old.values,old.maxentries * sizeof(t_value));
+		memcpy(m->nexts,old.nexts,old.maxentries * ksize);
 		memset(m->values + old.maxentries, 0, (nentries - old.maxentries) * sizeof(t_value));
 		hl_freelist_add_range(&m->lfree,old.maxentries,m->maxentries - old.maxentries);
 	} else {
 		// expand and remap
-		m->cells = (int*)hl_gc_alloc_noptr(ncells * sizeof(int));
+		m->cells = hl_gc_alloc_noptr((ncells + nentries) * ksize);
+		m->nexts = (char*)m->cells + ncells * ksize;
 		m->ncells = ncells;
 		m->nentries = 0;
-		memset(m->cells,0xFF,ncells * sizeof(int));
+		memset(m->cells,0xFF,ncells * ksize);
 		memset(m->values, 0, nentries * sizeof(t_value));
 		hl_freelist_init(&m->lfree);
 		hl_freelist_add_range(&m->lfree,0,m->maxentries);
-
-		hl_add_root(&old); // prevent old.cells pointer aliasing
-		for(i=0;i<old.ncells;i++) {
-			int c = old.cells[i];
-			while( c >= 0 ) {
-				_MNAME(set_impl)(m,_MKEY((&old),c),old.values[c].value);
-				c = old.entries[c].next;
+		if( old.ncells ) {
+			hl_add_root(&old); // prevent old.cells pointer aliasing
+			for(i=0;i<old.ncells;i++) {
+				int c = old.maxentries < _MLIMIT ? ((char*)old.cells)[i] : ((int*)old.cells)[i];
+				while( c >= 0 ) {
+					_MNAME(set_impl)(m,_MKEY((&old),c),old.values[c].value);
+					c = _MNEXT(&old,c);
+				}
 			}
+			hl_remove_root(&old);
 		}
-		hl_remove_root(&old);
 	}
 }
 
@@ -135,21 +150,28 @@ HL_PRIM bool _MNAME(remove)( t_map *m, t_key key ) {
 	key = _MNAME(filter)(key);
 	hash = _MNAME(hash)(key);
 	ckey = hash % ((unsigned)m->ncells);
-	c = m->cells[ckey];
+	c = _MINDEX(m,ckey);
 	while( c >= 0 ) {
 		if( _MMATCH(c) ) {
 			hl_freelist_add(&m->lfree,c);
 			m->nentries--;
 			_MERASE(c);
 			m->values[c].value = NULL;
-			if( prev >= 0 )
-				m->entries[prev].next = m->entries[c].next;
-			else
-				m->cells[ckey] = m->entries[c].next;
+			if( m->maxentries < _MLIMIT ) {
+				if( prev >= 0 )
+					((char*)m->nexts)[prev] = ((char*)m->nexts)[c];
+				else
+					((char*)m->cells)[ckey] = ((char*)m->nexts)[c];
+			} else {
+				if( prev >= 0 )
+					((int*)m->nexts)[prev] = ((int*)m->nexts)[c];
+				else
+					((int*)m->cells)[ckey] = ((int*)m->nexts)[c];
+			}
 			return true;
 		}
 		prev = c;
-		c = m->entries[c].next;
+		c = _MNEXT(m,c);
 	}
 	return false;
 }
@@ -160,10 +182,10 @@ HL_PRIM varray* _MNAME(keys)( t_map *m ) {
 	int p = 0;
 	int i;
 	for(i=0;i<m->ncells;i++) {
-		int c = m->cells[i];
+		int c = _MINDEX(m,i);
 		while( c >= 0 ) {
 			keys[p++] = _MKEY(m,c);
-			c = m->entries[c].next;
+			c = _MNEXT(m,c);
 		}
 	}
 	return a;
@@ -175,10 +197,10 @@ HL_PRIM varray* _MNAME(values)( t_map *m ) {
 	int p = 0;
 	int i;
 	for(i=0;i<m->ncells;i++) {
-		int c = m->cells[i];
+		int c = _MINDEX(m,i);
 		while( c >= 0 ) {
 			values[p++] = m->values[c].value;
-			c = m->entries[c].next;
+			c = _MNEXT(m,c);
 		}
 	}
 	return a;
@@ -202,4 +224,5 @@ HL_PRIM int _MNAME(size)( t_map *m ) {
 #undef _MSET
 #undef _MERASE
 #undef _MOLD_KEY
-
+#undef _MINDEX
+#undef _MNEXT