Coverage Report

Created: 2022-03-10 07:56

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