[svn:parrot] r48613 - trunk/src

nwellnhof at svn.parrot.org nwellnhof at svn.parrot.org
Mon Aug 23 14:54:50 UTC 2010


Author: nwellnhof
Date: Mon Aug 23 14:54:49 2010
New Revision: 48613
URL: https://trac.parrot.org/parrot/changeset/48613

Log:
Fast path for hash get/put with string keys

Inline get_hash_val and STRING_compare in hash_get_bucket and hash_put.
Also remove the COW test from STRING_compare. It was wrong (should have
used strstart instead of bufstart) and didn't give a speedup.

Modified:
   trunk/src/hash.c

Modified: trunk/src/hash.c
==============================================================================
--- trunk/src/hash.c	Mon Aug 23 13:21:42 2010	(r48612)
+++ trunk/src/hash.c	Mon Aug 23 14:54:49 2010	(r48613)
@@ -49,12 +49,6 @@
         __attribute__nonnull__(2)
         FUNC_MODIFIES(*hash);
 
-static UINTVAL get_hash_val(PARROT_INTERP,
-    ARGIN(const Hash *hash),
-    ARGIN_NULLOK(const void *key))
-        __attribute__nonnull__(1)
-        __attribute__nonnull__(2);
-
 static void hash_freeze(PARROT_INTERP,
     ARGIN(const Hash *hash),
     ARGMOD(PMC *info))
@@ -108,9 +102,6 @@
 #define ASSERT_ARGS_expand_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(hash))
-#define ASSERT_ARGS_get_hash_val __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
-       PARROT_ASSERT_ARG(interp) \
-    , PARROT_ASSERT_ARG(hash))
 #define ASSERT_ARGS_hash_freeze __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(hash) \
@@ -164,36 +155,6 @@
 
 /*
 
-=item C<static UINTVAL get_hash_val(PARROT_INTERP, const Hash *hash, const void
-*key)>
-
-An inlinable helper function to avoid the overhead of calling key_hash_STRING()
-when there's already a calculated hash value for the STRING key.
-
-=cut
-
-*/
-
-static UINTVAL
-get_hash_val(PARROT_INTERP, ARGIN(const Hash *hash), ARGIN_NULLOK(const void *key))
-{
-    ASSERT_ARGS(get_hash_val)
-    if (hash->hash_val == (hash_hash_key_fn)key_hash_STRING) {
-        /* Must be non-const because str_to_hashval caches the result
-         * in the STRING struct */
-        DECL_CONST_CAST;
-        STRING * const s = (STRING *)PARROT_const_cast(void *, key);
-        if (s->hashval)
-            return s->hashval;
-        return Parrot_str_to_hashval(interp, s);
-    }
-
-    return (hash->hash_val)(interp, key, hash->seed);
-}
-
-
-/*
-
 =item C<int STRING_compare(PARROT_INTERP, const void *search_key, const void
 *bucket_key)>
 
@@ -211,17 +172,9 @@
     STRING const *s1 = (STRING const *)search_key;
     STRING const *s2 = (STRING const *)bucket_key;
 
-    if (!s2)
-        return 1;
-
     if (s1->hashval != s2->hashval)
         return 1;
 
-    /* COWed strings */
-    if (Buffer_bufstart(s1) == Buffer_bufstart(s2)
-    &&  s1->bufused == s2->bufused)
-        return 0;
-
     return CHARSET_COMPARE(interp, s1, s2);
 }
 
@@ -863,7 +816,7 @@
         while ((b = *next_p) != NULL) {
             /* rehash the bucket */
             const size_t new_loc =
-                get_hash_val(interp, hash, b->key) & (new_size - 1);
+                (hash->hash_val)(interp, b->key, hash->seed) & (new_size - 1);
 
             if (i != new_loc) {
                 *next_p         = b->next;
@@ -1160,15 +1113,39 @@
 parrot_hash_get_bucket(PARROT_INTERP, ARGIN(const Hash *hash), ARGIN_NULLOK(const void *key))
 {
     ASSERT_ARGS(parrot_hash_get_bucket)
+    UINTVAL     hashval;
+    HashBucket *bucket;
+    const hash_hash_key_fn hash_val = hash->hash_val;
+    const hash_comp_fn     compare  = hash->compare;
 
     if (hash->entries <= 0)
         return NULL;
 
-    /* if the fast search didn't work, try the normal hashing search */
-    {
-        const UINTVAL hashval = get_hash_val(interp, hash, key);
-        HashBucket   *bucket  = hash->index[hashval & hash->mask];
-        const hash_comp_fn compare = hash->compare;
+    if (hash_val == key_hash_STRING && compare == STRING_compare) {
+        /* fast path for string keys */
+        const STRING *s = (const STRING *)key;
+
+        if (s->hashval)
+            hashval = s->hashval;
+        else
+            hashval = Parrot_str_to_hashval(interp, s);
+
+        bucket = hash->index[hashval & hash->mask];
+
+        while (bucket) {
+            const STRING *s2 = (const STRING *)bucket->key;
+
+            if (s == s2
+            || (s->hashval == s2->hashval
+            &&  CHARSET_COMPARE(interp, s, s2) == 0))
+                return bucket;
+
+            bucket = bucket->next;
+        }
+    }
+    else {
+        hashval = hash_val(interp, key, hash->seed);
+        bucket  = hash->index[hashval & hash->mask];
 
         while (bucket) {
             /* key equality is always a match, so it's worth checking */
@@ -1248,16 +1225,44 @@
         ARGIN_NULLOK(void *key), ARGIN_NULLOK(void *value))
 {
     ASSERT_ARGS(parrot_hash_put)
-    const UINTVAL hashval = get_hash_val(interp, hash, key);
-    HashBucket   *bucket  = hash->index[hashval & hash->mask];
-    const hash_comp_fn compare = hash->compare;
-
-    /* See if we have an existing value for this key */
-    while (bucket) {
-        /* store hash_val or not */
-        if ((compare)(interp, key, bucket->key) == 0)
-            break;
-        bucket = bucket->next;
+    UINTVAL     hashval;
+    HashBucket *bucket;
+    const hash_hash_key_fn hash_val = hash->hash_val;
+    const hash_comp_fn     compare  = hash->compare;
+
+    if (hash_val == key_hash_STRING && compare == STRING_compare) {
+        /* fast path for string keys */
+        const STRING *s = (const STRING *)key;
+
+        if (s->hashval)
+            hashval = s->hashval;
+        else
+            hashval = Parrot_str_to_hashval(interp, s);
+
+        bucket = hash->index[hashval & hash->mask];
+
+        while (bucket) {
+            const STRING *s2 = (const STRING *)bucket->key;
+
+            if (s == s2
+            || (s->hashval  == s2->hashval
+            &&  CHARSET_COMPARE(interp, s, s2) == 0))
+                break;
+
+            bucket = bucket->next;
+        }
+    }
+    else {
+        hashval = hash_val(interp, key, hash->seed);
+        bucket  = hash->index[hashval & hash->mask];
+
+        /* See if we have an existing value for this key */
+        while (bucket) {
+            /* store hash_val or not */
+            if (compare(interp, key, bucket->key) == 0)
+                break;
+            bucket = bucket->next;
+        }
     }
 
     /* If we have a bucket already, put the value in it. Otherwise, we need


More information about the parrot-commits mailing list