You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2012/09/07 00:13:25 UTC

svn commit: r1381777 - in /subversion/trunk/subversion/libsvn_subr: cache-membuffer.c cache_config.c

Author: stefan2
Date: Thu Sep  6 22:13:24 2012
New Revision: 1381777

URL: http://svn.apache.org/viewvc?rev=1381777&view=rev
Log:
Tune the membuffer cache code. Processing the key hash as
2x8 bytes instead of 16x1 bytes seems to produce better code.

Also, latest caches will contain relatively small items.
To still be able to fully use the cache memory, we need a
larger index with a lower rate of bucket overflows.

* subversion/libsvn_subr/cache_config.c
  (svn_cache__get_global_membuffer_cache):
   increase the relative size of the cache index

* subversion/libsvn_subr/cache-membuffer.c
  (GROUP_SIZE): double bucket ("group") size
  (KEY_SIZE): drop
  (GROUP_INIT_GRANULARITY): update docstring
  (entry_key_t): new key type to use
  (entry_t): use it here
  (get_group_index): adapt signature; simplify bucket selection
  (find_entry,
   membuffer_cache_set_internal,
   membuffer_cache_set,
   membuffer_cache_get_internal,
   membuffer_cache_get,
   membuffer_cache_get_partial_internal,
   membuffer_cache_get_partial,
   membuffer_cache_set_partial_internal,
   membuffer_cache_set_partial,
   svn_membuffer_cache_t): use the new key type

Modified:
    subversion/trunk/subversion/libsvn_subr/cache-membuffer.c
    subversion/trunk/subversion/libsvn_subr/cache_config.c

Modified: subversion/trunk/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/cache-membuffer.c?rev=1381777&r1=1381776&r2=1381777&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/trunk/subversion/libsvn_subr/cache-membuffer.c Thu Sep  6 22:13:24 2012
@@ -100,16 +100,12 @@
  * on their hash key.
  */
 
-/* A 4-way associative cache seems to be the best compromise between
+/* A 8-way associative cache seems to be a good compromise between
  * performance (worst-case lookups) and efficiency-loss due to collisions.
  *
  * This value may be changed to any positive integer.
  */
-#define GROUP_SIZE 4
-
-/* We use MD5 for digest size and speed (SHA1 is >2x slower, for instance).
- */
-#define KEY_SIZE APR_MD5_DIGESTSIZE
+#define GROUP_SIZE 8
 
 /* For more efficient copy operations, let'a align all data items properly.
  * Must be a power of 2.
@@ -124,9 +120,9 @@
 /* We don't mark the initialization status for every group but initialize
  * a number of groups at once. That will allow for a very small init flags
  * vector that is likely to fit into the CPU caches even for fairly large
- * caches. For instance, the default of 32 means 8x32 groups per byte, i.e.
- * 8 flags/byte x 32 groups/flag x 4 entries/group x 40 index bytes/entry
- * x 16 cache bytes/index byte = 1kB init vector / 640MB cache.
+ * membuffer caches. For instance, the default of 32 means 8x32 groups per
+ * byte, i.e. 8 flags/byte x 32 groups/flag x 8 entries/group x 40 index
+ * bytes/entry x 8 cache bytes/index byte = 1kB init vector / 640MB cache.
  */
 #define GROUP_INIT_GRANULARITY 32
 
@@ -293,6 +289,12 @@ static svn_error_t* assert_equal_tags(co
 
 #endif /* SVN_DEBUG_CACHE_MEMBUFFER */
 
+/* A 16 byte key type. We use that to identify cache entries.
+ * The notation as just two integer values will cause many compilers
+ * to create better code.
+ */
+typedef apr_uint64_t entry_key_t[2];
+
 /* A single dictionary entry. Since all entries will be allocated once
  * during cache creation, those entries might be either used or unused.
  * An entry is used if and only if it is contained in the doubly-linked
@@ -303,7 +305,7 @@ typedef struct entry_t
 {
   /* Identifying the data item. Only valid for used entries.
    */
-  unsigned char key [KEY_SIZE];
+  entry_key_t key;
 
   /* If NO_OFFSET, the entry is not in used. Otherwise, it is the offset
    * of the cached item's serialized data within the data buffer.
@@ -663,22 +665,11 @@ insert_entry(svn_membuffer_t *cache, ent
  */
 static apr_uint32_t
 get_group_index(svn_membuffer_t **cache,
-                const apr_uint32_t *key)
+                entry_key_t key)
 {
-  apr_uint32_t hash;
-
-  /* Get the group that *must* contain the entry. Fold the hash value
-   * just to be sure (it should not be necessary for perfect hashes).
-   */
-  hash = key[0];
-  hash = key[1] ^ ((hash >> 19) || (hash << 13));
-  hash = key[2] ^ ((hash >> 19) || (hash << 13));
-  hash = key[3] ^ ((hash >> 19) || (hash << 13));
-
   /* select the cache segment to use */
   *cache = &(*cache)[key[0] & ((*cache)->segment_count -1)];
-
-  return hash % (*cache)->group_count;
+  return key[0] % (*cache)->group_count;
 }
 
 /* Reduce the hit count of ENTRY and update the accumunated hit info
@@ -749,7 +740,7 @@ initialize_group(svn_membuffer_t *cache,
 static entry_t *
 find_entry(svn_membuffer_t *cache,
            apr_uint32_t group_index,
-           const unsigned char *to_find,
+           const apr_uint64_t to_find[2],
            svn_boolean_t find_empty)
 {
   entry_t *group;
@@ -770,7 +761,8 @@ find_entry(svn_membuffer_t *cache,
           entry = group;
 
           /* initialize entry for the new key */
-          memcpy(entry->key, to_find, KEY_SIZE);
+          entry->key[0] = to_find[0];
+          entry->key[1] = to_find[1];
         }
 
       return entry;
@@ -779,8 +771,9 @@ find_entry(svn_membuffer_t *cache,
   /* try to find the matching entry
    */
   for (i = 0; i < GROUP_SIZE; ++i)
-    if (group[i].offset != NO_OFFSET &&
-        !memcmp(to_find, group[i].key, KEY_SIZE))
+    if (   group[i].offset != NO_OFFSET
+        && to_find[0] == group[i].key[0]
+        && to_find[1] == group[i].key[1])
       {
         /* found it
          */
@@ -825,7 +818,8 @@ find_entry(svn_membuffer_t *cache,
         }
 
       /* initialize entry for the new key */
-      memcpy(entry->key, to_find, KEY_SIZE);
+      entry->key[0] = to_find[0];
+      entry->key[1] = to_find[1];
     }
 
   return entry;
@@ -1161,7 +1155,7 @@ svn_cache__membuffer_cache_create(svn_me
  */
 static svn_error_t *
 membuffer_cache_set_internal(svn_membuffer_t *cache,
-                             const unsigned char *to_find,
+                             entry_key_t to_find,
                              apr_uint32_t group_index,
                              char *buffer,
                              apr_size_t size,
@@ -1221,7 +1215,7 @@ membuffer_cache_set_internal(svn_membuff
  */
 static svn_error_t *
 membuffer_cache_set(svn_membuffer_t *cache,
-                    const void *key,
+                    entry_key_t key,
                     void *item,
                     svn_cache__serialize_func_t serializer,
                     DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1265,7 +1259,7 @@ membuffer_cache_set(svn_membuffer_t *cac
 static svn_error_t *
 membuffer_cache_get_internal(svn_membuffer_t *cache,
                              apr_uint32_t group_index,
-                             const unsigned char *to_find,
+                             entry_key_t to_find,
                              char **buffer,
                              apr_size_t *item_size,
                              DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1325,7 +1319,7 @@ membuffer_cache_get_internal(svn_membuff
  */
 static svn_error_t *
 membuffer_cache_get(svn_membuffer_t *cache,
-                    const void *key,
+                    entry_key_t key,
                     void **item,
                     svn_cache__deserialize_func_t deserializer,
                     DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1372,7 +1366,7 @@ membuffer_cache_get(svn_membuffer_t *cac
 static svn_error_t *
 membuffer_cache_get_partial_internal(svn_membuffer_t *cache,
                                      apr_uint32_t group_index,
-                                     const unsigned char *to_find,
+                                     entry_key_t to_find,
                                      void **item,
                                      svn_boolean_t *found,
                                      svn_cache__partial_getter_func_t deserializer,
@@ -1431,7 +1425,7 @@ membuffer_cache_get_partial_internal(svn
  */
 static svn_error_t *
 membuffer_cache_get_partial(svn_membuffer_t *cache,
-                            const void *key,
+                            entry_key_t key,
                             void **item,
                             svn_boolean_t *found,
                             svn_cache__partial_getter_func_t deserializer,
@@ -1463,7 +1457,7 @@ membuffer_cache_get_partial(svn_membuffe
 static svn_error_t *
 membuffer_cache_set_partial_internal(svn_membuffer_t *cache,
                                      apr_uint32_t group_index,
-                                     const unsigned char *to_find,
+                                     entry_key_t to_find,
                                      svn_cache__partial_setter_func_t func,
                                      void *baton,
                                      DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1563,7 +1557,7 @@ membuffer_cache_set_partial_internal(svn
  */
 static svn_error_t *
 membuffer_cache_set_partial(svn_membuffer_t *cache,
-                            const void *key,
+                            entry_key_t key,
                             svn_cache__partial_setter_func_t func,
                             void *baton,
                             DEBUG_CACHE_MEMBUFFER_TAG_ARG
@@ -1619,7 +1613,7 @@ typedef struct svn_membuffer_cache_t
    * This makes (very likely) our keys different from all keys used
    * by other svn_membuffer_cache_t instances.
    */
-  apr_uint64_t prefix [APR_MD5_DIGESTSIZE / sizeof(apr_uint64_t)];
+  entry_key_t prefix;
 
   /* A copy of the unmodified prefix. It is being used as a user-visible
    * ID for this cache instance.
@@ -1633,7 +1627,7 @@ typedef struct svn_membuffer_cache_t
 
   /* Temporary buffer containing the hash key for the current access
    */
-  apr_uint64_t combined_key [APR_MD5_DIGESTSIZE / sizeof(apr_uint64_t)];
+  entry_key_t combined_key;
 
   /* a pool for temporary allocations during get() and set()
    */

Modified: subversion/trunk/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/cache_config.c?rev=1381777&r1=1381776&r2=1381777&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/trunk/subversion/libsvn_subr/cache_config.c Thu Sep  6 22:13:24 2012
@@ -118,7 +118,7 @@ svn_cache__get_global_membuffer_cache(vo
       err = svn_cache__membuffer_cache_create(
           &new_cache,
           (apr_size_t)cache_size,
-          (apr_size_t)(cache_size / 16),
+          (apr_size_t)(cache_size / 10),
           ! svn_cache_config_get()->single_threaded,
           pool);