Rewrite statistics system.
authorRobert Haas <[email protected]>
Thu, 2 Aug 2012 14:01:20 +0000 (14:01 +0000)
committerRobert Haas <[email protected]>
Thu, 2 Aug 2012 14:01:20 +0000 (14:01 +0000)
contrib/hashtest/hashtest.c
src/backend/utils/hash/chash.c
src/include/utils/chash.h

index 440f1c5026d2e1f33c470bca206322c22338b781..554457df0e9f4e76591811cb32b2918c3f2a1784 100644 (file)
@@ -278,45 +278,20 @@ chash_collision_test(PG_FUNCTION_ARGS)
 Datum
 chash_write_stats_to_log(PG_FUNCTION_ARGS)
 {
-       StringInfoData buf;
-       CHashTableStats stats;
+       uint64  stats[CHS_NumberOfStatistics];
+       CHashStatisticsType i;
+       StringInfoData  buf;
 
-       CHashStatistics(chash, &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);
+       for (i = 0; i < CHS_NumberOfStatistics; ++i)
+       {
+               if (stats[i] == 0)
+                       continue;
+               appendStringInfo(&buf, UINT64_FORMAT " %s; ", stats[i],
+                                                CHashStatisticsNames[i]);
+       }
 
        if (buf.len > 1)
        {
index 4cb837183519bca95d405ce5bd0142348161cddb..5586ec5ac7520456b0ed0f0eaf13d10bc8c026c0 100644 (file)
@@ -162,7 +162,7 @@ typedef struct CHashTableData
         * unused.
         */
        uint32                  gc_next;                /* next garbage list to reclaim */
-       CHashTableStats stats;                  /* statistics */
+       uint64                  stats[CHS_NumberOfStatistics];  /* statistics */
 } CHashTableData;
 
 #define CHashTableGetRaw(table, offset) \
@@ -171,6 +171,8 @@ typedef struct CHashTableData
 #define CHashTableGetNode(table, ptr) \
        (AssertMacro(!CHashPtrIsInvalid(ptr)), \
         CHashTableGetRaw((table), CHashPtrGetOffset((ptr))))
+#define CHashTableIncrementStatistic(table, stat) \
+       ((table)->stats[(stat)]++)
 
 /*
  * Bucket scan.
@@ -183,6 +185,33 @@ typedef struct
        bool            found;
 } CHashScanResult;
 
+/* Human-readable statistics names. */
+char *CHashStatisticsNames[] = {
+       "searches",
+       "searches failed",
+       "inserts",
+       "inserts failed",
+       "inserts retried",
+       "deletions",
+       "deletions failed",
+       "deletions retried",
+       "scan expunges",
+       "scan expunges failed",
+       "scans restarted",
+       "cleanup scans",
+       "cleanup expunges",
+       "cleanup expunges failed",
+       "cleanups restarted",
+       "allocations failed",
+       "garbage enqueues retried",
+       "garbage dequeues failed",
+       "garbage collections",
+       "garbage collection spins",
+       "garbage collection fast reclaims",
+       "garbage collection reclaims retried",
+       "<end>"
+};
+
 /* Function prototypes. */
 static CHashPtr CHashAllocate(CHashTable table);
 static void CHashAddToGarbage(CHashTable table, uint32 bucket, CHashPtr c);
@@ -205,6 +234,9 @@ CHashBootstrap(CHashDescriptor *desc)
        CHashTable              table;
        uint32                  bucket_shift;
 
+       /* Sanity check. */
+       Assert(!strcmp(CHashStatisticsNames[CHS_NumberOfStatistics], "<end>"));
+
        /* Allocate table and copy descriptor. */
        table = MemoryContextAllocZero(TopMemoryContext, sizeof(CHashTableData));
        memcpy(&table->desc, desc, sizeof(CHashDescriptor)); 
@@ -260,6 +292,9 @@ CHashBootstrap(CHashDescriptor *desc)
        /* Each arena element must be MAXALIGN'd and include per-node space. */
        table->arena_stride = SizeOfCHashNode + MAXALIGN(desc->element_size);
 
+       /* Zero out statistics. */
+       memset(table->stats, 0, sizeof(uint64) * CHS_NumberOfStatistics);
+
        return table;
 }
 
@@ -388,6 +423,9 @@ CHashSearch(CHashTable table, void *entry)
        pg_memory_barrier();
        MyProc->hazard[0] = NULL;
 
+       CHashTableIncrementStatistic(table, CHS_Search);
+       if (!scan.found)
+               CHashTableIncrementStatistic(table, CHS_Search_Failed);
        return scan.found;
 }
 
@@ -461,7 +499,7 @@ retry:
                if (!__sync_bool_compare_and_swap(scan.pointer_to_target,
                                                                                  scan.target, new))
                {
-                       table->stats.s_insert_retry++;
+                       CHashTableIncrementStatistic(table, CHS_Insert_Retry);
                        goto retry;
                }
        }
@@ -485,8 +523,12 @@ retry:
         * element makes it back to the freelist is trying to allocate some
         * other node.
         */
+       CHashTableIncrementStatistic(table, CHS_Insert);
        if (scan.found)
+       {
+               CHashTableIncrementStatistic(table, CHS_Insert_Failed);
                CHashAddToGarbage(table, bucket, new);
+       }
 
        /* The insert succeeded if and only if no duplicate was found. */
        return !scan.found;
@@ -543,7 +585,7 @@ CHashDelete(CHashTable table, void *entry)
                                cleanup_scan = true;
                        break;
                }
-               table->stats.s_delete_retry++;
+               CHashTableIncrementStatistic(table, CHS_Delete_Retry);
        }
 
        /*
@@ -552,7 +594,7 @@ CHashDelete(CHashTable table, void *entry)
         */
        if (cleanup_scan)
        {
-               table->stats.s_cleanup_scan++;
+               CHashTableIncrementStatistic(table, CHS_Cleanup_Scan);
                CHashBucketCleanup(table, b, hashcode);
        }
 
@@ -562,6 +604,9 @@ CHashDelete(CHashTable table, void *entry)
        MyProc->hazard[0] = NULL;
 
        /* We're done. */
+       CHashTableIncrementStatistic(table, CHS_Delete);
+       if (!scan.found)
+               CHashTableIncrementStatistic(table, CHS_Delete_Failed);
        return scan.found;
 }
 
@@ -569,9 +614,9 @@ CHashDelete(CHashTable table, void *entry)
  * Provide backend-local statistics to caller.
  */
 void
-CHashStatistics(CHashTable table, CHashTableStats *stats)
+CHashStatistics(CHashTable table, uint64 *stats)
 {
-       memcpy(stats, &table->stats, sizeof(CHashTableStats));
+       memcpy(stats, &table->stats, sizeof(uint64) * CHS_NumberOfStatistics);
 }
 
 /*
@@ -653,7 +698,7 @@ zap:
                                 * all non-deleted items (and possibly some deleted items)
                                 * that were present at the time we began the scan.
                                 */
-                               table->stats.s_scan_expunge_ok++;
+                               CHashTableIncrementStatistic(table, CHS_Scan_Expunge);
                                CHashAddToGarbage(table, hashcode & table->bucket_mask,
                                                                  target);
                                target = CHashPtrUnmark(next);
@@ -680,11 +725,11 @@ zap:
                                 * have to be pretty unlucky to have it happen even twice in
                                 * a row.
                                 */
-                               table->stats.s_scan_expunge_fail++;
+                               CHashTableIncrementStatistic(table, CHS_Scan_Expunge_Fail);
                                target = *pointer_to_target;
                                if (CHashPtrIsMarked(target))
                                {
-                                       table->stats.s_scan_restart++;
+                                       CHashTableIncrementStatistic(table, CHS_Scan_Restart);
                                        goto retry;
                                }
                        }
@@ -797,7 +842,7 @@ retry:
                                                                                         CHashPtrUnmark(next)))
                        {
                                /* We removed the item. */
-                               table->stats.s_cleanup_expunge_ok++;
+                               CHashTableIncrementStatistic(table, CHS_Cleanup_Expunge);
                                CHashAddToGarbage(table, hashcode & table->bucket_mask,
                                                                  target);
                                target = CHashPtrUnmark(next);
@@ -805,11 +850,11 @@ retry:
                        else
                        {
                                /* Someone else removed the item first. */
-                               table->stats.s_cleanup_expunge_fail++;
+                               CHashTableIncrementStatistic(table, CHS_Cleanup_Expunge_Fail);
                                target = *pointer_to_target;
                                if (CHashPtrIsMarked(target))
                                {
-                                       table->stats.s_cleanup_restart++;
+                                       CHashTableIncrementStatistic(table, CHS_Cleanup_Restart);
                                        goto retry;
                                }
                        }
@@ -891,7 +936,7 @@ CHashAllocate(CHashTable table)
                        pg_read_barrier_depends();
                        if (__sync_bool_compare_and_swap(b, new, n->un.gcnext))
                                return new;
-                       table->stats.s_allocate_pop_fail++;
+                       CHashTableIncrementStatistic(table, CHS_Allocate_Fail);
                        new = *b;
                }
 
@@ -902,7 +947,7 @@ CHashAllocate(CHashTable table)
                if (CHashPtrIsInvalid(garbage))
                        ;
                else if (!__sync_bool_compare_and_swap(b, garbage, InvalidCHashPtr))
-                       table->stats.s_gc_pop_fail++;
+                       CHashTableIncrementStatistic(table, CHS_Garbage_Dequeue_Fail);
                else
                {
                        uint32          i;
@@ -929,16 +974,22 @@ CHashAllocate(CHashTable table)
                         * might want to eventually enter a longer sleep here, or PANIC,
                         * but it's not clear exactly how to calibrate that.
                         */
+                       CHashTableIncrementStatistic(table, CHS_GC);
                        MyProc->hazard[0] = NULL;
                        for (i = 0; i < ProcGlobal->allProcCount; i++)
                        {
                                volatile PGPROC *proc = &ProcGlobal->allProcs[i];
                                void       *hazard;
 
-                               do
+                               hazard = proc->hazard[0];
+                               if (hazard == b || hazard == fh)
                                {
-                                       hazard = proc->hazard[0];
-                               } while (hazard == b || hazard == fh);
+                                       CHashTableIncrementStatistic(table, CHS_GC_Spin);
+                                       do
+                                       {
+                                               hazard = proc->hazard[0];
+                                       } while (hazard == b || hazard == fh);
+                               }
                        }
 
                        /* Remove one item from list to satisfy current allocation. */
@@ -953,8 +1004,11 @@ CHashAllocate(CHashTable table)
                         * we needn't update the list any further; otherwise, we've got
                         * to adjust the next-pointer in the last of the reclaimed nodes.
                         */
-                       if (!CHashPtrIsInvalid(fhead)
-                               && !__sync_bool_compare_and_swap(fh, InvalidCHashPtr, fhead))
+                       if (CHashPtrIsInvalid(fhead))
+                               ;
+                       else if (__sync_bool_compare_and_swap(fh, InvalidCHashPtr, fhead))
+                               CHashTableIncrementStatistic(table, CHS_GC_Reclaim_Fast);
+                       else
                        {
                                CHashPtr        fcurrent;
                                CHashPtr        fnext;
@@ -978,7 +1032,7 @@ CHashAllocate(CHashTable table)
                                        n->un.gcnext = oldhead;
                                        if (__sync_bool_compare_and_swap(fh, oldhead, fhead))
                                                break;
-                                       table->stats.s_gc_reclaim_retry++;
+                                       CHashTableIncrementStatistic(table, CHS_GC_Reclaim_Retry);
                                }
                        }
 
@@ -1019,6 +1073,6 @@ CHashAddToGarbage(CHashTable table, uint32 bucket, CHashPtr c)
                n->un.gcnext = g;
                if (__sync_bool_compare_and_swap(garbage, g, c))
                        break;
-               table->stats.s_garbage_retry++;
+               CHashTableIncrementStatistic(table, CHS_Garbage_Enqueue_Retry);
        }
 }
index 703aa3d7de5572a713f8600dc817d994566ab22d..8ff7e6403967bf2716c04a949d62fd8b7dca4acd 100644 (file)
@@ -23,23 +23,35 @@ typedef struct
 } CHashDescriptor;
 
 /* Concurrent hash table statistics. */
-typedef struct
+typedef enum
 {
-       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;
+       CHS_Search,                                     /* search */
+       CHS_Search_Failed,                      /* search failed (no such key) */
+       CHS_Insert,                                     /* insert */
+       CHS_Insert_Failed,                      /* insert failed (duplicate key) */
+       CHS_Insert_Retry,                       /* insert retried (concurrent update) */
+       CHS_Delete,                                     /* delete */
+       CHS_Delete_Failed,                      /* delete failed (no such key) */
+       CHS_Delete_Retry,                       /* delete retried (concurrent update) */
+       CHS_Scan_Expunge,                       /* scan expunged deleted item */
+       CHS_Scan_Expunge_Fail,          /* scan failed to expunge */
+       CHS_Scan_Restart,                       /* concurrent deletes forced a scan restart */
+       CHS_Cleanup_Scan,                       /* concurrent update forced a cleanup scan */
+       CHS_Cleanup_Expunge,            /* cleanup scan expunged an item */
+       CHS_Cleanup_Expunge_Fail,       /* cleanup scan failed to expunge */
+       CHS_Cleanup_Restart,            /* concurrent deletes forced cleanup restart */
+       CHS_Allocate_Fail,                      /* allocation failed to pop freelist */
+       CHS_Garbage_Enqueue_Retry,      /* enqueue on garbage list retried */
+       CHS_Garbage_Dequeue_Fail,       /* dequeue of garbage failed */
+       CHS_GC,                                         /* garbage collection cycle */
+       CHS_GC_Spin,                            /* GC spun waiting for concurrent process */
+       CHS_GC_Reclaim_Fast,            /* GC put garbage on freelist via fast path */
+       CHS_GC_Reclaim_Retry,           /* enqueue of garbage on freelist retried */
+       CHS_NumberOfStatistics          /* number of statistics */
+} CHashStatisticsType;
+
+/* Human-readable names for statistics. */
+extern char *CHashStatisticsNames[];
 
 /* Opaque handle for a concurrent hash table. */
 struct CHashTableData;
@@ -54,6 +66,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);
+extern void CHashStatistics(CHashTable table, uint64 *stats);
 
 #endif   /* CHASH_H */