Add low contention stats counter

In the current statistics counter implementation, the statistics are
backed by an array of counters, which are updated via atomic operations.
This leads to contention, especially on high core count
machines.

This commit introduces a new isc_statsmulti_t counter that keeps a
separate array per thread. These counters are then aggregated only when
statistics are queried, shifting work off the critical path.

These changes lead to a ~2% improvement in perflab.
This commit is contained in:
Alessio Podda 2025-09-05 15:39:48 +02:00
parent 9911743d6a
commit ed0ecb62e4
20 changed files with 688 additions and 231 deletions

View file

@ -98,7 +98,7 @@ static dns_dispatch_t *dispatch4 = NULL;
static dns_dispatch_t *dispatch6 = NULL;
static dns_db_t *roothints = NULL;
static isc_stats_t *resstats = NULL;
static dns_stats_t *resquerystats = NULL;
static isc_statsmulti_t *resquerystats = NULL;
static FILE *logfp = NULL;
/* Managers */
@ -2177,7 +2177,7 @@ run_server(void *arg) {
dns_rdatatypestats_create(isc_g_mctx, &resquerystats);
dns_resolver_setquerystats(view->resolver, resquerystats);
dns_stats_detach(&resquerystats);
isc_statsmulti_detach(&resquerystats);
dns_view_freeze(view);

View file

@ -3635,7 +3635,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
bool empty_zones_enable;
const cfg_obj_t *disablelist = NULL;
isc_stats_t *resstats = NULL;
dns_stats_t *resquerystats = NULL;
isc_statsmulti_t *resquerystats = NULL;
isc_histomulti_t *resqueryinrttstats = NULL;
isc_histomulti_t *resqueryoutrttstats = NULL;
bool auto_root = false;
@ -5465,7 +5465,7 @@ cleanup:
isc_stats_detach(&resstats);
}
if (resquerystats != NULL) {
dns_stats_detach(&resquerystats);
isc_statsmulti_detach(&resquerystats);
}
if (resqueryinrttstats != NULL) {
isc_histomulti_detach(&resqueryinrttstats);
@ -10054,12 +10054,12 @@ named_server_resetstatscommand(named_server_t *server, isc_lex_t *lex,
}
if (recursive_high_water) {
isc_stats_set(ns_stats_get(server->sctx->nsstats), 0,
ns_statscounter_recurshighwater);
ns_stats_reset_highwater(server->sctx->nshighwaterstats,
ns_highwater_recursive);
}
if (tcp_high_water) {
isc_stats_set(ns_stats_get(server->sctx->nsstats), 0,
ns_statscounter_tcphighwater);
ns_stats_reset_highwater(server->sctx->nshighwaterstats,
ns_highwater_tcp);
}
return ISC_R_SUCCESS;
@ -11539,9 +11539,9 @@ named_server_status(named_server_t *server, isc_buffer_t *text) {
CHECK(putstr(text, line));
snprintf(line, sizeof(line), "recursive high-water: %u\n",
(unsigned int)ns_stats_get_counter(
server->sctx->nsstats,
ns_statscounter_recurshighwater));
(unsigned int)ns_stats_get_highwater(
server->sctx->nshighwaterstats,
ns_highwater_recursive));
CHECK(putstr(text, line));
snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
@ -11550,8 +11550,8 @@ named_server_status(named_server_t *server, isc_buffer_t *text) {
CHECK(putstr(text, line));
snprintf(line, sizeof(line), "TCP high-water: %u\n",
(unsigned int)ns_stats_get_counter(
server->sctx->nsstats, ns_statscounter_tcphighwater));
(unsigned int)ns_stats_get_highwater(
server->sctx->nshighwaterstats, ns_highwater_tcp));
CHECK(putstr(text, line));
reload_status = atomic_load(&server->reload_status);

View file

@ -140,6 +140,7 @@ user_zonetype(dns_zone_t *zone) {
* below so that they'll be less susceptible to counter name changes.
*/
static const char *nsstats_desc[ns_statscounter_max];
static const char *nshighwaterstats_desc[ns_highwater_max];
static const char *resstats_desc[dns_resstatscounter_max];
static const char *adbstats_desc[dns_adbstats_max];
static const char *zonestats_desc[dns_zonestatscounter_max];
@ -153,6 +154,7 @@ static const char *dnstapstats_desc[dns_dnstapcounter_max];
static const char *gluecachestats_desc[dns_gluecachestatscounter_max];
#if defined(EXTENDED_STATS)
static const char *nsstats_xmldesc[ns_statscounter_max];
static const char *nshighwaterstats_xmldesc[ns_highwater_max];
static const char *resstats_xmldesc[dns_resstatscounter_max];
static const char *adbstats_xmldesc[dns_adbstats_max];
static const char *zonestats_xmldesc[dns_zonestatscounter_max];
@ -167,18 +169,19 @@ static const char *gluecachestats_xmldesc[dns_gluecachestatscounter_max];
static const char *queryrttinstats_xmldesc[dns_queryrttcounter_in_max];
static const char *queryrttoutstats_xmldesc[dns_queryrttcounter_in_max];
#else /* if defined(EXTENDED_STATS) */
#define nsstats_xmldesc NULL
#define resstats_xmldesc NULL
#define adbstats_xmldesc NULL
#define zonestats_xmldesc NULL
#define sockstats_xmldesc NULL
#define dnssecstats_xmldesc NULL
#define udpinsizestats_xmldesc NULL
#define udpoutsizestats_xmldesc NULL
#define tcpinsizestats_xmldesc NULL
#define tcpoutsizestats_xmldesc NULL
#define dnstapstats_xmldesc NULL
#define gluecachestats_xmldesc NULL
#define nsstats_xmldesc NULL
#define nshighwaterstats_xmldesc NULL
#define resstats_xmldesc NULL
#define adbstats_xmldesc NULL
#define zonestats_xmldesc NULL
#define sockstats_xmldesc NULL
#define dnssecstats_xmldesc NULL
#define udpinsizestats_xmldesc NULL
#define udpoutsizestats_xmldesc NULL
#define tcpinsizestats_xmldesc NULL
#define tcpoutsizestats_xmldesc NULL
#define dnstapstats_xmldesc NULL
#define gluecachestats_xmldesc NULL
#endif /* EXTENDED_STATS */
#define TRY0(a) \
@ -194,6 +197,7 @@ static const char *queryrttoutstats_xmldesc[dns_queryrttcounter_in_max];
* nsstats_desc[nsstats_index[0]] will be the description that is shown first.
*/
static int nsstats_index[ns_statscounter_max];
static int nshighwaterstats_index[ns_highwater_max];
static int resstats_index[dns_resstatscounter_max];
static int adbstats_index[dns_adbstats_max];
static int zonestats_index[dns_zonestatscounter_max];
@ -328,8 +332,6 @@ init_desc(void) {
SET_NSSTATDESC(invalidsig, "requests with invalid signature",
"ReqBadSIG");
SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP");
SET_NSSTATDESC(tcphighwater, "TCP connection high-water",
"TCPConnHighWater");
SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej");
SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej");
SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej");
@ -368,8 +370,6 @@ init_desc(void) {
SET_NSSTATDESC(updatebadprereq,
"updates rejected due to prerequisite failure",
"UpdateBadPrereq");
SET_NSSTATDESC(recurshighwater, "Recursive clients high-water",
"RecursHighwater");
SET_NSSTATDESC(recursclients, "recursing clients", "RecursClients");
SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64");
SET_NSSTATDESC(ratedropped, "responses dropped for rate limits",
@ -440,6 +440,32 @@ init_desc(void) {
INSIST(i == ns_statscounter_max);
/* Initialize highwater statistics */
for (i = 0; i < ns_highwater_max; i++) {
nshighwaterstats_desc[i] = NULL;
}
#if defined(EXTENDED_STATS)
for (i = 0; i < ns_highwater_max; i++) {
nshighwaterstats_xmldesc[i] = NULL;
}
#endif /* if defined(EXTENDED_STATS) */
#define SET_NSHIGHWATERSTATDESC(counterid, desc, xmldesc) \
do { \
set_desc(ns_highwater_##counterid, ns_highwater_max, desc, \
nshighwaterstats_desc, xmldesc, \
nshighwaterstats_xmldesc); \
nshighwaterstats_index[i++] = ns_highwater_##counterid; \
} while (0)
i = 0;
SET_NSHIGHWATERSTATDESC(tcp, "TCP connection high-water",
"TCPConnHighWater");
SET_NSHIGHWATERSTATDESC(recursive, "Recursive clients high-water",
"RecursHighwater");
INSIST(i == ns_highwater_max);
/* Initialize resolver statistics */
for (i = 0; i < dns_resstatscounter_max; i++) {
resstats_desc[i] = NULL;
@ -738,6 +764,9 @@ init_desc(void) {
for (i = 0; i < ns_statscounter_max; i++) {
INSIST(nsstats_desc[i] != NULL);
}
for (i = 0; i < ns_highwater_max; i++) {
INSIST(nshighwaterstats_desc[i] != NULL);
}
for (i = 0; i < dns_resstatscounter_max; i++) {
INSIST(resstats_desc[i] != NULL);
}
@ -871,6 +900,25 @@ dump_stats(isc_stats_t *stats, isc_statsformat_t type, void *arg,
values, options);
}
static isc_result_t
dump_statsmulti(isc_statsmulti_t *stats, isc_statsformat_t type, void *arg,
const char *category, const char **desc, int ncounters,
int *indices, uint64_t *values, int options) {
stats_dumparg_t dumparg;
unsigned int multioptions = 0;
dumparg.type = type;
dumparg.ncounters = ncounters;
dumparg.counterindices = indices;
dumparg.countervalues = values;
memset(values, 0, sizeof(values[0]) * ncounters);
isc_statsmulti_dump(stats, generalstat_dump, &dumparg, multioptions);
return dump_counters(type, arg, category, desc, ncounters, indices,
values, options);
}
#if defined(EXTENDED_STATS)
static isc_result_t
dump_histo(isc_histomulti_t *hm, isc_statsformat_t type, void *arg,
@ -1416,7 +1464,7 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
if (statlevel == dns_zonestat_full) {
isc_stats_t *zonestats;
isc_stats_t *gluecachestats;
dns_stats_t *rcvquerystats;
isc_statsmulti_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
uint64_t nsstat_values[ns_statscounter_max];
uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
@ -1901,10 +1949,18 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "nsstat"));
CHECK(dump_stats(ns_stats_get(server->sctx->nsstats),
CHECK(dump_statsmulti(server->sctx->nsstats,
isc_statsformat_xml, writer, NULL,
nsstats_xmldesc, ns_statscounter_max,
nsstats_index, nsstat_values,
ISC_STATSMULTIDUMP_VERBOSE));
/* Add highwater stats to the same nsstat section */
uint64_t nshighwaterstat_values[ns_highwater_max];
CHECK(dump_stats(server->sctx->nshighwaterstats,
isc_statsformat_xml, writer, NULL,
nsstats_xmldesc, ns_statscounter_max,
nsstats_index, nsstat_values,
nshighwaterstats_xmldesc, ns_highwater_max,
nshighwaterstats_index, nshighwaterstat_values,
ISC_STATSDUMP_VERBOSE));
TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */
@ -2086,7 +2142,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
STATS_XML_XFRINS)) != 0))
{
isc_stats_t *istats = NULL;
dns_stats_t *dstats = NULL;
isc_statsmulti_t *dstats = NULL;
dns_adb_t *adb = NULL;
isc_histomulti_t *hmpin = NULL, *hmpout = NULL;
@ -2127,7 +2183,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
&dumparg, 0);
CHECK(dumparg.result);
}
dns_stats_detach(&dstats);
isc_statsmulti_detach(&dstats);
TRY0(xmlTextWriterEndElement(writer));
/* <resstats> */
@ -2492,7 +2548,7 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
if (statlevel == dns_zonestat_full) {
isc_stats_t *zonestats;
isc_stats_t *gluecachestats;
dns_stats_t *rcvquerystats;
isc_statsmulti_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
uint64_t nsstat_values[ns_statscounter_max];
uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
@ -3027,10 +3083,22 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
dumparg.result = ISC_R_SUCCESS;
dumparg.arg = counters;
result = dump_stats(ns_stats_get(server->sctx->nsstats),
result = dump_statsmulti(server->sctx->nsstats,
isc_statsformat_json, counters, NULL,
nsstats_xmldesc, ns_statscounter_max,
nsstats_index, nsstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto cleanup;
}
/* Add highwater stats to the same nsstats section */
uint64_t nshighwaterstat_values[ns_highwater_max];
result = dump_stats(server->sctx->nshighwaterstats,
isc_statsformat_json, counters, NULL,
nsstats_xmldesc, ns_statscounter_max,
nsstats_index, nsstat_values, 0);
nshighwaterstats_xmldesc, ns_highwater_max,
nshighwaterstats_index,
nshighwaterstat_values, 0);
if (result != ISC_R_SUCCESS) {
json_object_put(counters);
goto cleanup;
@ -3160,7 +3228,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
if ((flags & STATS_JSON_SERVER) != 0) {
json_object *res = NULL;
dns_stats_t *dstats = NULL;
isc_statsmulti_t *dstats = NULL;
isc_stats_t *istats = NULL;
res = json_object_new_object();
@ -3209,18 +3277,19 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
json_object_object_add(res, "qtypes",
counters);
dns_stats_detach(&dstats);
isc_statsmulti_detach(&dstats);
}
dstats = dns_db_getrrsetstats(view->cachedb);
if (dstats != NULL) {
dns_stats_t *rrsetstats =
dns_db_getrrsetstats(view->cachedb);
if (rrsetstats != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
dumparg.arg = counters;
dumparg.result = ISC_R_SUCCESS;
dns_rdatasetstats_dump(
dstats, rdatasetstats_dump,
rrsetstats, rdatasetstats_dump,
&dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
@ -4099,7 +4168,7 @@ named_stats_dump(named_server_t *server, FILE *fp) {
fprintf(fp, "++ Outgoing Queries ++\n");
ISC_LIST_FOREACH(server->viewlist, view, link) {
dns_stats_t *dstats = NULL;
isc_statsmulti_t *dstats = NULL;
dns_resolver_getquerystats(view->resolver, &dstats);
if (dstats == NULL) {
continue;
@ -4110,13 +4179,19 @@ named_stats_dump(named_server_t *server, FILE *fp) {
fprintf(fp, "[View: %s]\n", view->name);
}
dns_rdatatypestats_dump(dstats, rdtypestat_dump, &dumparg, 0);
dns_stats_detach(&dstats);
isc_statsmulti_detach(&dstats);
}
fprintf(fp, "++ Name Server Statistics ++\n");
(void)dump_stats(ns_stats_get(server->sctx->nsstats),
isc_statsformat_file, fp, NULL, nsstats_desc,
ns_statscounter_max, nsstats_index, nsstat_values, 0);
(void)dump_statsmulti(server->sctx->nsstats, isc_statsformat_file, fp,
NULL, nsstats_desc, ns_statscounter_max,
nsstats_index, nsstat_values, 0);
/* Add highwater stats to the same Name Server Statistics section */
uint64_t nshighwaterstat_values[ns_highwater_max];
(void)dump_stats(server->sctx->nshighwaterstats, isc_statsformat_file,
fp, NULL, nshighwaterstats_desc, ns_highwater_max,
nshighwaterstats_index, nshighwaterstat_values, 0);
fprintf(fp, "++ Zone Maintenance Statistics ++\n");
(void)dump_stats(server->zonestats, isc_statsformat_file, fp, NULL,

View file

@ -989,7 +989,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_masterformat_t masterformat;
const dns_master_style_t *masterstyle = &dns_master_style_default;
isc_stats_t *zoneqrystats;
dns_stats_t *rcvquerystats;
isc_statsmulti_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
dns_zonestat_level_t statlevel = dns_zonestat_none;
dns_ttl_t maxttl = 0; /* unlimited */
@ -1237,7 +1237,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
}
if (rcvquerystats != NULL) {
dns_stats_detach(&rcvquerystats);
isc_statsmulti_detach(&rcvquerystats);
}
if (dnssecsignstats != NULL) {

View file

@ -53,6 +53,7 @@
#include <isc/loop.h>
#include <isc/refcount.h>
#include <isc/stats.h>
#include <isc/statsmulti.h>
#include <isc/tls.h>
#include <isc/types.h>
@ -599,7 +600,7 @@ dns_resolver_incstats(dns_resolver_t *res, isc_statscounter_t counter);
*/
void
dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats);
dns_resolver_setquerystats(dns_resolver_t *res, isc_statsmulti_t *stats);
/*%<
* Set a statistics counter set of rdata type, 'stats', for 'res'. Once the
* statistic set is installed, the resolver will count outgoing queries
@ -611,7 +612,7 @@ dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats);
*/
void
dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp);
dns_resolver_getquerystats(dns_resolver_t *res, isc_statsmulti_t **statsp);
/*%<
* Get the rdatatype statistics counter set for 'res'. If a statistics set is
* set '*statsp' will be attached to the set; otherwise, '*statsp' will be

View file

@ -18,6 +18,7 @@
#include <inttypes.h>
#include <isc/histo.h>
#include <isc/statsmulti.h>
#include <dns/resolver.h>
#include <dns/types.h>
@ -285,7 +286,7 @@ dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters);
*/
void
dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp);
dns_rdatatypestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp);
/*%<
* Create a statistics counter structure per rdatatype.
*
@ -307,7 +308,7 @@ dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp);
*/
void
dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp);
dns_opcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp);
/*%<
* Create a statistics counter structure per opcode.
*
@ -318,7 +319,7 @@ dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp);
*/
void
dns_rcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp);
dns_rcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp);
/*%<
* Create a statistics counter structure per assigned rcode.
*
@ -373,12 +374,13 @@ dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter);
*/
void
dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type);
dns_rdatatypestats_increment(isc_statsmulti_t *stats, dns_rdatatype_t type);
/*%<
* Increment the statistics counter for 'type'.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_rdatatypestats_create().
*\li 'stats' is a valid isc_statsmulti_t created by
* dns_rdatatypestats_create().
*/
void
@ -403,21 +405,21 @@ dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype);
*/
void
dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code);
dns_opcodestats_increment(isc_statsmulti_t *stats, dns_opcode_t code);
/*%<
* Increment the statistics counter for 'code'.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_opcodestats_create().
*\li 'stats' is a valid isc_statsmulti_t created by dns_opcodestats_create().
*/
void
dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code);
dns_rcodestats_increment(isc_statsmulti_t *stats, dns_rcode_t code);
/*%<
* Increment the statistics counter for 'code'.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_rcodestats_create().
*\li 'stats' is a valid isc_statsmulti_t created by dns_rcodestats_create().
*/
void
@ -457,8 +459,9 @@ dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn,
*/
void
dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
void *arg, unsigned int options);
dns_rdatatypestats_dump(isc_statsmulti_t *stats,
dns_rdatatypestats_dumper_t dump_fn, void *arg,
unsigned int options);
/*%<
* Dump the current statistics counters in a specified way. For each counter
* in stats, dump_fn is called with the corresponding type in the form of
@ -467,7 +470,8 @@ dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
* the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_generalstats_create().
*\li 'stats' is a valid isc_statsmulti_t created by
* dns_rdatatypestats_create().
*/
void
@ -500,7 +504,7 @@ dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation,
*/
void
dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn,
dns_opcodestats_dump(isc_statsmulti_t *stats, dns_opcodestats_dumper_t dump_fn,
void *arg, unsigned int options);
/*%<
* Dump the current statistics counters in a specified way. For each counter
@ -510,11 +514,11 @@ dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn,
* such counters are dumped.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_generalstats_create().
*\li 'stats' is a valid isc_statsmulti_t created by dns_opcodestats_create().
*/
void
dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn,
dns_rcodestats_dump(isc_statsmulti_t *stats, dns_rcodestats_dumper_t dump_fn,
void *arg, unsigned int options);
/*%<
* Dump the current statistics counters in a specified way. For each counter
@ -524,5 +528,5 @@ dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn,
* such counters are dumped.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_generalstats_create().
*\li 'stats' is a valid isc_statsmulti_t created by dns_rcodestats_create().
*/

View file

@ -25,6 +25,7 @@
#include <isc/formatcheck.h>
#include <isc/rwlock.h>
#include <isc/statsmulti.h>
#include <isc/tls.h>
#include <dns/catz.h>
@ -1966,7 +1967,7 @@ void
dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats);
void
dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats);
dns_zone_setrcvquerystats(dns_zone_t *zone, isc_statsmulti_t *stats);
void
dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats);
@ -1984,7 +1985,7 @@ dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats);
isc_stats_t *
dns_zone_getrequeststats(dns_zone_t *zone);
dns_stats_t *
isc_statsmulti_t *
dns_zone_getrcvquerystats(dns_zone_t *zone);
dns_stats_t *

View file

@ -597,7 +597,7 @@ struct dns_resolver {
unsigned int maxqueries;
isc_result_t quotaresp[2];
isc_stats_t *stats;
dns_stats_t *querystats;
isc_statsmulti_t *querystats;
isc_histomulti_t *queryinrttstats;
isc_histomulti_t *queryoutrttstats;
@ -9642,7 +9642,7 @@ dns_resolver__destroy(dns_resolver_t *res) {
isc_histomulti_detach(&res->queryinrttstats);
}
if (res->querystats != NULL) {
dns_stats_detach(&res->querystats);
isc_statsmulti_detach(&res->querystats);
}
if (res->stats != NULL) {
isc_stats_detach(&res->stats);
@ -10866,20 +10866,20 @@ dns_resolver_incstats(dns_resolver_t *res, isc_statscounter_t counter) {
}
void
dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats) {
dns_resolver_setquerystats(dns_resolver_t *res, isc_statsmulti_t *stats) {
REQUIRE(VALID_RESOLVER(res));
REQUIRE(res->querystats == NULL);
dns_stats_attach(stats, &res->querystats);
isc_statsmulti_attach(stats, &res->querystats);
}
void
dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp) {
dns_resolver_getquerystats(dns_resolver_t *res, isc_statsmulti_t **statsp) {
REQUIRE(VALID_RESOLVER(res));
REQUIRE(statsp != NULL && *statsp == NULL);
if (res->querystats != NULL) {
dns_stats_attach(res->querystats, statsp);
isc_statsmulti_attach(res->querystats, statsp);
}
}

View file

@ -21,6 +21,7 @@
#include <isc/mem.h>
#include <isc/refcount.h>
#include <isc/stats.h>
#include <isc/statsmulti.h>
#include <isc/util.h>
#include <dns/opcode.h>
@ -189,15 +190,10 @@ dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) {
}
void
dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
dns_rdatatypestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
/*
* Create rdtype statistics for the first 255 RRtypes,
* plus one additional for other RRtypes.
*/
create_stats(mctx, dns_statstype_rdtype, RDTYPECOUNTER_MAXTYPE + 1,
statsp);
isc_statsmulti_create(mctx, statsp, RDTYPECOUNTER_MAXTYPE + 1);
}
void
@ -209,18 +205,17 @@ dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
}
void
dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
dns_opcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
create_stats(mctx, dns_statstype_opcode, 16, statsp);
isc_statsmulti_create(mctx, statsp, 16);
}
void
dns_rcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
dns_rcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
create_stats(mctx, dns_statstype_rcode, dns_rcode_badcookie + 1,
statsp);
isc_statsmulti_create(mctx, statsp, dns_rcode_badcookie + 1);
}
void
@ -254,13 +249,13 @@ rdatatype2counter(dns_rdatatype_t type) {
}
void
dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) {
dns_rdatatypestats_increment(isc_statsmulti_t *stats, dns_rdatatype_t type) {
isc_statscounter_t counter;
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
REQUIRE(stats != NULL);
counter = rdatatype2counter(type);
isc_stats_increment(stats->counters, counter);
isc_statsmulti_increment(stats, counter);
}
static void
@ -332,18 +327,18 @@ dns_rdatasetstats_decrement(dns_stats_t *stats,
}
void
dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) {
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
dns_opcodestats_increment(isc_statsmulti_t *stats, dns_opcode_t code) {
REQUIRE(stats != NULL);
isc_stats_increment(stats->counters, (isc_statscounter_t)code);
isc_statsmulti_increment(stats, (isc_statscounter_t)code);
}
void
dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code) {
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rcode);
dns_rcodestats_increment(isc_statsmulti_t *stats, dns_rcode_t code) {
REQUIRE(stats != NULL);
if (code <= dns_rcode_badcookie) {
isc_stats_increment(stats->counters, (isc_statscounter_t)code);
isc_statsmulti_increment(stats, (isc_statscounter_t)code);
}
}
@ -460,14 +455,15 @@ rdatatype_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
}
void
dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
void *arg0, unsigned int options) {
dns_rdatatypestats_dump(isc_statsmulti_t *stats,
dns_rdatatypestats_dumper_t dump_fn, void *arg0,
unsigned int options) {
rdatadumparg_t arg;
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype);
REQUIRE(stats != NULL);
arg.fn = dump_fn;
arg.arg = arg0;
isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options);
isc_statsmulti_dump(stats, rdatatype_dumpcb, &arg, options);
}
static void
@ -584,25 +580,25 @@ rcode_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
}
void
dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn,
dns_opcodestats_dump(isc_statsmulti_t *stats, dns_opcodestats_dumper_t dump_fn,
void *arg0, unsigned int options) {
opcodedumparg_t arg;
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
REQUIRE(stats != NULL);
arg.fn = dump_fn;
arg.arg = arg0;
isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options);
isc_statsmulti_dump(stats, opcode_dumpcb, &arg, options);
}
void
dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn,
dns_rcodestats_dump(isc_statsmulti_t *stats, dns_rcodestats_dumper_t dump_fn,
void *arg0, unsigned int options) {
rcodedumparg_t arg;
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rcode);
REQUIRE(stats != NULL);
arg.fn = dump_fn;
arg.arg = arg0;
isc_stats_dump(stats->counters, rcode_dumpcb, &arg, options);
isc_statsmulti_dump(stats, rcode_dumpcb, &arg, options);
}

View file

@ -387,7 +387,7 @@ struct dns_zone {
dns_zonestat_level_t statlevel;
bool requeststats_on;
isc_stats_t *requeststats;
dns_stats_t *rcvquerystats;
isc_statsmulti_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
dns_isselffunc_t isself;
void *isselfarg;
@ -1201,7 +1201,7 @@ dns__zone_free(dns_zone_t *zone) {
isc_stats_detach(&zone->requeststats);
}
if (zone->rcvquerystats != NULL) {
dns_stats_detach(&zone->rcvquerystats);
isc_statsmulti_detach(&zone->rcvquerystats);
}
if (zone->dnssecsignstats != NULL) {
dns_stats_detach(&zone->dnssecsignstats);
@ -18990,13 +18990,13 @@ dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) {
}
void
dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats) {
dns_zone_setrcvquerystats(dns_zone_t *zone, isc_statsmulti_t *stats) {
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
if (zone->requeststats_on && stats != NULL) {
if (zone->rcvquerystats == NULL) {
dns_stats_attach(stats, &zone->rcvquerystats);
isc_statsmulti_attach(stats, &zone->rcvquerystats);
zone->requeststats_on = true;
}
}
@ -19042,7 +19042,7 @@ dns_zone_getrequeststats(dns_zone_t *zone) {
* Return the received query stats bucket
* see note from dns_zone_getrequeststats()
*/
dns_stats_t *
isc_statsmulti_t *
dns_zone_getrcvquerystats(dns_zone_t *zone) {
if (zone->requeststats_on) {
return zone->rcvquerystats;

View file

@ -0,0 +1,120 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
/*! \file isc/statsmulti.h */
#include <inttypes.h>
#include <isc/types.h>
typedef struct isc_statsmulti isc_statsmulti_t; /*%< Statistics Multi */
/*%<
* Flag(s) for isc_statsmulti_dump().
*/
#define ISC_STATSMULTIDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */
/*%<
* Dump callback type.
*/
typedef void (*isc_statsmulti_dumper_t)(isc_statscounter_t, uint64_t, void *);
void
isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp,
int ncounters);
/*%<
* Create a statistics counter structure for additive counters.
* All counters are additive (sum across threads).
*
* Requires:
*\li 'mctx' must be a valid memory context.
*
*\li 'statsp' != NULL && '*statsp' == NULL.
*/
void
isc_statsmulti_attach(isc_statsmulti_t *stats, isc_statsmulti_t **statsp);
/*%<
* Attach to a statistics set.
*
* Requires:
*\li 'stats' is a valid isc_statsmulti_t.
*
*\li 'statsp' != NULL && '*statsp' == NULL
*/
void
isc_statsmulti_detach(isc_statsmulti_t **statsp);
/*%<
* Detaches from the statistics set.
*
* Requires:
*\li 'statsp' != NULL and '*statsp' is a valid isc_statsmulti_t.
*/
void
isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter);
/*%<
* Increment the counter-th counter of stats.
*
* Requires:
*\li 'stats' is a valid isc_statsmulti_t.
*
*\li counter is less than ncounters.
*/
void
isc_statsmulti_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter);
/*%<
* Decrement the counter-th counter of stats.
*
* Requires:
*\li 'stats' is a valid isc_statsmulti_t.
*
*\li counter is less than ncounters.
*/
void
isc_statsmulti_dump(isc_statsmulti_t *stats, isc_statsmulti_dumper_t dump_fn,
void *arg, unsigned int options);
/*%<
* Dump the current statistics counters in a specified way. For each counter
* in stats, dump_fn is called with its current value and the given argument
* arg. By default counters that have a value of 0 is skipped; if options has
* the ISC_STATSMULTIDUMP_VERBOSE flag, even such counters are dumped.
*
* Requires:
*\li 'stats' is a valid isc_statsmulti_t.
*/
isc_statscounter_t
isc_statsmulti_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter);
/*%<
* Returns value currently stored in counter.
*
* Requires:
*\li 'stats' is a valid isc_statsmulti_t.
*
*\li counter is less than ncounters.
*/
void
isc_statsmulti_clear(isc_statsmulti_t *stats);
/*%<
* Set all counters to zero.
*
* Requires:
*\li 'stats' is a valid isc_statsmulti_t.
*/

View file

@ -123,6 +123,7 @@ isc_srcset.add(
'signal.c',
'sockaddr.c',
'stats.c',
'statsmulti.c',
'stdio.c',
'stdtime.c',
'string.c',

187
lib/isc/statsmulti.c Normal file
View file

@ -0,0 +1,187 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
/*! \file */
#include <inttypes.h>
#include <string.h>
#include <isc/atomic.h>
#include <isc/buffer.h>
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/os.h>
#include <isc/refcount.h>
#include <isc/stats.h>
#include <isc/statsmulti.h>
#include <isc/tid.h>
#include <isc/util.h>
#define ISC_STATSMULTI_MAGIC ISC_MAGIC('S', 'M', 'u', 'l')
#define ISC_STATSMULTI_VALID(x) ISC_MAGIC_VALID(x, ISC_STATSMULTI_MAGIC)
/*
* Same constraint as stats.c
*/
STATIC_ASSERT(sizeof(isc_statscounter_t) <= sizeof(uint64_t),
"Exported statistics must fit into the statistic counter size");
struct isc_statsmulti {
unsigned int magic;
isc_mem_t *mctx;
isc_refcount_t references;
int n_counters;
int per_thread_capacity;
int num_threads_plus_one;
isc_atomic_statscounter_t *counters;
};
static int
to_index(isc_statsmulti_t *stats, isc_tid_t tid,
isc_statscounter_t internal_counter) {
int thread_id = tid + 1;
if (thread_id >= stats->num_threads_plus_one) {
thread_id = 0;
}
return thread_id * stats->per_thread_capacity + internal_counter;
}
void
isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp,
int ncounters) {
REQUIRE(statsp != NULL && *statsp == NULL);
size_t size_in_bytes = sizeof(isc_atomic_statscounter_t) * ncounters;
size_t rounded_up = (size_in_bytes + 63) & ~63; /* Round up to next
multiple of 64 */
int per_thread_capacity = rounded_up /
sizeof(isc_atomic_statscounter_t);
int num_threads_plus_one = isc_tid_count() + 1;
isc_statsmulti_t *stats = isc_mem_get(mctx, sizeof(*stats));
*stats = (isc_statsmulti_t){
.magic = ISC_STATSMULTI_MAGIC,
.counters = isc_mem_cget(
mctx, per_thread_capacity * num_threads_plus_one,
sizeof(isc_atomic_statscounter_t)),
.mctx = isc_mem_ref(mctx),
.n_counters = ncounters,
.num_threads_plus_one = num_threads_plus_one,
.per_thread_capacity = per_thread_capacity,
.references = ISC_REFCOUNT_INITIALIZER(1),
};
*statsp = stats;
}
void
isc_statsmulti_attach(isc_statsmulti_t *stats, isc_statsmulti_t **statsp) {
REQUIRE(ISC_STATSMULTI_VALID(stats));
REQUIRE(statsp != NULL && *statsp == NULL);
isc_refcount_increment(&stats->references);
*statsp = stats;
}
void
isc_statsmulti_detach(isc_statsmulti_t **statsp) {
isc_statsmulti_t *stats;
REQUIRE(statsp != NULL && ISC_STATSMULTI_VALID(*statsp));
stats = *statsp;
*statsp = NULL;
if (isc_refcount_decrement(&stats->references) == 1) {
isc_refcount_destroy(&stats->references);
size_t alloc_size = stats->per_thread_capacity *
stats->num_threads_plus_one *
sizeof(isc_atomic_statscounter_t);
isc_mem_put(stats->mctx, stats->counters, alloc_size);
isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
}
}
void
isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) {
REQUIRE(ISC_STATSMULTI_VALID(stats));
REQUIRE(counter < stats->n_counters);
int index = to_index(stats, isc_tid(), counter);
if (isc_tid() == -1) {
atomic_fetch_add_relaxed(&stats->counters[index], 1);
} else {
isc_atomic_statscounter_t *ptr = &stats->counters[index];
atomic_store_relaxed(ptr, atomic_load_relaxed(ptr) + 1);
}
}
void
isc_statsmulti_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) {
REQUIRE(ISC_STATSMULTI_VALID(stats));
REQUIRE(counter < stats->n_counters);
int index = to_index(stats, isc_tid(), counter);
if (isc_tid() == -1) {
atomic_fetch_sub_relaxed(&stats->counters[index], 1);
} else {
isc_atomic_statscounter_t *ptr = &stats->counters[index];
int_fast64_t tmp = atomic_load_relaxed(ptr);
atomic_store_relaxed(ptr, tmp - 1);
}
}
void
isc_statsmulti_dump(isc_statsmulti_t *stats, isc_statsmulti_dumper_t dump_fn,
void *arg, unsigned int options) {
REQUIRE(ISC_STATSMULTI_VALID(stats));
for (int counter = 0; counter < stats->n_counters; counter++) {
isc_statscounter_t total = isc_statsmulti_get_counter(stats,
counter);
if ((options & ISC_STATSMULTIDUMP_VERBOSE) == 0 && total == 0) {
continue;
}
dump_fn((isc_statscounter_t)counter, total, arg);
}
}
isc_statscounter_t
isc_statsmulti_get_counter(isc_statsmulti_t *stats,
isc_statscounter_t counter) {
REQUIRE(ISC_STATSMULTI_VALID(stats));
REQUIRE(counter < stats->n_counters);
int idx_0 = to_index(stats, 0, counter);
isc_statscounter_t total = atomic_load_acquire(&stats->counters[idx_0]);
for (int thread = 1; thread < stats->num_threads_plus_one; thread++) {
int index = to_index(stats, thread, counter);
total += atomic_load_relaxed(&stats->counters[index]);
}
return total;
}
void
isc_statsmulti_clear(isc_statsmulti_t *stats) {
REQUIRE(ISC_STATSMULTI_VALID(stats));
for (int idx = 0;
idx < stats->per_thread_capacity * stats->num_threads_plus_one;
idx++)
{
atomic_store_release(&stats->counters[idx], 0);
}
}

View file

@ -2515,7 +2515,7 @@ ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
}
tcpquota = isc_quota_getused(&sctx->tcpquota);
ns_stats_update_if_greater(sctx->nsstats, ns_statscounter_tcphighwater,
ns_stats_update_if_greater(sctx->nshighwaterstats, ns_highwater_tcp,
tcpquota);
return ISC_R_SUCCESS;

View file

@ -25,6 +25,7 @@
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/sockaddr.h>
#include <isc/statsmulti.h>
#include <isc/types.h>
#include <dns/acl.h>
@ -120,10 +121,11 @@ struct ns_server {
ns_matchview_t matchingview;
/*% Stats counters */
ns_stats_t *nsstats;
dns_stats_t *rcvquerystats;
dns_stats_t *opcodestats;
dns_stats_t *rcodestats;
isc_statsmulti_t *nsstats;
isc_stats_t *nshighwaterstats;
isc_statsmulti_t *rcvquerystats;
isc_statsmulti_t *opcodestats;
isc_statsmulti_t *rcodestats;
isc_histomulti_t *udpinstats4;
isc_histomulti_t *udpoutstats4;

View file

@ -17,6 +17,7 @@
#include <isc/mem.h>
#include <isc/stats.h>
#include <isc/statsmulti.h>
#include <ns/types.h>
@ -107,50 +108,54 @@ enum {
ns_statscounter_prefetch = 64,
ns_statscounter_keytagopt = 65,
ns_statscounter_tcphighwater = 66,
ns_statscounter_reclimitdropped = 66,
ns_statscounter_reclimitdropped = 67,
ns_statscounter_updatequota = 67,
ns_statscounter_dot = 68,
ns_statscounter_doh = 69,
ns_statscounter_dohplain = 70,
ns_statscounter_updatequota = 68,
ns_statscounter_proxyudp = 71,
ns_statscounter_proxytcp = 72,
ns_statscounter_proxydot = 73,
ns_statscounter_proxydoh = 74,
ns_statscounter_proxydohplain = 75,
ns_statscounter_encryptedproxydot = 76,
ns_statscounter_encryptedproxydoh = 77,
ns_statscounter_recurshighwater = 69,
ns_statscounter_max = 78,
};
ns_statscounter_dot = 70,
ns_statscounter_doh = 71,
ns_statscounter_dohplain = 72,
/*%
* Highwater statistics counters. Used as isc_statscounter_t values
* for the separate highwater stats structure.
*/
enum {
ns_highwater_tcp = 0,
ns_highwater_recursive = 1,
ns_statscounter_proxyudp = 73,
ns_statscounter_proxytcp = 74,
ns_statscounter_proxydot = 75,
ns_statscounter_proxydoh = 76,
ns_statscounter_proxydohplain = 77,
ns_statscounter_encryptedproxydot = 78,
ns_statscounter_encryptedproxydoh = 79,
ns_statscounter_max = 80,
ns_highwater_max = 2,
};
void
ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp);
ns_stats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp,
isc_stats_t **hwstatsp);
void
ns_stats_detach(ns_stats_t **statsp);
ns_stats_increment(isc_statsmulti_t *stats, isc_statscounter_t counter);
void
ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp);
isc_statscounter_t
ns_stats_increment(ns_stats_t *stats, isc_statscounter_t counter);
ns_stats_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter);
void
ns_stats_decrement(ns_stats_t *stats, isc_statscounter_t counter);
isc_stats_t *
ns_stats_get(ns_stats_t *stats);
void
ns_stats_update_if_greater(ns_stats_t *stats, isc_statscounter_t counter,
ns_stats_update_if_greater(isc_stats_t *hwstats, isc_statscounter_t counter,
isc_statscounter_t value);
isc_statscounter_t
ns_stats_get_counter(ns_stats_t *stats, isc_statscounter_t counter);
ns_stats_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter);
isc_statscounter_t
ns_stats_get_highwater(isc_stats_t *hwstats, isc_statscounter_t counter);
void
ns_stats_reset_highwater(isc_stats_t *hwstats, isc_statscounter_t counter);

View file

@ -546,7 +546,7 @@ inc_stats(ns_client_t *client, isc_statscounter_t counter) {
dns_rdatatype_t qtype;
dns_rdataset_t *rdataset;
isc_stats_t *zonestats;
dns_stats_t *querystats = NULL;
isc_statsmulti_t *querystats = NULL;
ns_stats_increment(client->manager->sctx->nsstats, counter);
@ -2587,7 +2587,6 @@ free_fresp(ns_client_t *client, dns_fetchresponse_t **frespp) {
static isc_result_t
recursionquotatype_attach(ns_client_t *client, bool soft_limit) {
isc_statscounter_t recurscount;
isc_result_t result;
result = isc_quota_acquire(&client->manager->sctx->recursionquota);
@ -2610,12 +2609,13 @@ recursionquotatype_attach(ns_client_t *client, bool soft_limit) {
return result;
}
recurscount = ns_stats_increment(client->manager->sctx->nsstats,
ns_statscounter_recursclients);
ns_stats_increment(client->manager->sctx->nsstats,
ns_statscounter_recursclients);
isc_statscounter_t recurscount = ns_stats_get_counter(
client->manager->sctx->nsstats, ns_statscounter_recursclients);
ns_stats_update_if_greater(client->manager->sctx->nsstats,
ns_statscounter_recurshighwater,
recurscount + 1);
ns_stats_update_if_greater(client->manager->sctx->nshighwaterstats,
ns_highwater_recursive, recurscount);
return result;
}

View file

@ -70,7 +70,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview,
ISC_LIST_INIT(sctx->http_quotas);
isc_mutex_init(&sctx->http_quotas_lock);
ns_stats_create(mctx, ns_statscounter_max, &sctx->nsstats);
ns_stats_create(mctx, &sctx->nsstats, &sctx->nshighwaterstats);
dns_rdatatypestats_create(mctx, &sctx->rcvquerystats);
@ -162,17 +162,21 @@ ns_server_detach(ns_server_t **sctxp) {
}
if (sctx->nsstats != NULL) {
ns_stats_detach(&sctx->nsstats);
isc_statsmulti_detach(&sctx->nsstats);
}
if (sctx->nshighwaterstats != NULL) {
isc_stats_detach(&sctx->nshighwaterstats);
}
if (sctx->rcvquerystats != NULL) {
dns_stats_detach(&sctx->rcvquerystats);
isc_statsmulti_detach(&sctx->rcvquerystats);
}
if (sctx->opcodestats != NULL) {
dns_stats_detach(&sctx->opcodestats);
isc_statsmulti_detach(&sctx->opcodestats);
}
if (sctx->rcodestats != NULL) {
dns_stats_detach(&sctx->rcodestats);
isc_statsmulti_detach(&sctx->rcodestats);
}
if (sctx->udpinstats4 != NULL) {

View file

@ -13,103 +13,65 @@
/*! \file */
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/refcount.h>
#include <isc/stats.h>
#include <isc/statsmulti.h>
#include <isc/util.h>
#include <ns/stats.h>
#define NS_STATS_MAGIC ISC_MAGIC('N', 's', 't', 't')
#define NS_STATS_VALID(x) ISC_MAGIC_VALID(x, NS_STATS_MAGIC)
struct ns_stats {
/*% Unlocked */
unsigned int magic;
isc_mem_t *mctx;
isc_stats_t *counters;
isc_refcount_t references;
};
void
ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp) {
REQUIRE(NS_STATS_VALID(stats));
ns_stats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp,
isc_stats_t **hwstatsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
REQUIRE(hwstatsp != NULL && *hwstatsp == NULL);
isc_refcount_increment(&stats->references);
*statsp = stats;
}
void
ns_stats_detach(ns_stats_t **statsp) {
ns_stats_t *stats;
REQUIRE(statsp != NULL && NS_STATS_VALID(*statsp));
stats = *statsp;
*statsp = NULL;
if (isc_refcount_decrement(&stats->references) == 1) {
isc_stats_detach(&stats->counters);
isc_refcount_destroy(&stats->references);
isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
}
}
void
ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
ns_stats_t *stats = isc_mem_get(mctx, sizeof(*stats));
stats->counters = NULL;
isc_refcount_init(&stats->references, 1);
isc_stats_create(mctx, &stats->counters, ncounters);
stats->magic = NS_STATS_MAGIC;
stats->mctx = NULL;
isc_mem_attach(mctx, &stats->mctx);
*statsp = stats;
isc_statsmulti_create(mctx, statsp, ns_statscounter_max);
isc_stats_create(mctx, hwstatsp, ns_highwater_max);
}
/*%
* Increment/Decrement methods
*/
isc_statscounter_t
ns_stats_increment(ns_stats_t *stats, isc_statscounter_t counter) {
REQUIRE(NS_STATS_VALID(stats));
void
ns_stats_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) {
REQUIRE(stats != NULL);
return isc_stats_increment(stats->counters, counter);
isc_statsmulti_increment(stats, counter);
}
void
ns_stats_decrement(ns_stats_t *stats, isc_statscounter_t counter) {
REQUIRE(NS_STATS_VALID(stats));
ns_stats_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) {
REQUIRE(stats != NULL);
isc_stats_decrement(stats->counters, counter);
}
isc_stats_t *
ns_stats_get(ns_stats_t *stats) {
REQUIRE(NS_STATS_VALID(stats));
return stats->counters;
isc_statsmulti_decrement(stats, counter);
}
void
ns_stats_update_if_greater(ns_stats_t *stats, isc_statscounter_t counter,
ns_stats_update_if_greater(isc_stats_t *hwstats, isc_statscounter_t counter,
isc_statscounter_t value) {
REQUIRE(NS_STATS_VALID(stats));
REQUIRE(hwstats != NULL);
isc_stats_update_if_greater(stats->counters, counter, value);
isc_stats_update_if_greater(hwstats, counter, value);
}
isc_statscounter_t
ns_stats_get_counter(ns_stats_t *stats, isc_statscounter_t counter) {
REQUIRE(NS_STATS_VALID(stats));
ns_stats_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter) {
REQUIRE(stats != NULL);
return isc_stats_get_counter(stats->counters, counter);
return isc_statsmulti_get_counter(stats, counter);
}
isc_statscounter_t
ns_stats_get_highwater(isc_stats_t *hwstats, isc_statscounter_t counter) {
REQUIRE(hwstats != NULL);
return isc_stats_get_counter(hwstats, counter);
}
void
ns_stats_reset_highwater(isc_stats_t *hwstats, isc_statscounter_t counter) {
REQUIRE(hwstats != NULL);
isc_stats_set(hwstats, 0, counter);
}

View file

@ -22,10 +22,16 @@
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/async.h>
#include <isc/atomic.h>
#include <isc/lib.h>
#include <isc/loop.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/stats.h>
#include <isc/statsmulti.h>
#include <isc/time.h>
#include <isc/timer.h>
#include <isc/util.h>
#include <tests/isc.h>
@ -92,9 +98,102 @@ ISC_RUN_TEST_IMPL(isc_stats_basic) {
isc_stats_detach(&stats);
}
/* test statsmulti */
ISC_RUN_TEST_IMPL(isc_statsmulti_basic) {
isc_statsmulti_t *stats = NULL;
/* Create with 3 additive counters */
isc_statsmulti_create(isc_g_mctx, &stats, 3);
/* Test increment on additive counters */
for (int i = 0; i < 3; i++) {
isc_statsmulti_increment(stats, i);
assert_int_equal(isc_statsmulti_get_counter(stats, i), 1);
isc_statsmulti_increment(stats, i);
assert_int_equal(isc_statsmulti_get_counter(stats, i), 2);
}
/* Test decrement on additive counters */
for (int i = 0; i < 3; i++) {
isc_statsmulti_decrement(stats, i);
assert_int_equal(isc_statsmulti_get_counter(stats, i), 1);
isc_statsmulti_decrement(stats, i);
assert_int_equal(isc_statsmulti_get_counter(stats, i), 0);
}
/* Test clear */
isc_statsmulti_increment(stats, 0);
isc_statsmulti_increment(stats, 1);
isc_statsmulti_clear(stats);
for (int i = 0; i < 3; i++) {
assert_int_equal(isc_statsmulti_get_counter(stats, i), 0);
}
isc_statsmulti_detach(&stats);
}
/* test statsmulti with multiple threads */
static isc_statsmulti_t *mt_stats = NULL;
static atomic_uint_fast32_t mt_workers_completed = 0;
static int mt_counter_id = 0; /* Global counter ID */
#define MT_INCREMENTS_PER_THREAD 100000
static void
mt_increment_worker(void *arg ISC_ATTR_UNUSED) {
/* Do exactly 100,000 increments */
for (int i = 0; i < MT_INCREMENTS_PER_THREAD; i++) {
isc_statsmulti_increment(mt_stats, mt_counter_id);
}
/* Signal completion and check if we're the last one */
uint32_t completed = atomic_fetch_add(&mt_workers_completed, 1) + 1;
if (completed == isc_loopmgr_nloops()) {
/* Last worker shuts down the loop manager */
isc_loopmgr_shutdown();
}
}
static void
mt_setup_workers(void *arg ISC_ATTR_UNUSED) {
/* Start workers on each loop */
for (size_t i = 0; i < isc_loopmgr_nloops(); i++) {
isc_async_run(isc_loop_get(i), mt_increment_worker, NULL);
}
}
ISC_RUN_TEST_IMPL(isc_statsmulti_multithread) {
atomic_store(&mt_workers_completed, 0);
/* Create stats with 1 additive counter */
isc_statsmulti_create(isc_g_mctx, &mt_stats, 1);
isc_loop_setup(isc_loop_main(), mt_setup_workers, NULL);
isc_loopmgr_run();
/* Check results - should be exactly threads * increments per thread */
uint64_t actual_count = isc_statsmulti_get_counter(mt_stats, 0);
uint64_t expected_total = (uint64_t)isc_loopmgr_nloops() *
MT_INCREMENTS_PER_THREAD;
/* Verify no increments were lost */
assert_int_equal(actual_count, expected_total);
assert_true(actual_count > 0);
/* Verify all workers completed */
assert_int_equal(atomic_load(&mt_workers_completed),
isc_loopmgr_nloops());
/* Cleanup */
isc_statsmulti_detach(&mt_stats);
}
ISC_TEST_LIST_START
ISC_TEST_ENTRY(isc_stats_basic)
ISC_TEST_ENTRY(isc_statsmulti_basic)
ISC_TEST_ENTRY_CUSTOM(isc_statsmulti_multithread, setup_loopmgr,
teardown_loopmgr)
ISC_TEST_LIST_END