Coverage Report

Created: 2023-06-07 06:23

/src/bind9/lib/isc/stats.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
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/refcount.h>
24
#include <isc/stats.h>
25
#include <isc/util.h>
26
27
#define ISC_STATS_MAGIC    ISC_MAGIC('S', 't', 'a', 't')
28
#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
29
30
typedef atomic_int_fast64_t isc__atomic_statcounter_t;
31
32
struct isc_stats {
33
  unsigned int magic;
34
  isc_mem_t *mctx;
35
  isc_refcount_t references;
36
  int ncounters;
37
  isc__atomic_statcounter_t *counters;
38
};
39
40
static isc_result_t
41
create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
42
  isc_stats_t *stats;
43
  size_t counters_alloc_size;
44
45
  REQUIRE(statsp != NULL && *statsp == NULL);
46
47
  stats = isc_mem_get(mctx, sizeof(*stats));
48
  counters_alloc_size = sizeof(isc__atomic_statcounter_t) * ncounters;
49
  stats->counters = isc_mem_get(mctx, counters_alloc_size);
50
  isc_refcount_init(&stats->references, 1);
51
  for (int i = 0; i < ncounters; i++) {
52
    atomic_init(&stats->counters[i], 0);
53
  }
54
  stats->mctx = NULL;
55
  isc_mem_attach(mctx, &stats->mctx);
56
  stats->ncounters = ncounters;
57
  stats->magic = ISC_STATS_MAGIC;
58
  *statsp = stats;
59
60
  return (ISC_R_SUCCESS);
61
}
62
63
void
64
2
isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) {
65
2
  REQUIRE(ISC_STATS_VALID(stats));
66
2
  REQUIRE(statsp != NULL && *statsp == NULL);
67
68
2
  isc_refcount_increment(&stats->references);
69
2
  *statsp = stats;
70
2
}
71
72
void
73
4
isc_stats_detach(isc_stats_t **statsp) {
74
4
  isc_stats_t *stats;
75
76
4
  REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp));
77
78
4
  stats = *statsp;
79
4
  *statsp = NULL;
80
81
4
  if (isc_refcount_decrement(&stats->references) == 1) {
82
2
    isc_refcount_destroy(&stats->references);
83
2
    isc_mem_put(stats->mctx, stats->counters,
84
2
          sizeof(isc__atomic_statcounter_t) *
85
2
            stats->ncounters);
86
2
    isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
87
2
  }
88
4
}
89
90
int
91
0
isc_stats_ncounters(isc_stats_t *stats) {
92
0
  REQUIRE(ISC_STATS_VALID(stats));
93
94
0
  return (stats->ncounters);
95
0
}
96
97
isc_result_t
98
2
isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) {
99
2
  REQUIRE(statsp != NULL && *statsp == NULL);
100
101
2
  return (create_stats(mctx, ncounters, statsp));
102
2
}
103
104
void
105
0
isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
106
0
  REQUIRE(ISC_STATS_VALID(stats));
107
0
  REQUIRE(counter < stats->ncounters);
108
109
0
  atomic_fetch_add_relaxed(&stats->counters[counter], 1);
110
0
}
111
112
void
113
0
isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
114
0
  REQUIRE(ISC_STATS_VALID(stats));
115
0
  REQUIRE(counter < stats->ncounters);
116
0
#if ISC_STATS_CHECKUNDERFLOW
117
0
  REQUIRE(atomic_fetch_sub_release(&stats->counters[counter], 1) > 0);
118
#else
119
  atomic_fetch_sub_release(&stats->counters[counter], 1);
120
#endif
121
0
}
122
123
void
124
isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg,
125
0
         unsigned int options) {
126
0
  int i;
127
128
0
  REQUIRE(ISC_STATS_VALID(stats));
129
130
0
  for (i = 0; i < stats->ncounters; i++) {
131
0
    uint32_t counter = atomic_load_acquire(&stats->counters[i]);
132
0
    if ((options & ISC_STATSDUMP_VERBOSE) == 0 && counter == 0) {
133
0
      continue;
134
0
    }
135
0
    dump_fn((isc_statscounter_t)i, counter, arg);
136
0
  }
137
0
}
138
139
void
140
0
isc_stats_set(isc_stats_t *stats, uint64_t val, isc_statscounter_t counter) {
141
0
  REQUIRE(ISC_STATS_VALID(stats));
142
0
  REQUIRE(counter < stats->ncounters);
143
144
0
  atomic_store_release(&stats->counters[counter], val);
145
0
}
146
147
void
148
isc_stats_update_if_greater(isc_stats_t *stats, isc_statscounter_t counter,
149
0
          isc_statscounter_t value) {
150
0
  REQUIRE(ISC_STATS_VALID(stats));
151
0
  REQUIRE(counter < stats->ncounters);
152
153
0
  isc_statscounter_t curr_value =
154
0
    atomic_load_acquire(&stats->counters[counter]);
155
0
  do {
156
0
    if (curr_value >= value) {
157
0
      break;
158
0
    }
159
0
  } while (!atomic_compare_exchange_weak_acq_rel(
160
0
    &stats->counters[counter], &curr_value, value));
161
0
}
162
163
isc_statscounter_t
164
0
isc_stats_get_counter(isc_stats_t *stats, isc_statscounter_t counter) {
165
0
  REQUIRE(ISC_STATS_VALID(stats));
166
0
  REQUIRE(counter < stats->ncounters);
167
168
0
  return (atomic_load_acquire(&stats->counters[counter]));
169
0
}
170
171
void
172
0
isc_stats_resize(isc_stats_t **statsp, int ncounters) {
173
0
  isc_stats_t *stats;
174
0
  size_t counters_alloc_size;
175
0
  isc__atomic_statcounter_t *newcounters;
176
177
0
  REQUIRE(statsp != NULL && *statsp != NULL);
178
0
  REQUIRE(ISC_STATS_VALID(*statsp));
179
0
  REQUIRE(ncounters > 0);
180
181
0
  stats = *statsp;
182
0
  if (stats->ncounters >= ncounters) {
183
    /* We already have enough counters. */
184
0
    return;
185
0
  }
186
187
  /* Grow number of counters. */
188
0
  counters_alloc_size = sizeof(isc__atomic_statcounter_t) * ncounters;
189
0
  newcounters = isc_mem_get(stats->mctx, counters_alloc_size);
190
0
  for (int i = 0; i < ncounters; i++) {
191
0
    atomic_init(&newcounters[i], 0);
192
0
  }
193
0
  for (int i = 0; i < stats->ncounters; i++) {
194
0
    uint32_t counter = atomic_load_acquire(&stats->counters[i]);
195
0
    atomic_store_release(&newcounters[i], counter);
196
0
  }
197
0
  isc_mem_put(stats->mctx, stats->counters,
198
0
        sizeof(isc__atomic_statcounter_t) * stats->ncounters);
199
0
  stats->counters = newcounters;
200
0
  stats->ncounters = ncounters;
201
0
}