Better statistics stuff.
authorRobert Haas <[email protected]>
Mon, 30 Jul 2012 17:34:15 +0000 (17:34 +0000)
committerRobert Haas <[email protected]>
Mon, 30 Jul 2012 17:34:15 +0000 (17:34 +0000)
contrib/hashtest/hashtest--1.0.sql
contrib/hashtest/hashtest.c
src/backend/utils/hash/chash.c
src/include/utils/chash.h

index 5d37927618b1823f27f8b67a244019e025fa5a0e..e1dddfcf9bff7bd4a45ab484b0ab24adb88a6f5a 100644 (file)
@@ -26,6 +26,11 @@ RETURNS void
 AS 'MODULE_PATHNAME', 'chash_collision_test'
 LANGUAGE C;
 
+CREATE FUNCTION chash_write_stats_to_log()
+RETURNS void
+AS 'MODULE_PATHNAME', 'chash_write_stats_to_log'
+LANGUAGE C;
+
 CREATE FUNCTION dynahash_insert_test()
 RETURNS void
 AS 'MODULE_PATHNAME', 'dynahash_insert_test'
index 16ac27a194cbc0d5d4967f0ff39bd6bf9876e30f..bd716c7f2ca9c45e928af739dcf396bdb2315c19 100644 (file)
@@ -19,6 +19,7 @@ Datum         chash_search_test(PG_FUNCTION_ARGS);
 Datum          chash_delete_test(PG_FUNCTION_ARGS);
 Datum          chash_concurrent_test(PG_FUNCTION_ARGS);
 Datum          chash_collision_test(PG_FUNCTION_ARGS);
+Datum          chash_write_stats_to_log(PG_FUNCTION_ARGS);
 Datum          dynahash_insert_test(PG_FUNCTION_ARGS);
 Datum          dynahash_search_test(PG_FUNCTION_ARGS);
 Datum          dynahash_delete_test(PG_FUNCTION_ARGS);
@@ -271,6 +272,60 @@ chash_collision_test(PG_FUNCTION_ARGS)
        PG_RETURN_VOID();
 }
 
+Datum
+chash_write_stats_to_log(PG_FUNCTION_ARGS)
+{
+       StringInfoData buf;
+       CHashTableStats stats;
+
+       CHashStatistics(chash, &stats);
+       initStringInfo(&buf);
+
+       if (stats.s_insert_retry)
+               appendStringInfo(&buf, UINT64_FORMAT " inserts retried; ",
+                                                stats.s_insert_retry);
+       if (stats.s_delete_retry)
+               appendStringInfo(&buf, UINT64_FORMAT " deletes retried; ",
+                                                stats.s_delete_retry);
+       if (stats.s_cleanup_scan)
+               appendStringInfo(&buf, UINT64_FORMAT " cleanup scans; ",
+                                                stats.s_delete_retry);
+       if (stats.s_scan_expunge_ok)
+               appendStringInfo(&buf, UINT64_FORMAT " scan expunges ok; ",
+                                                stats.s_scan_expunge_ok);
+       if (stats.s_scan_expunge_fail)
+               appendStringInfo(&buf, UINT64_FORMAT " scan expunges failed; ",
+                                                stats.s_scan_expunge_fail);
+       if (stats.s_scan_restart)
+               appendStringInfo(&buf, UINT64_FORMAT " scans restarted; ",
+                                                stats.s_scan_restart);
+       if (stats.s_allocate_pop_fail)
+               appendStringInfo(&buf, UINT64_FORMAT " allocation pops failed; ",
+                                                stats.s_allocate_pop_fail);
+       if (stats.s_gc_pop_fail)
+               appendStringInfo(&buf, UINT64_FORMAT " GC pops failed; ",
+                                                stats.s_gc_pop_fail);
+       if (stats.s_gc_reclaim_retry)
+               appendStringInfo(&buf, UINT64_FORMAT " GC reclaims retried; ",
+                                                stats.s_gc_reclaim_retry);
+       if (stats.s_garbage_retry)
+               appendStringInfo(&buf, UINT64_FORMAT " garbage enqueues retried; ",
+                                                stats.s_garbage_retry);
+       if (stats.s_free_retry)
+               appendStringInfo(&buf, UINT64_FORMAT " immediate frees retried; ",
+                                                stats.s_free_retry);
+
+       if (buf.len > 1)
+       {
+               buf.data[buf.len-2] = '\0';
+               elog(LOG, "chash statistics: %s", buf.data);
+       }
+       else
+               elog(LOG, "chash statistics: nothing to report");
+
+       PG_RETURN_VOID();
+}
+
 static bool
 dynahash_insert(uint32 key, uint32 val)
 {
index 555dd41a519ac23b057f05339c8794bea712f11a..06c2a1d988a9731a7cd61286899b8c5fbaa1f920 100644 (file)
@@ -162,20 +162,7 @@ typedef struct CHashTableData
         * unused.
         */
        uint32                  gc_next;                /* next garbage list to reclaim */
-       uint64                  s_insert_retry; /* insert point concurrently updated */
-       uint64                  s_delete_retry; /* delete point concurrently updated */
-       uint64                  s_cleanup_scan; /* expunge-after-delete failed */
-       uint64                  s_scan_expunge_ok;              /* scan did expunge */
-       uint64                  s_scan_expunge_fail;    /* expunge failed */
-       uint64                  s_scan_restart;                 /* scan restarted */
-       uint64                  s_cleanup_expunge_ok;   /* cleanup scan did expunge */
-       uint64                  s_cleanup_expunge_fail; /* cleanup scan expunge failed */
-       uint64                  s_cleanup_restart;              /* cleanup scan restarted */
-       uint64                  s_allocate_pop_fail;    /* freelist pop failed */
-       uint64                  s_gc_pop_fail;          /* garbage list pop failed */
-       uint64                  s_gc_reclaim_retry;     /* failed to return GC'd nodes */
-       uint64                  s_garbage_retry;        /* failed to enqueue garbage */
-       uint64                  s_free_retry;           /* failed to perform immediate free */
+       CHashTableStats stats;                  /* statistics */
 } CHashTableData;
 
 #define CHashTableGetRaw(table, offset) \
@@ -489,7 +476,7 @@ retry:
                if (!__sync_bool_compare_and_swap(scan.pointer_to_target,
                                                                                  scan.target, new))
                {
-                       table->s_insert_retry++;
+                       table->stats.s_insert_retry++;
                        goto retry;
                }
        }
@@ -553,7 +540,7 @@ CHashDelete(CHashTable table, void *entry)
                                cleanup_scan = true;
                        break;
                }
-               table->s_delete_retry++;
+               table->stats.s_delete_retry++;
        }
 
        /*
@@ -562,7 +549,7 @@ CHashDelete(CHashTable table, void *entry)
         */
        if (cleanup_scan)
        {
-               table->s_cleanup_scan++;
+               table->stats.s_cleanup_scan++;
                CHashBucketCleanup(table, &table->bucket[bucket], hashcode);
        }
 
@@ -573,6 +560,15 @@ CHashDelete(CHashTable table, void *entry)
        return scan.found;
 }
 
+/*
+ * Provide backend-local statistics to caller.
+ */
+void
+CHashStatistics(CHashTable table, CHashTableStats *stats)
+{
+       memcpy(stats, &table->stats, sizeof(CHashTableStats));
+}
+
 /*
  * Scan one bucket of a concurrent hash table, storing the results in a
  * CHashResult object provided by the caller.
@@ -652,7 +648,7 @@ zap:
                                 * all non-deleted items (and possibly some deleted items)
                                 * that were present at the time we began the scan.
                                 */
-                               table->s_scan_expunge_ok++;
+                               table->stats.s_scan_expunge_ok++;
                                CHashAddToGarbage(table, hashcode & table->bucket_mask,
                                                                  target);
                                target = CHashPtrUnmark(next);
@@ -679,11 +675,11 @@ zap:
                                 * have to be pretty unlucky to have it happen even twice in
                                 * a row.
                                 */
-                               table->s_scan_expunge_fail++;
+                               table->stats.s_scan_expunge_fail++;
                                target = *pointer_to_target;
                                if (CHashPtrIsMarked(target))
                                {
-                                       table->s_scan_restart++;
+                                       table->stats.s_scan_restart++;
                                        goto retry;
                                }
                        }
@@ -796,7 +792,7 @@ retry:
                                                                                         CHashPtrUnmark(next)))
                        {
                                /* We removed the item. */
-                               table->s_cleanup_expunge_ok++;
+                               table->stats.s_cleanup_expunge_ok++;
                                CHashAddToGarbage(table, hashcode & table->bucket_mask,
                                                                  target);
                                target = CHashPtrUnmark(next);
@@ -870,7 +866,7 @@ CHashAllocate(CHashTable table)
                        pg_read_barrier_depends();
                        if (__sync_bool_compare_and_swap(b, new, n->un.gcnext))
                                return new;
-                       table->s_allocate_pop_fail++;
+                       table->stats.s_allocate_pop_fail++;
                }
 
                /* If next garbage list is non-empty, empty it via compare-and-swap. */
@@ -880,7 +876,7 @@ CHashAllocate(CHashTable table)
                if (CHashPtrIsInvalid(garbage))
                        ;
                else if (!__sync_bool_compare_and_swap(b, garbage, InvalidCHashPtr))
-                       ++table->s_gc_pop_fail;
+                       ++table->stats.s_gc_pop_fail;
                else
                {
                        uint64          chash_bucket;
@@ -940,7 +936,7 @@ CHashAllocate(CHashTable table)
                                        n->un.gcnext = oldhead;
                                        if (__sync_bool_compare_and_swap(b, oldhead, fhead))
                                                break;
-                                       ++table->s_gc_reclaim_retry;
+                                       ++table->stats.s_gc_reclaim_retry;
                                }
                        }
 
@@ -981,7 +977,7 @@ CHashAddToGarbage(CHashTable table, uint32 bucket, CHashPtr c)
                n->un.gcnext = g;
                if (__sync_bool_compare_and_swap(garbage, g, c))
                        break;
-               ++table->s_garbage_retry;
+               ++table->stats.s_garbage_retry;
        }
 }
 
@@ -1011,6 +1007,6 @@ CHashImmediateFree(CHashTable table, CHashPtr c)
                n->un.gcnext = f;
                if (__sync_bool_compare_and_swap(free, f, c))
                        break;
-               ++table->s_free_retry;
+               ++table->stats.s_free_retry;
        }
 }
index e17a45aca41bcfd25885800aae0ed335b79b9670..b356915115f6946e47e0f888a2683a58ef8c9689 100644 (file)
@@ -23,6 +23,25 @@ typedef struct
        uint16          key_size;               /* size of each key */
 } CHashDescriptor;
 
+/* Concurrent hash table statistics. */
+typedef struct
+{
+       uint64          s_insert_retry;                 /* insert point concurrently updated */
+       uint64          s_delete_retry;                 /* delete point concurrently updated */
+       uint64          s_cleanup_scan;                 /* expunge-after-delete failed */
+       uint64          s_scan_expunge_ok;              /* scan did expunge */
+       uint64          s_scan_expunge_fail;    /* expunge failed */
+       uint64          s_scan_restart;                 /* scan restarted */
+       uint64          s_cleanup_expunge_ok;   /* cleanup scan did expunge */
+       uint64          s_cleanup_expunge_fail; /* cleanup scan expunge failed */
+       uint64          s_cleanup_restart;              /* cleanup scan restarted */
+       uint64          s_allocate_pop_fail;    /* freelist pop failed */
+       uint64          s_gc_pop_fail;                  /* garbage list pop failed */
+       uint64          s_gc_reclaim_retry;             /* failed to return GC'd nodes */
+       uint64          s_garbage_retry;                /* failed to enqueue garbage */
+       uint64          s_free_retry;                   /* failed to perform immediate free */
+} CHashTableStats;
+
 /* Opaque handle for a concurrent hash table. */
 struct CHashTableData;
 typedef struct CHashTableData *CHashTable;
@@ -36,5 +55,6 @@ extern CHashTable CHashInitialize(CHashTable table, CHashDescriptor *desc);
 extern bool CHashInsert(CHashTable table, void *entry);
 extern bool CHashDelete(CHashTable table, void *key);
 extern bool CHashSearch(CHashTable table, void *entry);
+extern void CHashStatistics(CHashTable table, CHashTableStats *stats);
 
 #endif   /* CHASH_H */