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