[svn:parrot] r47868 - in branches/hash_allocator: include/parrot src src/call

whiteknight at svn.parrot.org whiteknight at svn.parrot.org
Sat Jun 26 14:46:13 UTC 2010


Author: whiteknight
Date: Sat Jun 26 14:46:12 2010
New Revision: 47868
URL: https://trac.parrot.org/parrot/changeset/47868

Log:
[hash] First pass at converting hash to use the fixed-size allocator. Things are indoubtably broken

Modified:
   branches/hash_allocator/include/parrot/hash.h
   branches/hash_allocator/src/call/args.c
   branches/hash_allocator/src/hash.c

Modified: branches/hash_allocator/include/parrot/hash.h
==============================================================================
--- branches/hash_allocator/include/parrot/hash.h	Sat Jun 26 13:31:35 2010	(r47867)
+++ branches/hash_allocator/include/parrot/hash.h	Sat Jun 26 14:46:12 2010	(r47868)
@@ -23,9 +23,8 @@
 typedef UINTVAL BucketIndex;
 #define INITBucketIndex ((BucketIndex)-2)
 
-#define N_BUCKETS(n) ((n) - (n)/4)
-#define HASH_ALLOC_SIZE(n) (N_BUCKETS(n) * sizeof (HashBucket) + \
-                                     (n) * sizeof (HashBucket *))
+#define N_BUCKETS(n) ((n) - (n)/4))
+#define HASH_ALLOC_SIZE(n) ((n) * sizeof (HashBucket *))
 
 typedef int (*hash_comp_fn)(PARROT_INTERP, ARGIN(const void *), ARGIN(const void *));
 typedef size_t (*hash_hash_key_fn)(PARROT_INTERP, ARGIN(const void *), size_t seed);
@@ -46,16 +45,15 @@
     void *value;
 } HashBucket;
 
-struct _hash {
-    /* Large slab store of buckets */
-    HashBucket *buckets;
+typedef struct _hashiteratorstate {
+    INTVAL idx;
+    HashBucket curr;
+} HashIteratorState;
 
+struct _hash {
     /* List of Bucket pointers */
     HashBucket **bucket_indices;
 
-    /* Store for empty buckets */
-    HashBucket *free_list;
-
     /* Number of values stored in hashtable */
     UINTVAL entries;
 

Modified: branches/hash_allocator/src/call/args.c
==============================================================================
--- branches/hash_allocator/src/call/args.c	Sat Jun 26 13:31:35 2010	(r47867)
+++ branches/hash_allocator/src/call/args.c	Sat Jun 26 14:46:12 2010	(r47868)
@@ -490,15 +490,16 @@
     else if (VTABLE_does(interp, aggregate, CONST_STRING(interp, "hash"))) {
         const INTVAL elements = VTABLE_elements(interp, aggregate);
         INTVAL index;
-        PMC * const key = Parrot_pmc_new(interp, enum_class_Key);
-        VTABLE_set_integer_native(interp, key, 0);
-        SETATTR_Key_next_key(interp, key, (PMC *)INITBucketIndex);
+        Hash * const hash = (Hash *)VTABLE_get_pointer(interp, aggregate);
+        HashIteratorState state;
+        state.idx = INITBucketIndex;
+        state.current = NULL;
 
         /* Low-level hash iteration. */
         for (index = 0; index < elements; ++index) {
             if (!PMC_IS_NULL(key)) {
-                STRING * const name = (STRING *)parrot_hash_get_idx(interp,
-                                (Hash *)VTABLE_get_pointer(interp, aggregate), key);
+                STRING * const name = (STRING *)Parrot_hash_get_next_key(interp,
+                                hash, &state);
                 PARROT_ASSERT(name);
                 VTABLE_set_pmc_keyed_str(interp, call_object, name,
                     VTABLE_get_pmc_keyed_str(interp, aggregate, name));

Modified: branches/hash_allocator/src/hash.c
==============================================================================
--- branches/hash_allocator/src/hash.c	Sat Jun 26 13:31:35 2010	(r47867)
+++ branches/hash_allocator/src/hash.c	Sat Jun 26 14:46:12 2010	(r47868)
@@ -28,10 +28,14 @@
 #include "pmc/pmc_key.h"
 
 /* the number of entries above which it's faster to hash the hashval instead of
- * looping over the used HashBuckets directly */
+   looping over the used HashBuckets directly */
 #define SMALL_HASH_SIZE  4
 #define INITIAL_BUCKETS  4
 
+/* The ratio of buckets to indices in the hash before we decide to realloc the
+   indices array */
+#define HASH_INDICES_RATIO 2.0
+
 /* HEADERIZER HFILE: include/parrot/hash.h */
 
 /* HEADERIZER BEGIN: static */
@@ -785,21 +789,10 @@
 
     void * const  old_mem    = hash->buckets;
     const UINTVAL old_size   = hash->mask + 1;
-    const UINTVAL new_size   = old_size << 1; /* Double. Right-shift is 2x */
+    const UINTVAL new_size   = old_size << 1; /* Double. Left-shift is 2x */
     const UINTVAL old_nb     = N_BUCKETS(old_size);
     size_t        offset, i;
 
-    /*
-       allocate some less buckets
-       e.g. 3 buckets, 4 pointers:
-
-         +---+---+---+-+-+-+-+
-         | --> buckets |     |
-         +---+---+---+-+-+-+-+
-         ^             ^
-         | old_mem     | hash->bucket_indices
-    */
-
     /* resize mem */
     if (old_offset != old_mem) {
         /* This buffer has been reallocated at least once before. */
@@ -1007,11 +1000,9 @@
         NOTNULL(hash_comp_fn compare), NOTNULL(hash_hash_key_fn keyhash))
 {
     ASSERT_ARGS(parrot_create_hash)
-    HashBucket  *bp;
-    void        *alloc = Parrot_gc_allocate_memory_chunk_with_interior_pointers(
-                            interp, sizeof (Hash) + HASH_ALLOC_SIZE(INITIAL_BUCKETS));
-    Hash * const hash  = (Hash*)alloc;
-    size_t       i;
+    const INTVAL numbuckets = N_BUCKETS(INITIAL_BUCKETS);
+    Hash * const hash  = (Hash*)Parrot_gc_allocate_fixed_size_storage(interp, sizeof (Hash));
+    HashBucket ** const bp = Parrot_gc_allocate_memory_chunk(interp, HASH_ALLOC_SIZE(INITIAL_BUCKETS));
 
     PARROT_ASSERT(INITIAL_BUCKETS % 4 == 0);
 
@@ -1023,22 +1014,7 @@
     hash->mask       = INITIAL_BUCKETS - 1;
     hash->entries    = 0;
     hash->container  = PMCNULL;
-
-    bp = (HashBucket *)((char *)alloc + sizeof (Hash));
-    hash->free_list = NULL;
-
-    /* fill free_list from hi addresses so that we can use
-     * buckets[i] directly in an OrderedHash, *if* nothing
-     * was deleted */
-
-    hash->buckets = bp;
-    bp += N_BUCKETS(INITIAL_BUCKETS);
-    hash->bucket_indices = (HashBucket **)bp;
-
-    for (i = 0, --bp; i < N_BUCKETS(INITIAL_BUCKETS); ++i, --bp) {
-        bp->next        = hash->free_list;
-        hash->free_list = bp;
-    }
+    hash->bucket_indices = bp;
 
     return hash;
 }
@@ -1061,10 +1037,8 @@
 parrot_hash_destroy(PARROT_INTERP, ARGFREE_NOTNULL(Hash *hash))
 {
     ASSERT_ARGS(parrot_hash_destroy)
-    HashBucket * const bp = (HashBucket*)((char*)hash + sizeof (Hash));
-    if (bp != hash->buckets)
-        mem_gc_free(interp, hash->buckets);
-    mem_gc_free(interp, hash);
+    Parrot_gc_free_memory_chunk(interp, hash->bucket_indices);
+    Parrot_gc_free_fixed_size_storage(interp, hash);
 }
 
 
@@ -1153,13 +1127,54 @@
     return hash->entries;
 }
 
+/*
+
+=item C<void * Parrot_hash_get_next_key(PARROT_INTERP, ARGIN(const Hash * hash),
+    ARGMOD(HashIteratorState *state)>
+
+Iterate through the hash using a state object to keep track of the current
+position in the hash as we go. Results are undefined if you modify the hash
+during iteration. It likely won't do what you want.
+
+=cut
+
+*/
+
+void *
+Parrot_hash_get_next_key(PARROT_INTERP, ARGIN(const Hash * hash),
+    ARGMOD(HashIteratorState *state)
+{
+    INTVAL i = state->idx == INITBucketIndex ?
+        0 : state->idx;
+    HashBucket * bp = state->current == NULL ?
+        hash->bucket_indices[i] : state->current->next;
+    void * result = NULL;
+
+    while(i < hash->entries) {
+        while (bp) {
+            if (bp->key) {
+                result = bp->key;
+                break;
+            }
+            bp = bp->next;
+        }
+        if (result != null)
+            break;
+        i++;
+        bp = hash->bucket_indices[i];
+    }
+    state->idx = i;
+    state->current = bp;
+    return result;
+}
+
 
 /*
 
 =item C<void * parrot_hash_get_idx(PARROT_INTERP, const Hash *hash, PMC *key)>
 
 Finds the next index into the hash's internal storage for the given Key.  Used
-by iterators.  Ugly.
+by iterators.  Ugly, and DEPRECATED.
 
 =cut
 
@@ -1235,29 +1250,14 @@
 PARROT_WARN_UNUSED_RESULT
 PARROT_CAN_RETURN_NULL
 HashBucket *
-parrot_hash_get_bucket(PARROT_INTERP, ARGIN(const Hash *hash), ARGIN_NULLOK(const void *key))
+parrot_hash_get_bucket(PARROT_INTERP, ARGIN(const Hash *hash),
+    ARGIN_NULLOK(const void *key))
 {
     ASSERT_ARGS(parrot_hash_get_bucket)
 
     if (hash->entries <= 0)
         return NULL;
-
-    /* a very fast search for very small hashes */
-    if (hash->entries <= SMALL_HASH_SIZE) {
-        const UINTVAL  entries = hash->entries;
-        UINTVAL        i;
-
-        for (i = 0; i < entries; ++i) {
-            HashBucket * const bucket = hash->buckets + i;
-
-            /* the hash->compare cost is too high for this fast path */
-            if (bucket->key == key)
-                return bucket;
-        }
-    }
-
-    /* if the fast search didn't work, try the normal hashing search */
-    {
+    else {
         const UINTVAL hashval = (hash->hash_val)(interp, key, hash->seed);
         HashBucket   *bucket  = hash->bucket_indices[hashval & hash->mask];
 
@@ -1370,19 +1370,15 @@
     if (bucket)
         bucket->value = value;
     else {
-        /* Get a new bucket off the free list. If the free list is empty, we
-           expand the hash so we get more items on the free list */
-        bucket = hash->free_list;
-        if (!bucket) {
-            expand_hash(interp, hash);
-            bucket = hash->free_list;
-        }
+        bucket = (HashBucket *)Parrot_gc_allocate_fixed_size_storage(interp,
+            sizeof(HashBucket));
+
+        /* TODO: Expand the hash if we need to */
 
         /* Add the value to the new bucket, increasing the count of elements */
         ++hash->entries;
-        hash->free_list                = bucket->next;
-        bucket->key                    = key;
-        bucket->value                  = value;
+        bucket->key   = key;
+        bucket->value = value;
         bucket->next = hash->bucket_indices[hashval & hash->mask];
         hash->bucket_indices[hashval & hash->mask] = bucket;
     }
@@ -1419,9 +1415,7 @@
                 hash->bucket_indices[hashval] = bucket->next;
 
             --hash->entries;
-            bucket->next    = hash->free_list;
-            bucket->key     = NULL;
-            hash->free_list = bucket;
+            Parrot_gc_free_fixed_size_storage(interp, bucket);
 
             return;
         }


More information about the parrot-commits mailing list