Home | History | Annotate | Line # | Download | only in isc
stats.c revision 1.4.2.3
      1 /*	$NetBSD: stats.c,v 1.4.2.3 2020/04/13 08:02:58 martin Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 
     15 /*! \file */
     16 
     17 #include <config.h>
     18 
     19 #include <inttypes.h>
     20 #include <string.h>
     21 
     22 #include <isc/atomic.h>
     23 #include <isc/buffer.h>
     24 #include <isc/magic.h>
     25 #include <isc/mem.h>
     26 #include <isc/platform.h>
     27 #include <isc/print.h>
     28 #include <isc/refcount.h>
     29 #include <isc/stats.h>
     30 #include <isc/util.h>
     31 
     32 #define ISC_STATS_MAGIC			ISC_MAGIC('S', 't', 'a', 't')
     33 #define ISC_STATS_VALID(x)		ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
     34 
     35 #if (defined(_WIN32) && !defined(_WIN64)) || !defined(_LP64)
     36 	typedef atomic_int_fast32_t isc__atomic_statcounter_t;
     37 #else
     38 	typedef atomic_int_fast64_t isc__atomic_statcounter_t;
     39 #endif
     40 
     41 struct isc_stats {
     42 	unsigned int			magic;
     43 	isc_mem_t			*mctx;
     44 	isc_refcount_t			refs;
     45 	int				ncounters;
     46 	isc__atomic_statcounter_t	*counters;
     47 };
     48 
     49 static isc_result_t
     50 create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
     51 	isc_stats_t *stats;
     52 	size_t counters_alloc_size;
     53 
     54 	REQUIRE(statsp != NULL && *statsp == NULL);
     55 
     56 	stats = isc_mem_get(mctx, sizeof(*stats));
     57 	counters_alloc_size = sizeof(isc__atomic_statcounter_t) * ncounters;
     58 	stats->counters = isc_mem_get(mctx, counters_alloc_size);
     59 	isc_refcount_init(&stats->refs, 1);
     60 	memset(stats->counters, 0, counters_alloc_size);
     61 	stats->mctx = NULL;
     62 	isc_mem_attach(mctx, &stats->mctx);
     63 	stats->ncounters = ncounters;
     64 	stats->magic = ISC_STATS_MAGIC;
     65 	*statsp = stats;
     66 
     67 	return (ISC_R_SUCCESS);
     68 }
     69 
     70 void
     71 isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) {
     72 	REQUIRE(ISC_STATS_VALID(stats));
     73 	REQUIRE(statsp != NULL && *statsp == NULL);
     74 
     75 	isc_refcount_increment(&stats->refs);
     76 	*statsp = stats;
     77 }
     78 
     79 void
     80 isc_stats_detach(isc_stats_t **statsp) {
     81 	isc_stats_t *stats;
     82 
     83 	REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp));
     84 
     85 	stats = *statsp;
     86 	*statsp = NULL;
     87 
     88 	if (isc_refcount_decrement(&stats->refs) == 1) {
     89 		isc_mem_put(stats->mctx, stats->counters,
     90 			    sizeof(isc__atomic_statcounter_t) *
     91 				stats->ncounters);
     92 		isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
     93 	}
     94 }
     95 
     96 int
     97 isc_stats_ncounters(isc_stats_t *stats) {
     98 	REQUIRE(ISC_STATS_VALID(stats));
     99 
    100 	return (stats->ncounters);
    101 }
    102 
    103 isc_result_t
    104 isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) {
    105 	REQUIRE(statsp != NULL && *statsp == NULL);
    106 
    107 	return (create_stats(mctx, ncounters, statsp));
    108 }
    109 
    110 void
    111 isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
    112 	REQUIRE(ISC_STATS_VALID(stats));
    113 	REQUIRE(counter < stats->ncounters);
    114 
    115 	atomic_fetch_add_explicit(&stats->counters[counter], 1,
    116 				  memory_order_relaxed);
    117 }
    118 
    119 void
    120 isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
    121 	REQUIRE(ISC_STATS_VALID(stats));
    122 	REQUIRE(counter < stats->ncounters);
    123 
    124 	atomic_fetch_sub_explicit(&stats->counters[counter], 1,
    125 				  memory_order_relaxed);
    126 }
    127 
    128 void
    129 isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn,
    130 	       void *arg, unsigned int options)
    131 {
    132 	int i;
    133 
    134 	REQUIRE(ISC_STATS_VALID(stats));
    135 
    136 	for (i = 0; i < stats->ncounters; i++) {
    137 		uint32_t counter = atomic_load_explicit(&stats->counters[i],
    138 							memory_order_relaxed);
    139 		if ((options & ISC_STATSDUMP_VERBOSE) == 0 && counter == 0) {
    140 			continue;
    141 		}
    142 		dump_fn((isc_statscounter_t)i, counter, arg);
    143 	}
    144 }
    145 
    146 void
    147 isc_stats_set(isc_stats_t *stats, uint64_t val,
    148 	      isc_statscounter_t counter)
    149 {
    150 	REQUIRE(ISC_STATS_VALID(stats));
    151 	REQUIRE(counter < stats->ncounters);
    152 
    153 	atomic_store_explicit(&stats->counters[counter], val,
    154 			      memory_order_relaxed);
    155 }
    156 
    157 void isc_stats_update_if_greater(isc_stats_t *stats,
    158 				 isc_statscounter_t counter,
    159 				 isc_statscounter_t value)
    160 {
    161 	REQUIRE(ISC_STATS_VALID(stats));
    162 	REQUIRE(counter < stats->ncounters);
    163 
    164 	isc_statscounter_t curr_value =
    165 		atomic_load_relaxed(&stats->counters[counter]);
    166 	do {
    167 		if (curr_value >= value) {
    168 			break;
    169 		}
    170 	} while (!atomic_compare_exchange_strong(&stats->counters[counter],
    171 						 &curr_value,
    172 						 value));
    173 }
    174 
    175 isc_statscounter_t
    176 isc_stats_get_counter(isc_stats_t *stats, isc_statscounter_t counter)
    177 {
    178 	REQUIRE(ISC_STATS_VALID(stats));
    179 	REQUIRE(counter < stats->ncounters);
    180 
    181 	return (atomic_load_explicit(&stats->counters[counter],
    182 				    memory_order_relaxed));
    183 }
    184