From a4ef2ab9c43d9095764d0601440ee840e6cba313 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 30 Jul 2012 17:34:15 +0000 Subject: [PATCH] Better statistics stuff. --- contrib/hashtest/hashtest--1.0.sql | 5 +++ contrib/hashtest/hashtest.c | 55 ++++++++++++++++++++++++++++++ src/backend/utils/hash/chash.c | 48 ++++++++++++-------------- src/include/utils/chash.h | 20 +++++++++++ 4 files changed, 102 insertions(+), 26 deletions(-) diff --git a/contrib/hashtest/hashtest--1.0.sql b/contrib/hashtest/hashtest--1.0.sql index 5d37927618..e1dddfcf9b 100644 --- a/contrib/hashtest/hashtest--1.0.sql +++ b/contrib/hashtest/hashtest--1.0.sql @@ -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' diff --git a/contrib/hashtest/hashtest.c b/contrib/hashtest/hashtest.c index 16ac27a194..bd716c7f2c 100644 --- a/contrib/hashtest/hashtest.c +++ b/contrib/hashtest/hashtest.c @@ -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) { diff --git a/src/backend/utils/hash/chash.c b/src/backend/utils/hash/chash.c index 555dd41a51..06c2a1d988 100644 --- a/src/backend/utils/hash/chash.c +++ b/src/backend/utils/hash/chash.c @@ -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; } } diff --git a/src/include/utils/chash.h b/src/include/utils/chash.h index e17a45aca4..b356915115 100644 --- a/src/include/utils/chash.h +++ b/src/include/utils/chash.h @@ -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 */ -- 2.39.5