xref: /netbsd-src/external/mpl/bind/dist/lib/isc/stats.c (revision a04395531661c5e8d314125d5ae77d4cbedd5d73)
1 /*	$NetBSD: stats.c,v 1.9 2021/08/19 11:50:18 christos 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 https://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 /*! \file */
15 
16 #include <inttypes.h>
17 #include <string.h>
18 
19 #include <isc/atomic.h>
20 #include <isc/buffer.h>
21 #include <isc/magic.h>
22 #include <isc/mem.h>
23 #include <isc/platform.h>
24 #include <isc/print.h>
25 #include <isc/refcount.h>
26 #include <isc/stats.h>
27 #include <isc/util.h>
28 
29 #define ISC_STATS_MAGIC	   ISC_MAGIC('S', 't', 'a', 't')
30 #define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
31 
32 #if (defined(_WIN32) && !defined(_WIN64)) || !defined(_LP64)
33 typedef atomic_int_fast32_t isc__atomic_statcounter_t;
34 #else  /* if defined(_WIN32) && !defined(_WIN64) */
35 typedef atomic_int_fast64_t isc__atomic_statcounter_t;
36 #endif /* if defined(_WIN32) && !defined(_WIN64) */
37 
38 struct isc_stats {
39 	unsigned int magic;
40 	isc_mem_t *mctx;
41 	isc_refcount_t references;
42 	int ncounters;
43 	isc__atomic_statcounter_t *counters;
44 };
45 
46 static isc_result_t
47 create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
48 	isc_stats_t *stats;
49 	size_t counters_alloc_size;
50 
51 	REQUIRE(statsp != NULL && *statsp == NULL);
52 
53 	stats = isc_mem_get(mctx, sizeof(*stats));
54 	counters_alloc_size = sizeof(isc__atomic_statcounter_t) * ncounters;
55 	stats->counters = isc_mem_get(mctx, counters_alloc_size);
56 	isc_refcount_init(&stats->references, 1);
57 	for (int i = 0; i < ncounters; i++) {
58 		atomic_init(&stats->counters[i], 0);
59 	}
60 	stats->mctx = NULL;
61 	isc_mem_attach(mctx, &stats->mctx);
62 	stats->ncounters = ncounters;
63 	stats->magic = ISC_STATS_MAGIC;
64 	*statsp = stats;
65 
66 	return (ISC_R_SUCCESS);
67 }
68 
69 void
70 isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) {
71 	REQUIRE(ISC_STATS_VALID(stats));
72 	REQUIRE(statsp != NULL && *statsp == NULL);
73 
74 	isc_refcount_increment(&stats->references);
75 	*statsp = stats;
76 }
77 
78 void
79 isc_stats_detach(isc_stats_t **statsp) {
80 	isc_stats_t *stats;
81 
82 	REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp));
83 
84 	stats = *statsp;
85 	*statsp = NULL;
86 
87 	if (isc_refcount_decrement(&stats->references) == 1) {
88 		isc_refcount_destroy(&stats->references);
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_relaxed(&stats->counters[counter], 1);
116 }
117 
118 void
119 isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
120 	REQUIRE(ISC_STATS_VALID(stats));
121 	REQUIRE(counter < stats->ncounters);
122 	atomic_fetch_sub_release(&stats->counters[counter], 1);
123 }
124 
125 void
126 isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg,
127 	       unsigned int options) {
128 	int i;
129 
130 	REQUIRE(ISC_STATS_VALID(stats));
131 
132 	for (i = 0; i < stats->ncounters; i++) {
133 		uint32_t counter = atomic_load_acquire(&stats->counters[i]);
134 		if ((options & ISC_STATSDUMP_VERBOSE) == 0 && counter == 0) {
135 			continue;
136 		}
137 		dump_fn((isc_statscounter_t)i, counter, arg);
138 	}
139 }
140 
141 void
142 isc_stats_set(isc_stats_t *stats, uint64_t val, isc_statscounter_t counter) {
143 	REQUIRE(ISC_STATS_VALID(stats));
144 	REQUIRE(counter < stats->ncounters);
145 
146 	atomic_store_release(&stats->counters[counter], val);
147 }
148 
149 void
150 isc_stats_update_if_greater(isc_stats_t *stats, isc_statscounter_t counter,
151 			    isc_statscounter_t value) {
152 	REQUIRE(ISC_STATS_VALID(stats));
153 	REQUIRE(counter < stats->ncounters);
154 
155 	isc_statscounter_t curr_value =
156 		atomic_load_acquire(&stats->counters[counter]);
157 	do {
158 		if (curr_value >= value) {
159 			break;
160 		}
161 	} while (!atomic_compare_exchange_weak_acq_rel(
162 		&stats->counters[counter], &curr_value, value));
163 }
164 
165 isc_statscounter_t
166 isc_stats_get_counter(isc_stats_t *stats, isc_statscounter_t counter) {
167 	REQUIRE(ISC_STATS_VALID(stats));
168 	REQUIRE(counter < stats->ncounters);
169 
170 	return (atomic_load_acquire(&stats->counters[counter]));
171 }
172