-/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
{ 0 }
};
-static void dump_counters(FILE *fd, int level, mod_ctr_t *ctr)
+uint64_t stats_get_counter(uint64_t **stats_vals, uint32_t offset, unsigned threads)
+{
+ uint64_t res = 0;
+ for (unsigned i = 0; i < threads; i++) {
+ res += ATOMIC_GET(stats_vals[i][offset]);
+ }
+ return res;
+}
+
+static void dump_counters(FILE *fd, int level, mod_ctr_t *ctr, uint64_t **stats_vals, unsigned threads)
{
for (uint32_t j = 0; j < ctr->count; j++) {
- uint64_t counter = ATOMIC_GET(ctr->counters[j]);
+ uint64_t counter = stats_get_counter(stats_vals, ctr->offset + j, threads);
// Skip empty counters.
if (counter == 0) {
level = 0;
}
+ unsigned threads = knotd_mod_threads(mod);
+
// Dump module counters.
DUMP_STR(ctx->fd, level, "%s", mod->id->name + 1, "");
for (int i = 0; i < mod->stats_count; i++) {
- mod_ctr_t *ctr = mod->stats + i;
+ mod_ctr_t *ctr = mod->stats_info + i;
if (ctr->name == NULL) {
// Empty counter.
continue;
}
if (ctr->count == 1) {
// Simple counter.
- uint64_t counter = ATOMIC_GET(ctr->counter);
+ uint64_t counter = stats_get_counter(mod->stats_vals,
+ ctr->offset, threads);
DUMP_CTR(ctx->fd, level + 1, "%s", ctr->name, counter);
} else {
// Array of counters.
DUMP_STR(ctx->fd, level + 1, "%s", ctr->name, "");
- dump_counters(ctx->fd, level + 2, ctr);
+ dump_counters(ctx->fd, level + 2, ctr, mod->stats_vals, threads);
}
}
}
-/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
extern const stats_item_t server_stats[];
+/*!
+ * \brief Read out value of single counter summed across threads.
+ */
+uint64_t stats_get_counter(uint64_t **stats_vals, uint32_t offset, unsigned threads);
+
/*!
* \brief Reconfigures the statistics facility.
*/
return KNOT_EOK;
}
-static int send_stats_ctr(mod_ctr_t *ctr, ctl_args_t *args, knot_ctl_data_t *data)
+static int send_stats_ctr(mod_ctr_t *ctr, uint64_t **stats_vals, unsigned threads,
+ ctl_args_t *args, knot_ctl_data_t *data)
{
char index[128];
char value[32];
if (ctr->count == 1) {
- uint64_t counter = ATOMIC_GET(ctr->counter);
+ uint64_t counter = stats_get_counter(stats_vals, ctr->offset, threads);
int ret = snprintf(value, sizeof(value), "%"PRIu64, counter);
if (ret <= 0 || ret >= sizeof(value)) {
return KNOT_ESPACE;
CTL_FLAG_FORCE);
for (uint32_t i = 0; i < ctr->count; i++) {
- uint64_t counter = ATOMIC_GET(ctr->counters[i]);
+ uint64_t counter = stats_get_counter(stats_vals, ctr->offset + i, threads);
// Skip empty counters.
if (counter == 0 && !force) {
data[KNOT_CTL_IDX_SECTION] = mod->id->name + 1;
+ unsigned threads = knotd_mod_threads(mod);
+
for (int i = 0; i < mod->stats_count; i++) {
- mod_ctr_t *ctr = mod->stats + i;
+ mod_ctr_t *ctr = mod->stats_info + i;
// Skip empty counter.
if (ctr->name == NULL) {
data[KNOT_CTL_IDX_ITEM] = ctr->name;
// Send the counters.
- int ret = send_stats_ctr(ctr, args, &data);
+ int ret = send_stats_ctr(ctr, mod->stats_vals, threads, args, &data);
if (ret != KNOT_EOK) {
return ret;
}
* Increments a statistics counter.
*
* \param[in] mod Module context.
+ * \param[in] thr_id Index of worker thread.
* \param[in] ctr_id Counter id (counted in the order the counters were registered).
* \param[in] idx Subcounter index (set 0 for single-counter).
* \param[in] val Value increment.
*/
-void knotd_mod_stats_incr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val);
+void knotd_mod_stats_incr(knotd_mod_t *mod, unsigned thread_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val);
/*!
* Decrements a statistics counter.
*
* \param[in] mod Module context.
+ * \param[in] thr_id Index of worker thread.
* \param[in] ctr_id Counter id (counted in the order the counters were registered).
* \param[in] idx Subcounter index (set 0 for single-counter).
* \param[in] val Value decrement.
*/
-void knotd_mod_stats_decr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val);
+void knotd_mod_stats_decr(knotd_mod_t *mod, unsigned thread_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val);
/*!
* Sets a statistics counter value.
*
* \param[in] mod Module context.
+ * \param[in] thr_id Index of worker thread.
* \param[in] ctr_id Counter id (counted in the order the counters were registered).
* \param[in] idx Subcounter index (set 0 for single-counter).
* \param[in] val Value.
*/
-void knotd_mod_stats_store(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val);
+void knotd_mod_stats_store(knotd_mod_t *mod, unsigned thread_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val);
/*! Configuration single-value abstraction. */
typedef union {
*/
knotd_conf_t knotd_conf_env(knotd_mod_t *mod, knotd_conf_env_t env);
+/*!
+ * Gets number of answering threads.
+ *
+ * \param[in] mod Module context.
+ *
+ * \return Number of worker threads.
+ */
+unsigned knotd_mod_threads(knotd_mod_t *mod);
+
/*!
* Gets module configuration value.
*
-/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
}
// Increment the statistics counter.
- knotd_mod_stats_incr(mod, 0, 0, 1);
+ knotd_mod_stats_incr(mod, qdata->params->thread_id, 0, 0, 1);
knot_edns_cookie_t cc;
knot_edns_cookie_t sc;
}
/* Initialize queues. */
- knotd_conf_t udp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_UDP);
- knotd_conf_t xdp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_XDP);
- knotd_conf_t tcp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_TCP);
- size_t qcount = udp.single.integer + xdp.single.integer + tcp.single.integer;
- fstrm_iothr_options_set_num_input_queues(opt, qcount);
+ fstrm_iothr_options_set_num_input_queues(opt, knotd_mod_threads(mod));
/* Create the I/O thread. */
ctx->iothread = fstrm_iothr_init(opt, &writer);
knotd_conf_t conf = knotd_conf_mod(mod, MOD_UDP_ALLOW_RATE);
ctx->rate = conf.single.integer;
if (ctx->rate > 0) {
- knotd_conf_t udp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_UDP);
- knotd_conf_t tcp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_TCP);
- knotd_conf_t xdp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_XDP);
- size_t workers = udp.single.integer + tcp.single.integer + xdp.single.integer;
- ctx->counters = calloc(workers, sizeof(uint32_t));
+ ctx->counters = calloc(knotd_mod_threads(mod), sizeof(uint32_t));
if (ctx->counters == NULL) {
free(ctx);
return KNOT_ENOMEM;
-/* Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
if (rrl_slip_roll(ctx->slip)) {
// Slip the answer.
- knotd_mod_stats_incr(mod, 0, 0, 1);
+ knotd_mod_stats_incr(mod, qdata->params->thread_id, 0, 0, 1);
qdata->err_truncated = true;
return KNOTD_STATE_FAIL;
} else {
// Drop the answer.
- knotd_mod_stats_incr(mod, 1, 0, 1);
+ knotd_mod_stats_incr(mod, qdata->params->thread_id, 1, 0, 1);
return KNOTD_STATE_NOOP;
}
}
{ NULL }
};
-static void incr_edns_option(knotd_mod_t *mod, const knot_pkt_t *pkt, unsigned ctr_name)
+static void incr_edns_option(knotd_mod_t *mod, unsigned thr_id, const knot_pkt_t *pkt, unsigned ctr_name)
{
if (!knot_pkt_has_edns(pkt)) {
return;
if (wire.error != KNOT_EOK) {
break;
}
- knotd_mod_stats_incr(mod, ctr_name, MIN(opt_code, EOPT_OTHER), 1);
+ knotd_mod_stats_incr(mod, thr_id, ctr_name, MIN(opt_code, EOPT_OTHER), 1);
}
}
uint16_t operation;
unsigned xfr_packets = 0;
+ unsigned tid = qdata->params->thread_id;
// Get the server operation.
switch (qdata->type) {
if (stats->req_bytes) {
switch (operation) {
case OPERATION_QUERY:
- knotd_mod_stats_incr(mod, CTR_REQ_BYTES, REQ_BYTES_QUERY,
+ knotd_mod_stats_incr(mod, tid, CTR_REQ_BYTES, REQ_BYTES_QUERY,
knot_pkt_size(qdata->query));
break;
case OPERATION_UPDATE:
- knotd_mod_stats_incr(mod, CTR_REQ_BYTES, REQ_BYTES_UPDATE,
+ knotd_mod_stats_incr(mod, tid, CTR_REQ_BYTES, REQ_BYTES_UPDATE,
knot_pkt_size(qdata->query));
break;
default:
if (xfr_packets <= 1) {
- knotd_mod_stats_incr(mod, CTR_REQ_BYTES, REQ_BYTES_OTHER,
+ knotd_mod_stats_incr(mod, tid, CTR_REQ_BYTES, REQ_BYTES_OTHER,
knot_pkt_size(qdata->query));
}
break;
if (stats->resp_bytes && state != KNOTD_STATE_NOOP) {
switch (operation) {
case OPERATION_QUERY:
- knotd_mod_stats_incr(mod, CTR_RESP_BYTES, RESP_BYTES_REPLY,
+ knotd_mod_stats_incr(mod, tid, CTR_RESP_BYTES, RESP_BYTES_REPLY,
knot_pkt_size(pkt));
break;
case OPERATION_AXFR:
case OPERATION_IXFR:
- knotd_mod_stats_incr(mod, CTR_RESP_BYTES, RESP_BYTES_TRANSFER,
+ knotd_mod_stats_incr(mod, tid, CTR_RESP_BYTES, RESP_BYTES_TRANSFER,
knot_pkt_size(pkt));
break;
default:
- knotd_mod_stats_incr(mod, CTR_RESP_BYTES, RESP_BYTES_OTHER,
+ knotd_mod_stats_incr(mod, tid, CTR_RESP_BYTES, RESP_BYTES_OTHER,
knot_pkt_size(pkt));
break;
}
if (xfr_packets > 1) {
assert(rcode != KNOT_RCODE_NOERROR);
// Ignore the leading XFR message NOERROR.
- knotd_mod_stats_decr(mod, CTR_RCODE,
+ knotd_mod_stats_decr(mod, tid, CTR_RCODE,
KNOT_RCODE_NOERROR, 1);
}
if (qdata->rcode_tsig == KNOT_RCODE_BADSIG) {
- knotd_mod_stats_incr(mod, CTR_RCODE, RCODE_BADSIG, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_RCODE, RCODE_BADSIG, 1);
} else {
- knotd_mod_stats_incr(mod, CTR_RCODE,
+ knotd_mod_stats_incr(mod, tid, CTR_RCODE,
MIN(rcode, RCODE_OTHER), 1);
}
}
// Count the server opearation.
if (stats->operation) {
- knotd_mod_stats_incr(mod, CTR_OPERATION, operation, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_OPERATION, operation, 1);
}
// Count the request protocol.
if (qdata->params->remote->ss_family == AF_INET) {
if (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE) {
if (xdp) {
- knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL,
PROTOCOL_UDP4_XDP, 1);
} else {
- knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL,
PROTOCOL_UDP4, 1);
}
} else {
- knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL,
PROTOCOL_TCP4, 1);
}
} else {
if (qdata->params->flags & KNOTD_QUERY_FLAG_LIMIT_SIZE) {
if (xdp) {
- knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL,
PROTOCOL_UDP6_XDP, 1);
} else {
- knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL,
PROTOCOL_UDP6, 1);
}
} else {
- knotd_mod_stats_incr(mod, CTR_PROTOCOL,
+ knotd_mod_stats_incr(mod, tid, CTR_PROTOCOL,
PROTOCOL_TCP6, 1);
}
}
// Count EDNS occurrences.
if (stats->edns) {
if (knot_pkt_has_edns(qdata->query)) {
- knotd_mod_stats_incr(mod, CTR_EDNS, EDNS_REQ, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_EDNS, EDNS_REQ, 1);
}
if (knot_pkt_has_edns(pkt) && state != KNOTD_STATE_NOOP) {
- knotd_mod_stats_incr(mod, CTR_EDNS, EDNS_RESP, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_EDNS, EDNS_RESP, 1);
}
}
// Count interesting message header flags.
if (stats->flag) {
if (state != KNOTD_STATE_NOOP && knot_wire_get_tc(pkt->wire)) {
- knotd_mod_stats_incr(mod, CTR_FLAG, FLAG_TC, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_FLAG, FLAG_TC, 1);
}
if (knot_pkt_has_dnssec(pkt)) {
- knotd_mod_stats_incr(mod, CTR_FLAG, FLAG_DO, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_FLAG, FLAG_DO, 1);
}
}
// Count EDNS options.
if (stats->req_eopt) {
- incr_edns_option(mod, qdata->query, CTR_REQ_EOPT);
+ incr_edns_option(mod, tid, qdata->query, CTR_REQ_EOPT);
}
if (stats->resp_eopt) {
- incr_edns_option(mod, pkt, CTR_RESP_EOPT);
+ incr_edns_option(mod, tid, pkt, CTR_RESP_EOPT);
}
// Return if not query operation.
knot_pkt_rr(knot_pkt_section(pkt, KNOT_AUTHORITY), 0)->type == KNOT_RRTYPE_SOA)) {
switch (knot_pkt_qtype(qdata->query)) {
case KNOT_RRTYPE_A:
- knotd_mod_stats_incr(mod, CTR_NODATA, NODATA_A, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_NODATA, NODATA_A, 1);
break;
case KNOT_RRTYPE_AAAA:
- knotd_mod_stats_incr(mod, CTR_NODATA, NODATA_AAAA, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_NODATA, NODATA_AAAA, 1);
break;
default:
- knotd_mod_stats_incr(mod, CTR_NODATA, NODATA_OTHER, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_NODATA, NODATA_OTHER, 1);
break;
}
}
default: idx = QTYPE_OTHER; break;
}
- knotd_mod_stats_incr(mod, CTR_QTYPE, idx, 1);
+ knotd_mod_stats_incr(mod, tid, CTR_QTYPE, idx, 1);
}
// Count the query size.
if (stats->qsize) {
uint64_t idx = knot_pkt_size(qdata->query) / BUCKET_SIZE;
- knotd_mod_stats_incr(mod, CTR_QSIZE, MIN(idx, QSIZE_MAX_IDX), 1);
+ knotd_mod_stats_incr(mod, tid, CTR_QSIZE, MIN(idx, QSIZE_MAX_IDX), 1);
}
// Count the reply size.
if (stats->rsize && state != KNOTD_STATE_NOOP) {
uint64_t idx = knot_pkt_size(pkt) / BUCKET_SIZE;
- knotd_mod_stats_incr(mod, CTR_RSIZE, MIN(idx, RSIZE_MAX_IDX), 1);
+ knotd_mod_stats_incr(mod, tid, CTR_RSIZE, MIN(idx, RSIZE_MAX_IDX), 1);
}
return state;
#define ATOMIC_SUB(dst, val) __atomic_sub_fetch(&(dst), (val), __ATOMIC_RELAXED)
#define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED)
#else
- #warning "Statistics data can be inaccurate if configured with multiple udp/tcp workers"
+ #warning "Statistics data can be inaccurate"
#define ATOMIC_ADD(dst, val) ((dst) += (val))
#define ATOMIC_SUB(dst, val) ((dst) -= (val))
#define ATOMIC_SET(dst, val) ((dst) = (val))
return KNOT_EINVAL;
}
+ unsigned threads = knotd_mod_threads(mod);
+
mod_ctr_t *stats = NULL;
- if (mod->stats == NULL) {
+ uint32_t offset = 0;
+ if (mod->stats_info == NULL) {
assert(mod->stats_count == 0);
stats = malloc(sizeof(*stats));
if (stats == NULL) {
return KNOT_ENOMEM;
}
- mod->stats = stats;
+ mod->stats_info = stats;
+
+ assert(mod->stats_vals == NULL);
+ mod->stats_vals = calloc(threads, sizeof(*mod->stats_vals));
+ if (mod->stats_vals == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+
+ for (unsigned i = 0; i < threads; i++) {
+ mod->stats_vals[i] = calloc(idx_count, sizeof(**mod->stats_vals));
+ if (mod->stats_vals[i] == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ }
} else {
+ for (uint32_t i = 0; i < mod->stats_count; i++) {
+ offset += mod->stats_info[i].count;
+ }
+ assert(offset == mod->stats_info[mod->stats_count - 1].offset +
+ mod->stats_info[mod->stats_count - 1].count);
+
assert(mod->stats_count > 0);
size_t old_size = mod->stats_count * sizeof(*stats);
size_t new_size = old_size + sizeof(*stats);
- stats = realloc(mod->stats, new_size);
+ stats = realloc(mod->stats_info, new_size);
if (stats == NULL) {
knotd_mod_stats_free(mod);
return KNOT_ENOMEM;
}
- mod->stats = stats;
+ mod->stats_info = stats;
stats += mod->stats_count;
- }
- if (idx_count == 1) {
- stats->counter = 0;
- } else {
- size_t size = idx_count * sizeof(((mod_ctr_t *)0)->counter);
- stats->counters = calloc(1, size);
- if (stats->counters == NULL) {
- knotd_mod_stats_free(mod);
- return KNOT_ENOMEM;
+ for (unsigned i = 0; i < threads; i++) {
+ uint64_t *new_vals = realloc(mod->stats_vals[i],
+ (offset + idx_count) * sizeof(*new_vals));
+ if (new_vals == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ mod->stats_vals[i] = new_vals;
+ new_vals += offset;
+ for (uint32_t j = 0; j < idx_count; j++) {
+ *new_vals++ = 0;
+ }
}
- stats->idx_to_str = idx_to_str;
}
+
stats->name = ctr_name;
stats->count = idx_count;
+ stats->idx_to_str = idx_to_str;
+ stats->offset = offset;
mod->stats_count++;
_public_
void knotd_mod_stats_free(knotd_mod_t *mod)
{
- if (mod == NULL || mod->stats == NULL) {
+ if (mod == NULL || mod->stats_info == NULL) {
return;
}
- for (int i = 0; i < mod->stats_count; i++) {
- if (mod->stats[i].count > 1) {
- free(mod->stats[i].counters);
- }
+ unsigned threads = knotd_mod_threads(mod);
+
+ for (unsigned i = 0; i < threads; i++) {
+ free(mod->stats_vals[i]);
}
- free(mod->stats);
+ free(mod->stats_vals);
+ free(mod->stats_info);
}
#define STATS_BODY(OPERATION) { \
if (mod == NULL) return; \
\
- mod_ctr_t *ctr = mod->stats + ctr_id; \
- if (ctr->count == 1) { \
- assert(idx == 0); \
- OPERATION(ctr->counter, val); \
- } else { \
- assert(idx < ctr->count); \
- OPERATION(ctr->counters[idx], val); \
- } \
+ mod_ctr_t *ctr = mod->stats_info + ctr_id; \
+ assert(idx < ctr->count); \
+ OPERATION(mod->stats_vals[thread_id][ctr->offset + idx], val); \
}
_public_
-void knotd_mod_stats_incr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val)
+void knotd_mod_stats_incr(knotd_mod_t *mod, unsigned thread_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val)
{
STATS_BODY(ATOMIC_ADD)
}
_public_
-void knotd_mod_stats_decr(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val)
+void knotd_mod_stats_decr(knotd_mod_t *mod, unsigned thread_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val)
{
STATS_BODY(ATOMIC_SUB)
}
_public_
-void knotd_mod_stats_store(knotd_mod_t *mod, uint32_t ctr_id, uint32_t idx, uint64_t val)
+void knotd_mod_stats_store(knotd_mod_t *mod, unsigned thread_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val)
{
STATS_BODY(ATOMIC_SET)
}
return out;
}
+_public_
+unsigned knotd_mod_threads(knotd_mod_t *mod)
+{
+ knotd_conf_t udp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_UDP);
+ knotd_conf_t xdp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_XDP);
+ knotd_conf_t tcp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_TCP);
+ return udp.single.integer + xdp.single.integer + tcp.single.integer;
+}
+
static void set_val(yp_type_t type, knotd_conf_val_t *item, conf_val_t *val)
{
switch (type) {
typedef struct {
const char *name;
- union {
- uint64_t counter;
- struct {
- uint64_t *counters;
- mod_idx_to_str_f idx_to_str;
- };
- };
+ mod_idx_to_str_f idx_to_str; // unused if count == 1
+ uint32_t offset; // offset of counters in stats_vals[thread_id]
uint32_t count;
} mod_ctr_t;
kdnssec_ctx_t *dnssec;
zone_keyset_t *keyset;
zone_sign_ctx_t *sign_ctx;
- mod_ctr_t *stats;
+ mod_ctr_t *stats_info;
+ uint64_t **stats_vals;
uint32_t stats_count;
void *ctx;
};