]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add highwater counters
authorAlessio Podda <alessio@isc.org>
Tue, 9 Sep 2025 13:46:45 +0000 (15:46 +0200)
committerAlessio Podda <alessio@isc.org>
Wed, 24 Sep 2025 15:01:49 +0000 (17:01 +0200)
lib/dns/stats.c
lib/isc/include/isc/statsmulti.h
lib/isc/statsmulti.c

index ba80894fe88d599ed5ee35017102775a7dc88fdd..2a77b01c4e8e75426d65af89386057981cd4a8af 100644 (file)
@@ -197,7 +197,7 @@ dns_rdatatypestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) {
         * Create rdtype statistics using statsmulti for better multithreading performance.
         * We need RDTYPECOUNTER_MAXVAL + 1 counters (0x0602 + 1 = 1539 counters).
         */
-       isc_statsmulti_create(mctx, statsp, RDTYPECOUNTER_MAXVAL + 1);
+       isc_statsmulti_create(mctx, statsp, RDTYPECOUNTER_MAXVAL + 1, 0);
 }
 
 void
index f408105c7f34c816db87ac7b1973246dbae050bf..e539a945445371cb1f36bdc9e7b3295b06e9cf24 100644 (file)
@@ -32,10 +32,11 @@ typedef struct isc_statsmulti isc_statsmulti_t; /*%< Statistics Multi */
 typedef void (*isc_statsmulti_dumper_t)(isc_statscounter_t, uint64_t, void *);
 
 void
-isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, int ncounters);
+isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, int n_additive, int n_max);
 /*%<
- * Create a statistics counter structure of general type.  It counts a general
- * set of counters indexed by an ID between 0 and ncounters -1.
+ * Create a statistics counter structure with both additive and highwater counters.
+ * Counters [0, n_additive) are additive (sum across threads).
+ * Counters [n_additive, n_additive + n_max) are highwater (maximum across threads).
  *
  * Requires:
  *\li  'mctx' must be a valid memory context.
@@ -116,4 +117,28 @@ isc_statsmulti_clear(isc_statsmulti_t *stats);
  *
  * Requires:
  *\li  'stats' is a valid isc_statsmulti_t.
+ */
+
+void
+isc_statsmulti_update_if_greater(isc_statsmulti_t *stats, isc_statscounter_t counter, isc_statscounter_t value);
+/*%<
+ * Update a highwater counter if the provided value is greater than the current per-thread value.
+ * Only works on counters in the range [n_additive, n_additive + n_max).
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_statsmulti_t.
+ *
+ *\li  counter is in the highwater range for the stats specified on creation.
+ */
+
+isc_statscounter_t
+isc_statsmulti_get_highwater(isc_statsmulti_t *stats, isc_statscounter_t counter);
+/*%<
+ * Returns the maximum value across all threads for a highwater counter.
+ * Only works on counters in the range [n_additive, n_additive + n_max).
+ *
+ * Requires:
+ *\li  'stats' is a valid isc_statsmulti_t.
+ *
+ *\li  counter is in the highwater range for the stats specified on creation.
  */
\ No newline at end of file
index 22279adc24fa87e989126a696ccb8a3651b30ab6..cf29fb8c1b8a0f6013acb4fed97a175f5411cfbc 100644 (file)
@@ -41,15 +41,18 @@ struct isc_statsmulti {
        isc_mem_t *mctx;
        isc_refcount_t references;
        int ncounters;
+       int n_additive;
+       int n_max;
        int per_thread_capacity;
        int num_threads;
        isc_atomic_statscounter_t *counters;
 };
 
 void
-isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, int ncounters) {
+isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, int n_additive, int n_max) {
        REQUIRE(statsp != NULL && *statsp == NULL);
 
+       int ncounters = n_additive + n_max;
        isc_statsmulti_t *stats = isc_mem_get(mctx, sizeof(*stats));
        
        size_t counters_size = sizeof(isc_atomic_statscounter_t) * ncounters;
@@ -67,6 +70,8 @@ isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, int ncounters)
        stats->mctx = NULL;
        isc_mem_attach(mctx, &stats->mctx);
        stats->ncounters = ncounters;
+       stats->n_additive = n_additive;
+       stats->n_max = n_max;
        stats->per_thread_capacity = per_thread_capacity;
        stats->num_threads = num_threads;
        stats->magic = ISC_STATSMULTI_MAGIC;
@@ -102,7 +107,7 @@ isc_statsmulti_detach(isc_statsmulti_t **statsp) {
 isc_statscounter_t
 isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) {
        REQUIRE(ISC_STATSMULTI_VALID(stats));
-       REQUIRE(counter < stats->ncounters);
+       REQUIRE(counter < stats->n_additive);
 
        isc_tid_t tid = isc_tid();
        int thread_id = ISC_MAX(tid, 0);
@@ -116,7 +121,7 @@ isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) {
 void
 isc_statsmulti_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) {
        REQUIRE(ISC_STATSMULTI_VALID(stats));
-       REQUIRE(counter < stats->ncounters);
+       REQUIRE(counter < stats->n_additive);
 
        isc_tid_t tid = isc_tid();
        int thread_id = ISC_MAX(tid, 0);
@@ -151,7 +156,7 @@ isc_statsmulti_dump(isc_statsmulti_t *stats, isc_statsmulti_dumper_t dump_fn, vo
 isc_statscounter_t
 isc_statsmulti_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter) {
        REQUIRE(ISC_STATSMULTI_VALID(stats));
-       REQUIRE(counter < stats->ncounters);
+       REQUIRE(counter < stats->n_additive);
 
        isc_statscounter_t total = 0;
        /* Accumulate across all threads */
@@ -171,3 +176,44 @@ isc_statsmulti_clear(isc_statsmulti_t *stats) {
                atomic_store_relaxed(&stats->counters[i], 0);
        }
 }
+
+void
+isc_statsmulti_update_if_greater(isc_statsmulti_t *stats, isc_statscounter_t counter, isc_statscounter_t value) {
+       REQUIRE(ISC_STATSMULTI_VALID(stats));
+       REQUIRE(counter >= stats->n_additive);
+       REQUIRE(counter < stats->ncounters);
+
+       isc_tid_t tid = isc_tid();
+       int thread_id = ISC_MAX(tid, 0);
+       if (thread_id >= stats->num_threads) {
+               thread_id = 0;
+       }
+       int index = thread_id * stats->per_thread_capacity + counter;
+       
+       /* Atomically update if the new value is greater than current */
+       isc_statscounter_t current = atomic_load_relaxed(&stats->counters[index]);
+       while (value > current) {
+               if (atomic_compare_exchange_weak_relaxed(&stats->counters[index], &current, value)) {
+                       break;
+               }
+               /* current was updated by the failed compare_exchange, try again */
+       }
+}
+
+isc_statscounter_t
+isc_statsmulti_get_highwater(isc_statsmulti_t *stats, isc_statscounter_t counter) {
+       REQUIRE(ISC_STATSMULTI_VALID(stats));
+       REQUIRE(counter >= stats->n_additive);
+       REQUIRE(counter < stats->ncounters);
+
+       isc_statscounter_t max_value = 0;
+       /* Find maximum value across all threads */
+       for (int thread = 0; thread < stats->num_threads; thread++) {
+               int index = thread * stats->per_thread_capacity + counter;
+               isc_statscounter_t value = atomic_load_acquire(&stats->counters[index]);
+               if (value > max_value) {
+                       max_value = value;
+               }
+       }
+       return max_value;
+}