]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
stats/performance: per-thread counters
authorLibor Peltan <libor.peltan@nic.cz>
Thu, 14 May 2020 19:39:18 +0000 (21:39 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 15 May 2020 11:45:01 +0000 (13:45 +0200)
src/knot/common/stats.c
src/knot/common/stats.h
src/knot/ctl/commands.c
src/knot/include/module.h
src/knot/modules/cookies/cookies.c
src/knot/modules/dnstap/dnstap.c
src/knot/modules/noudp/noudp.c
src/knot/modules/rrl/rrl.c
src/knot/modules/stats/stats.c
src/knot/nameserver/query_module.c
src/knot/nameserver/query_module.h

index 7c0e38fe430200817c128426594790e28b6e53f2..5cdfbaea5c0199d98b9656a61b487473a5ce8d8f 100644 (file)
@@ -1,4 +1,4 @@
-/*  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
@@ -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);
                        }
                }
        }
index 2269a4026bf01c11c49a592bfddf72a96c0ac1f8..bd6df6d2267e77f150d58652d4407ca2479cd08a 100644 (file)
@@ -1,4 +1,4 @@
-/*  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
@@ -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.
  */
index d65f9546d2d9ef3602e07f42492cb252340926a3..0b880cd51ea2c9bb2e1be2d001302b5fc253e495 100644 (file)
@@ -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;
                        }
index 7f0a2cc7a05033619d0fbf3feeb85576f8181aa3..626bb6bcd1fc401bdd500d9d9959483a185d79ce 100644 (file)
@@ -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.
  *
index c9a1f3dc8077c41c3ff693d230e9a4a0587f4b34..65950d7752b6a693e200db1ea041e2a742fd1e40 100644 (file)
@@ -1,4 +1,4 @@
-/*  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
@@ -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;
index 630c5dd88663b643bec5845b184f53bc457ea707..35eb2cbbe3ef00819aa39b9ef73c3f031c23cd35 100644 (file)
@@ -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);
index d7fb5b09b0de5c2ccfe2fe5a943ba98682c5f361..cb454b52c628a3651279c38dbbeeb19e15c41bd5 100644 (file)
@@ -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;
index 07ee385ad864dd6daeca14baa0561ab654d399d0..cd68c71b5a42e0d383db07069394cfe60e78496c 100644 (file)
@@ -1,4 +1,4 @@
-/*  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
@@ -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;
        }
 }
index 84d9d77f26fee7bbbea4ac5501f5b30ba2987823..b93c163737bef04c9c6647686efb2890571d7418 100644 (file)
@@ -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;
index 3954558a862e784326930a689fd933d5852fdafc..adcc730e1a597272fa4b822788a465332d68f53d 100644 (file)
@@ -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) {
index 52d0fe7eb0e2f0fbf28547fbd2610392a194469d..b8541a6670a9377e72852c10f948e21ef03d64a6 100644 (file)
@@ -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;
 };