Coverage Report

Created: 2026-06-15 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/statsmulti.c
Line
Count
Source
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/os.h>
24
#include <isc/refcount.h>
25
#include <isc/stats.h>
26
#include <isc/statsmulti.h>
27
#include <isc/tid.h>
28
#include <isc/util.h>
29
30
0
#define ISC_STATSMULTI_MAGIC  ISC_MAGIC('S', 'M', 'u', 'l')
31
#define ISC_STATSMULTI_VALID(x) ISC_MAGIC_VALID(x, ISC_STATSMULTI_MAGIC)
32
33
/*
34
 * Same constraint as stats.c
35
 */
36
STATIC_ASSERT(sizeof(isc_statscounter_t) <= sizeof(uint64_t),
37
        "Exported statistics must fit into the statistic counter size");
38
39
struct isc_statsmulti {
40
  unsigned int magic;
41
  isc_mem_t *mctx;
42
  isc_refcount_t references;
43
  int n_counters;
44
  int per_thread_capacity;
45
  int num_threads_plus_one;
46
  isc_atomic_statscounter_t *counters;
47
};
48
49
static int
50
to_index(isc_statsmulti_t *stats, isc_tid_t tid,
51
0
   isc_statscounter_t internal_counter) {
52
0
  int thread_id = tid + 1;
53
0
  if (thread_id >= stats->num_threads_plus_one) {
54
0
    thread_id = 0;
55
0
  }
56
0
  return thread_id * stats->per_thread_capacity + internal_counter;
57
0
}
58
59
void
60
isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp,
61
0
          int ncounters) {
62
0
  REQUIRE(statsp != NULL && *statsp == NULL);
63
64
0
  size_t size_in_bytes = sizeof(isc_atomic_statscounter_t) * ncounters;
65
0
  size_t rounded_up = (size_in_bytes + 63) & ~63; /* Round up to next
66
                 multiple of 64 */
67
0
  int per_thread_capacity = rounded_up /
68
0
          sizeof(isc_atomic_statscounter_t);
69
0
  int num_threads_plus_one = isc_tid_count() + 1;
70
71
0
  isc_statsmulti_t *stats = isc_mem_get(mctx, sizeof(*stats));
72
0
  *stats = (isc_statsmulti_t){
73
0
    .magic = ISC_STATSMULTI_MAGIC,
74
0
    .counters = isc_mem_cget(
75
0
      mctx, per_thread_capacity * num_threads_plus_one,
76
0
      sizeof(isc_atomic_statscounter_t)),
77
0
    .mctx = isc_mem_ref(mctx),
78
0
    .n_counters = ncounters,
79
0
    .num_threads_plus_one = num_threads_plus_one,
80
0
    .per_thread_capacity = per_thread_capacity,
81
0
    .references = ISC_REFCOUNT_INITIALIZER(1),
82
83
0
  };
84
0
  *statsp = stats;
85
0
}
86
87
static void
88
0
isc__statsmulti_destroy(isc_statsmulti_t *stats) {
89
0
  REQUIRE(ISC_STATSMULTI_VALID(stats));
90
91
0
  size_t alloc_size = stats->per_thread_capacity *
92
0
          stats->num_threads_plus_one *
93
0
          sizeof(isc_atomic_statscounter_t);
94
0
  isc_mem_put(stats->mctx, stats->counters, alloc_size);
95
0
  isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
96
0
}
97
98
0
ISC_REFCOUNT_IMPL(isc_statsmulti, isc__statsmulti_destroy);
Unexecuted instantiation: isc_statsmulti_ref
Unexecuted instantiation: isc_statsmulti_unref
Unexecuted instantiation: isc_statsmulti_detach
99
0
100
0
void
101
0
isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) {
102
0
  REQUIRE(ISC_STATSMULTI_VALID(stats));
103
0
  REQUIRE(counter < stats->n_counters);
104
105
0
  int index = to_index(stats, isc_tid(), counter);
106
0
  if (isc_tid() == -1) {
107
0
    atomic_fetch_add_relaxed(&stats->counters[index], 1);
108
0
  } else {
109
0
    isc_atomic_statscounter_t *ptr = &stats->counters[index];
110
0
    atomic_store_relaxed(ptr, atomic_load_relaxed(ptr) + 1);
111
0
  }
112
0
}
113
114
void
115
0
isc_statsmulti_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) {
116
0
  REQUIRE(ISC_STATSMULTI_VALID(stats));
117
0
  REQUIRE(counter < stats->n_counters);
118
119
0
  int index = to_index(stats, isc_tid(), counter);
120
0
  if (isc_tid() == -1) {
121
0
    atomic_fetch_sub_relaxed(&stats->counters[index], 1);
122
0
  } else {
123
0
    isc_atomic_statscounter_t *ptr = &stats->counters[index];
124
0
    int_fast64_t tmp = atomic_load_relaxed(ptr);
125
0
    atomic_store_relaxed(ptr, tmp - 1);
126
0
  }
127
0
}
128
129
void
130
isc_statsmulti_dump(isc_statsmulti_t *stats, isc_statsmulti_dumper_t dump_fn,
131
0
        void *arg, unsigned int options) {
132
0
  REQUIRE(ISC_STATSMULTI_VALID(stats));
133
134
0
  for (int counter = 0; counter < stats->n_counters; counter++) {
135
0
    isc_statscounter_t total = isc_statsmulti_get_counter(stats,
136
0
                      counter);
137
138
0
    if ((options & ISC_STATSMULTIDUMP_VERBOSE) == 0 && total == 0) {
139
0
      continue;
140
0
    }
141
0
    dump_fn((isc_statscounter_t)counter, total, arg);
142
0
  }
143
0
}
144
145
isc_statscounter_t
146
isc_statsmulti_get_counter(isc_statsmulti_t *stats,
147
0
         isc_statscounter_t counter) {
148
0
  REQUIRE(ISC_STATSMULTI_VALID(stats));
149
0
  REQUIRE(counter < stats->n_counters);
150
151
0
  int idx_0 = to_index(stats, 0, counter);
152
0
  isc_statscounter_t total = atomic_load_acquire(&stats->counters[idx_0]);
153
154
0
  for (int thread = 1; thread < stats->num_threads_plus_one; thread++) {
155
0
    int index = to_index(stats, thread, counter);
156
0
    total += atomic_load_relaxed(&stats->counters[index]);
157
0
  }
158
159
0
  return total;
160
0
}
161
162
void
163
0
isc_statsmulti_clear(isc_statsmulti_t *stats) {
164
0
  REQUIRE(ISC_STATSMULTI_VALID(stats));
165
166
0
  for (int idx = 0;
167
0
       idx < stats->per_thread_capacity * stats->num_threads_plus_one;
168
0
       idx++)
169
0
  {
170
    atomic_store_release(&stats->counters[idx], 0);
171
0
  }
172
0
}