[svn:parrot] r49000 - in trunk: include/parrot src

luben at svn.parrot.org luben at svn.parrot.org
Tue Sep 14 16:55:34 UTC 2010


Author: luben
Date: Tue Sep 14 16:55:34 2010
New Revision: 49000
URL: https://trac.parrot.org/parrot/changeset/49000

Log:
Use fixed size allocator for small hashes

Modified:
   trunk/include/parrot/hash.h
   trunk/src/hash.c

Modified: trunk/include/parrot/hash.h
==============================================================================
--- trunk/include/parrot/hash.h	Tue Sep 14 16:35:42 2010	(r48999)
+++ trunk/include/parrot/hash.h	Tue Sep 14 16:55:34 2010	(r49000)
@@ -68,6 +68,7 @@
 
     /* Random seed value for seeding hash algorithms */
     size_t seed;
+
 };
 
 /* Utility macros - use them, do not reinvent the wheel */
@@ -89,26 +90,29 @@
 #define parrot_hash_iterate_indexed(_hash, _code)                           \
 {                                                                           \
     INTVAL _loc;                                                            \
-    for (_loc = (_hash)->mask; _loc >= 0; --_loc) {                         \
-        HashBucket *_bucket = (_hash)->index[_loc];                         \
-        while (_bucket) {                                                   \
-            _code                                                           \
-            _bucket = _bucket->next;                                        \
+        if ((_hash)->entries){                                              \
+            for (_loc = 0; _loc <= (_hash)->mask; ++_loc) {                 \
+                HashBucket *_bucket = (_hash)->index[_loc];                 \
+                while (_bucket) {                                           \
+                    _code                                                   \
+                    _bucket = _bucket->next;                                \
+                }                                                           \
+            }                                                               \
         }                                                                   \
-    }                                                                       \
 }
 
-
 #define parrot_hash_iterator_advance(_hash, _bucket, _loc)                  \
 {                                                                           \
-    /* Try to advance current bucket */                                     \
-    if ((_bucket))                                                          \
-        (_bucket) = (_bucket)->next;                                        \
-    while (!(_bucket)) {                                                    \
-        /* If there is no more buckets */                                   \
-        if ((_loc) == (INTVAL)(_hash)->mask+1)                              \
-            break;                                                          \
-        (_bucket) = (_hash)->index[(_loc)++];                               \
+    if ((_hash)->entries) {                                                 \
+        /* Try to advance current bucket */                                 \
+        if ((_bucket))                                                      \
+            (_bucket) = (_bucket)->next;                                    \
+        while (!(_bucket)) {                                                \
+            /* If there is no more buckets */                               \
+            if ((_loc) == (INTVAL)(_hash)->mask+1)                          \
+                break;                                                      \
+            (_bucket) = (_hash)->index[(_loc)++];                           \
+        }                                                                   \
     }                                                                       \
 }
 
@@ -335,7 +339,6 @@
 
 PARROT_CANNOT_RETURN_NULL
 PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
 Hash * parrot_create_hash(PARROT_INTERP,
     PARROT_DATA_TYPE val_type,
     Hash_key_type hkey_type)
@@ -343,7 +346,6 @@
 
 PARROT_CANNOT_RETURN_NULL
 PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
 Hash * parrot_create_hash_sized(PARROT_INTERP,
     PARROT_DATA_TYPE val_type,
     Hash_key_type hkey_type,
@@ -369,7 +371,6 @@
 
 PARROT_CANNOT_RETURN_NULL
 PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
 Hash * Parrot_hash_thaw(PARROT_INTERP, ARGMOD(PMC *info))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)

Modified: trunk/src/hash.c
==============================================================================
--- trunk/src/hash.c	Tue Sep 14 16:35:42 2010	(r48999)
+++ trunk/src/hash.c	Tue Sep 14 16:55:34 2010	(r49000)
@@ -28,13 +28,26 @@
 
 /* the number of entries above which it's faster to hash the hashval instead of
  * looping over the used HashBuckets directly */
-#define INITIAL_SIZE  8
+
+/* hash first allocation size */
+#define INITIAL_SIZE  2
+
+/* below this hash size we use fixed_size_allocator
+ * else we use system allocator */
+#define SPLIT_POINT  16
 
 /* HEADERIZER HFILE: include/parrot/hash.h */
 
 /* HEADERIZER BEGIN: static */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
+static void allocate_buckets(PARROT_INTERP,
+    ARGMOD(Hash *hash),
+    ARGIN_NULLOK(const UINTVAL size))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        FUNC_MODIFIES(*hash);
+
 static void expand_hash(PARROT_INTERP, ARGMOD(Hash *hash))
         __attribute__nonnull__(1)
         __attribute__nonnull__(2)
@@ -172,6 +185,9 @@
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
+#define ASSERT_ARGS_allocate_buckets __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(hash))
 #define ASSERT_ARGS_expand_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(hash))
@@ -613,6 +629,9 @@
     int mark_key   = 0;
     int mark_value = 0;
 
+    if (!hash->buckets)
+        return;
+
     if (hash->entry_type == (PARROT_DATA_TYPE) enum_hash_string
     ||  hash->entry_type == (PARROT_DATA_TYPE) enum_hash_pmc)
         mark_value = 1;
@@ -740,7 +759,6 @@
 
 PARROT_CANNOT_RETURN_NULL
 PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
 Hash *
 Parrot_hash_thaw(PARROT_INTERP, ARGMOD(PMC *info))
 {
@@ -885,6 +903,51 @@
         });
 }
 
+/*
+
+=item C<static void allocate_buckets(PARROT_INTERP, Hash *hash, const UINTVAL
+size)>
+
+Allocate sized buckets and index storage for a hash
+
+=cut
+
+*/
+
+static void
+allocate_buckets(PARROT_INTERP, ARGMOD(Hash *hash), ARGIN_NULLOK(const UINTVAL size))
+{
+    ASSERT_ARGS(allocate_buckets)
+
+    UINTVAL new_size = INITIAL_SIZE;
+    HashBucket *new_buckets, *bucket;
+    size_t i;
+
+    while (size > new_size)
+        new_size <<= 1;
+
+    if (new_size > SPLIT_POINT)
+        new_buckets  = (HashBucket *) Parrot_gc_allocate_memory_chunk(
+                        interp, HASH_ALLOC_SIZE(new_size));
+    else
+        new_buckets  = (HashBucket *) Parrot_gc_allocate_fixed_size_storage(
+                        interp, HASH_ALLOC_SIZE(new_size));
+
+    memset(new_buckets, 0, HASH_ALLOC_SIZE(new_size));
+
+    hash->mask      = new_size - 1;
+    hash->buckets   = new_buckets;
+    hash->index     = (HashBucket **)(new_buckets + N_BUCKETS(new_size));
+
+    /* add new buckets to free_list
+     * lowest bucket is top on free list and will be used first */
+
+    bucket = hash->buckets + N_BUCKETS(new_size) - 1;
+    for (i = 0; i < N_BUCKETS(new_size); ++i, --bucket) {
+        bucket->next    = hash->free_list;
+        hash->free_list = bucket;
+    }
+}
 
 /*
 
@@ -924,8 +987,6 @@
     HashBucket  **new_index,  **index;
     HashBucket   *new_buckets, *bucket;
 
-    HashBucket * const initial_offset = (HashBucket *)((char *)hash + sizeof (Hash));
-
     void *        new_mem;
     void * const  old_mem    = hash->buckets;
     const UINTVAL old_size   = hash->mask + 1;
@@ -945,42 +1006,37 @@
     */
 
     /* resize mem */
-    if (initial_offset != old_mem) {
-        /* This buffer has been reallocated at least once before. */
-        new_mem   = Parrot_gc_reallocate_memory_chunk_with_interior_pointers(
-                interp, old_mem,
-                HASH_ALLOC_SIZE(new_size),
-                HASH_ALLOC_SIZE(old_size));
-
-        new_buckets = (HashBucket *)  new_mem;
-        new_index   = (HashBucket **)(new_buckets + N_BUCKETS(new_size));
-
-        offset = (char *)new_mem - (char *)old_mem;
-
-        /* old index is here */
-        index  = (HashBucket **)(new_buckets + N_BUCKETS(old_size));
-        /* reallocate index */
-        mem_sys_memcopy(new_index, index, sizeof (HashBucket *) * old_size);
-
-        /* clear second half of the buckets, freed by old the index */
-        memset(new_buckets + N_BUCKETS(old_size), 0,
-                sizeof (HashBucket *) * old_size);
-    }
-    else {
-        /* Allocate a new buffer. */
-        new_mem = Parrot_gc_allocate_memory_chunk_with_interior_pointers(
-                interp, HASH_ALLOC_SIZE(new_size));
-
-        new_buckets = (HashBucket *)  new_mem;
-        new_index   = (HashBucket **)(new_buckets + N_BUCKETS(new_size));
-
-        offset = (char *)new_buckets - (char *)hash->buckets;
-
-        mem_sys_memcopy(new_buckets, hash->buckets ,
-                N_BUCKETS(old_size) * sizeof (HashBucket));
-        mem_sys_memcopy(new_index,   hash->index,
-                sizeof (HashBucket *) * old_size);
-    }
+    if (new_size > SPLIT_POINT)
+        new_mem  = Parrot_gc_allocate_memory_chunk(
+                        interp, HASH_ALLOC_SIZE(new_size));
+    else
+        new_mem  = Parrot_gc_allocate_fixed_size_storage(
+                        interp, HASH_ALLOC_SIZE(new_size));
+
+    offset = (char *)new_mem - (char *)old_mem;
+
+    new_buckets = (HashBucket *)  new_mem;
+    new_index   = (HashBucket **)(new_buckets + N_BUCKETS(new_size));
+
+    /* copy buckets and index */
+    mem_sys_memcopy(new_buckets, hash->buckets,
+            N_BUCKETS(old_size) * sizeof (HashBucket));
+    mem_sys_memcopy(new_index, hash->index, old_size * sizeof (HashBucket **));
+
+    /* free */
+    if (old_size > SPLIT_POINT)
+        Parrot_gc_free_memory_chunk(interp, old_mem);
+    else
+        Parrot_gc_free_fixed_size_storage(interp, HASH_ALLOC_SIZE(old_size), old_mem);
+
+
+    /* clear second half of the buckets, freed by old the index */
+    memset(new_buckets + N_BUCKETS(old_size), 0,
+            sizeof (HashBucket *) * old_size);
+
+    /* clear second half of the index */
+    memset(new_index + (old_size), 0, sizeof (HashBucket **) * old_size);
+
 
 
     /*
@@ -1032,16 +1088,13 @@
 
     /* add new buckets to free_list
      * lowest bucket is top on free list and will be used first */
-
     bucket = new_buckets + N_BUCKETS(old_size);
-
-    for (; bucket < new_buckets + N_BUCKETS(new_size) - 1; ++bucket) {
+    for (i = N_BUCKETS(old_size)-1 ; i > 0; --i, ++bucket) {
         bucket->next = bucket + 1;
-        bucket->key  = bucket->value = NULL;
     }
 
-    hash->free_list = new_buckets + N_BUCKETS(old_size);
     bucket->next = NULL;
+    hash->free_list = new_buckets + N_BUCKETS(old_size);
 }
 
 
@@ -1150,32 +1203,22 @@
 
 PARROT_CANNOT_RETURN_NULL
 PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
 Hash *
 parrot_create_hash(PARROT_INTERP, PARROT_DATA_TYPE val_type, Hash_key_type hkey_type)
 {
     ASSERT_ARGS(parrot_create_hash)
-    return parrot_create_hash_sized(interp, val_type, hkey_type, INITIAL_SIZE);
-}
-
-
-/*
+    Hash * const hash = (Hash*) Parrot_gc_allocate_fixed_size_storage(interp, sizeof (Hash));
 
-=item C<static UINTVAL round_up_pow2(UINTVAL x)>
-
-Round a value up to the nearest power of 2.
-
-=cut
-
-*/
+    hash->entry_type = val_type;
+    hash->key_type   = hkey_type;
+    hash->seed       = interp->hash_seed;
+    hash->mask       = 0;
+    hash->entries    = 0;
+    hash->index      = NULL;
+    hash->buckets    = NULL;
+    hash->free_list  = NULL;
 
-PARROT_INLINE
-static UINTVAL
-round_up_pow2(UINTVAL x) {
-    UINTVAL y = 1;
-    while (y < x)
-        y <<= 1;
-    return y;
+    return hash;
 }
 
 
@@ -1194,43 +1237,14 @@
 
 PARROT_CANNOT_RETURN_NULL
 PARROT_WARN_UNUSED_RESULT
-PARROT_MALLOC
 Hash *
 parrot_create_hash_sized(PARROT_INTERP, PARROT_DATA_TYPE val_type, Hash_key_type hkey_type,
         UINTVAL size)
 {
     ASSERT_ARGS(parrot_create_hash_sized)
-    UINTVAL      initial_buckets = size > INITIAL_SIZE ? round_up_pow2(size) : INITIAL_SIZE;
-    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;
-
-    PARROT_ASSERT(initial_buckets % 4 == 0);
-
-    hash->entry_type = val_type;
-    hash->key_type   = hkey_type;
-    hash->seed       = interp->hash_seed;
-    hash->mask       = initial_buckets - 1;
-    hash->entries    = 0;
-
-    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->index = (HashBucket **)bp;
-
-    for (i = 0, --bp; i < N_BUCKETS(initial_buckets); ++i, --bp) {
-        bp->next        = hash->free_list;
-        hash->free_list = bp;
-    }
 
+    Hash *hash = parrot_create_hash(interp, val_type, hkey_type);
+    allocate_buckets(interp, hash, size);
     return hash;
 }
 
@@ -1252,10 +1266,14 @@
 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);
+    if (hash->buckets){
+        if (hash->mask > SPLIT_POINT)
+            Parrot_gc_free_memory_chunk(interp, hash->buckets);
+        else
+            Parrot_gc_free_fixed_size_storage(interp,
+                HASH_ALLOC_SIZE(hash->mask+1), hash->buckets);
+    }
+    Parrot_gc_free_fixed_size_storage(interp, sizeof (Hash), hash);
 }
 
 
@@ -1460,38 +1478,44 @@
         ARGIN_NULLOK(void *key), ARGIN_NULLOK(void *value))
 {
     ASSERT_ARGS(parrot_hash_put)
-    HashBucket *bucket;
+    HashBucket *bucket = NULL;
     size_t      hashval;
 
-    if (hash->key_type == Hash_key_type_STRING) {
-        const STRING * const s = (STRING *)key;
-        hashval                = key_hash_STRING(interp, (STRING *)key, hash->seed);
-        bucket                 = hash->index[hashval & hash->mask];
-
-        while (bucket) {
-            const STRING *s2 = (const STRING *)bucket->key;
-            if (s == s2)
-                break;
-            /* manually inline part of string_equal  */
-            if (hashval == s2->hashval) {
-                if (s->encoding == s2->encoding) {
-                    if ((STRING_byte_length(s) == STRING_byte_length(s2))
-                    && (memcmp(s->strstart, s2->strstart, STRING_byte_length(s)) == 0))
-                        break;
-                } else if (STRING_equal(interp, s, s2))
-                        break;
-            }
-            bucket = bucket->next;
-        }
+    if (!hash->buckets){
+        allocate_buckets(interp, hash, INITIAL_SIZE);
+        hashval = key_hash(interp, hash, key);
     }
     else {
-        hashval = key_hash(interp, hash, key);
-        bucket  = hash->index[hashval & hash->mask];
+        if (hash->key_type == Hash_key_type_STRING) {
+            const STRING * const s = (STRING *)key;
+            hashval                = key_hash_STRING(interp, (STRING *)key, hash->seed);
+            bucket                 = hash->index[hashval & hash->mask];
+
+            while (bucket) {
+                const STRING *s2 = (const STRING *)bucket->key;
+                if (s == s2)
+                    break;
+                /* manually inline part of string_equal  */
+                if (hashval == s2->hashval) {
+                    if (s->encoding == s2->encoding) {
+                        if ((STRING_byte_length(s) == STRING_byte_length(s2))
+                        && (memcmp(s->strstart, s2->strstart, STRING_byte_length(s)) == 0))
+                            break;
+                    } else if (STRING_equal(interp, s, s2))
+                            break;
+                }
+                bucket = bucket->next;
+            }
+        }
+        else {
+            hashval = key_hash(interp, hash, key);
+            bucket  = hash->index[hashval & hash->mask];
 
-        while (bucket) {
-            if (hash_compare(interp, hash, key, bucket->key) == 0)
-                break;
-            bucket = bucket->next;
+            while (bucket) {
+                if (hash_compare(interp, hash, key, bucket->key) == 0)
+                    break;
+                bucket = bucket->next;
+            }
         }
     }
 
@@ -1536,17 +1560,19 @@
 {
     ASSERT_ARGS(parrot_hash_delete)
     const UINTVAL hashval = key_hash(interp, hash, key) & hash->mask;
-    HashBucket   **prev   = &hash->index[hashval];
-    if (*prev) {
-        for (; *prev; prev = &(*prev)->next) {
-            HashBucket *current = *prev;
-            if (hash_compare(interp, hash, key, current->key) == 0) {
-                *prev = current->next;
-                --hash->entries;
-                current->next    = hash->free_list;
-                current->key     = NULL;
-                hash->free_list = current;
-                return;
+    if (hash->buckets){
+        HashBucket   **prev   = &hash->index[hashval];
+        if (*prev) {
+            for (; *prev; prev = &(*prev)->next) {
+                HashBucket *current = *prev;
+                if (hash_compare(interp, hash, key, current->key) == 0) {
+                    *prev = current->next;
+                    --hash->entries;
+                    current->next    = hash->free_list;
+                    current->key     = NULL;
+                    hash->free_list = current;
+                    return;
+                }
             }
         }
     }


More information about the parrot-commits mailing list