From: Libor Peltan Date: Thu, 14 May 2020 19:39:18 +0000 (+0200) Subject: stats/performance: per-thread counters X-Git-Tag: v3.0.0~124^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c68e26e450f46167fa019a7fe1b87bc93a7cfec6;p=thirdparty%2Fknot-dns.git stats/performance: per-thread counters --- diff --git a/src/knot/common/stats.c b/src/knot/common/stats.c index 7c0e38fe43..5cdfbaea5c 100644 --- a/src/knot/common/stats.c +++ b/src/knot/common/stats.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. 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 @@ -56,10 +56,19 @@ const stats_item_t server_stats[] = { { 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) { @@ -106,22 +115,25 @@ static void dump_modules(dump_ctx_t *ctx) 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); } } } diff --git a/src/knot/common/stats.h b/src/knot/common/stats.h index 2269a4026b..bd6df6d226 100644 --- a/src/knot/common/stats.h +++ b/src/knot/common/stats.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. 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 @@ -37,6 +37,11 @@ typedef struct { */ 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. */ diff --git a/src/knot/ctl/commands.c b/src/knot/ctl/commands.c index d65f9546d2..0b880cd51e 100644 --- a/src/knot/ctl/commands.c +++ b/src/knot/ctl/commands.c @@ -1167,13 +1167,14 @@ static int zone_purge(zone_t *zone, ctl_args_t *args) 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; @@ -1191,7 +1192,7 @@ static int send_stats_ctr(mod_ctr_t *ctr, ctl_args_t *args, knot_ctl_data_t *dat 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) { @@ -1268,8 +1269,10 @@ static int modules_stats(list_t *query_modules, ctl_args_t *args, knot_dname_t * 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) { @@ -1298,7 +1301,7 @@ static int modules_stats(list_t *query_modules, ctl_args_t *args, knot_dname_t * 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; } diff --git a/src/knot/include/module.h b/src/knot/include/module.h index 7f0a2cc7a0..626bb6bcd1 100644 --- a/src/knot/include/module.h +++ b/src/knot/include/module.h @@ -220,31 +220,37 @@ int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_cou * 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 { @@ -303,6 +309,15 @@ knotd_conf_t knotd_conf(knotd_mod_t *mod, const yp_name_t *section_name, */ 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. * diff --git a/src/knot/modules/cookies/cookies.c b/src/knot/modules/cookies/cookies.c index c9a1f3dc80..65950d7752 100644 --- a/src/knot/modules/cookies/cookies.c +++ b/src/knot/modules/cookies/cookies.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. 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 @@ -162,7 +162,7 @@ static knotd_state_t cookies_process(knotd_state_t state, knot_pkt_t *pkt, } // 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; diff --git a/src/knot/modules/dnstap/dnstap.c b/src/knot/modules/dnstap/dnstap.c index 630c5dd886..35eb2cbbe3 100644 --- a/src/knot/modules/dnstap/dnstap.c +++ b/src/knot/modules/dnstap/dnstap.c @@ -272,11 +272,7 @@ int dnstap_load(knotd_mod_t *mod) } /* 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); diff --git a/src/knot/modules/noudp/noudp.c b/src/knot/modules/noudp/noudp.c index d7fb5b09b0..cb454b52c6 100644 --- a/src/knot/modules/noudp/noudp.c +++ b/src/knot/modules/noudp/noudp.c @@ -59,11 +59,7 @@ int noudp_load(knotd_mod_t *mod) 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; diff --git a/src/knot/modules/rrl/rrl.c b/src/knot/modules/rrl/rrl.c index 07ee385ad8..cd68c71b5a 100644 --- a/src/knot/modules/rrl/rrl.c +++ b/src/knot/modules/rrl/rrl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 CZ.NIC, z.s.p.o. +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. 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 @@ -137,12 +137,12 @@ static knotd_state_t ratelimit_apply(knotd_state_t state, knot_pkt_t *pkt, 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; } } diff --git a/src/knot/modules/stats/stats.c b/src/knot/modules/stats/stats.c index 84d9d77f26..b93c163737 100644 --- a/src/knot/modules/stats/stats.c +++ b/src/knot/modules/stats/stats.c @@ -353,7 +353,7 @@ static const ctr_desc_t ctr_descs[] = { { 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; @@ -372,7 +372,7 @@ static void incr_edns_option(knotd_mod_t *mod, const knot_pkt_t *pkt, unsigned c 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); } } @@ -385,6 +385,7 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, uint16_t operation; unsigned xfr_packets = 0; + unsigned tid = qdata->params->thread_id; // Get the server operation. switch (qdata->type) { @@ -418,16 +419,16 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, 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; @@ -438,16 +439,16 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, 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; } @@ -465,14 +466,14 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, 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); } } @@ -485,7 +486,7 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, // 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. @@ -494,27 +495,27 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, 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); } } @@ -523,29 +524,29 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, // 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. @@ -560,13 +561,13 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, 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; } } @@ -583,19 +584,19 @@ static knotd_state_t update_counters(knotd_state_t state, knot_pkt_t *pkt, 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; diff --git a/src/knot/nameserver/query_module.c b/src/knot/nameserver/query_module.c index 3954558a86..adcc730e1a 100644 --- a/src/knot/nameserver/query_module.c +++ b/src/knot/nameserver/query_module.c @@ -35,7 +35,7 @@ #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)) @@ -235,40 +235,69 @@ int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_cou 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++; @@ -278,46 +307,45 @@ int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_cou _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) } @@ -360,6 +388,15 @@ knotd_conf_t knotd_conf_env(knotd_mod_t *mod, knotd_conf_env_t env) 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) { diff --git a/src/knot/nameserver/query_module.h b/src/knot/nameserver/query_module.h index 52d0fe7eb0..b8541a6670 100644 --- a/src/knot/nameserver/query_module.h +++ b/src/knot/nameserver/query_module.h @@ -71,13 +71,8 @@ typedef char* (*mod_idx_to_str_f)(uint32_t idx, uint32_t count); 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; @@ -92,7 +87,8 @@ struct knotd_mod { 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; };