]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Remove zero initialization of large buffers
authoralessio <alessio@isc.org>
Thu, 30 Jan 2025 11:33:48 +0000 (12:33 +0100)
committerxoranth <alessio@isc.org>
Wed, 2 Apr 2025 14:24:31 +0000 (16:24 +0200)
Profiles show that an high amount of CPU time spent in memset.
By removing zero initalization of certain large buffers we improve
performance in certain authoritative workloads.

lib/dns/qp.c
lib/dns/qpcache.c
lib/dns/qpzone.c

index 3805845b914ca630fbb3e99547d6a6ab2c960644..79a0b8e6eebe1573897587ca0c00bec17e5a3f54 100644 (file)
@@ -1785,10 +1785,14 @@ dns_qpchain_init(dns_qpreadable_t qpr, dns_qpchain_t *chain) {
        REQUIRE(QP_VALID(qp));
        REQUIRE(chain != NULL);
 
-       *chain = (dns_qpchain_t){
-               .magic = QPCHAIN_MAGIC,
-               .qp = qp,
-       };
+       /*
+        * dns_qpchain_t contains a 2kb buffer, which is slow to
+        * zero-initialize. Therefore we avoid designated initializers, and
+        * initialize each field manually.
+        */
+       chain->magic = QPCHAIN_MAGIC;
+       chain->qp = qp;
+       chain->len = 0;
 }
 
 unsigned int
@@ -1821,10 +1825,19 @@ dns_qpiter_init(dns_qpreadable_t qpr, dns_qpiter_t *qpi) {
        dns_qpreader_t *qp = dns_qpreader(qpr);
        REQUIRE(QP_VALID(qp));
        REQUIRE(qpi != NULL);
-       *qpi = (dns_qpiter_t){
-               .qp = qp,
-               .magic = QPITER_MAGIC,
-       };
+
+       /*
+        * dns_qpiter_t contains a 4kb buffer, which is slow to zero-initialize.
+        * Therefore we avoid designated initializers, and initialize each
+        * field manually.
+        */
+       qpi->qp = qp;
+       qpi->sp = 0;
+       qpi->magic = QPITER_MAGIC;
+       /*
+        * The top of the stack must be initialized.
+        */
+       qpi->stack[qpi->sp] = NULL;
 }
 
 /*
index 1b506082039491ead69ae135a40b9addc1a3bc2e..3b7f5680b1d95ca3fb92897901264b7723fba214 100644 (file)
@@ -1458,6 +1458,29 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
         (DNS_TRUST_PENDING((found)->trust) &&             \
          (((options) & DNS_DBFIND_PENDINGOK) == 0)))
 
+static void
+qpc_search_init(qpc_search_t *search, qpcache_t *db, unsigned int options,
+               isc_stdtime_t now) {
+       /*
+        * qpc_search_t contains two structures with large buffers (dns_qpiter_t
+        * and dns_qpchain_t). Those two structures will be initialized later by
+        * dns_qp_lookup anyway.
+        * To avoid the overhead of zero initialization, we avoid designated
+        * initializers and initialize all "small" fields manually.
+        */
+       search->qpdb = (qpcache_t *)db;
+       search->options = options;
+       /*
+        * qpch->in - Init by dns_qp_lookup
+        * qpiter - Init by dns_qp_lookup
+        */
+       search->need_cleanup = false;
+       search->now = now ? now : isc_stdtime_now();
+       search->zonecut = NULL;
+       search->zonecut_header = NULL;
+       search->zonecut_sigheader = NULL;
+}
+
 static isc_result_t
 qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
             dns_rdatatype_t type, unsigned int options, isc_stdtime_t __now,
@@ -1479,11 +1502,9 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
        dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL;
        dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL;
        dns_typepair_t sigtype, negtype;
-       qpc_search_t search = (qpc_search_t){
-               .qpdb = (qpcache_t *)db,
-               .options = options,
-               .now = __now ? __now : isc_stdtime_now(),
-       };
+
+       qpc_search_t search;
+       qpc_search_init(&search, (qpcache_t *)db, options, __now);
 
        REQUIRE(VALID_QPDB((qpcache_t *)db));
        REQUIRE(version == NULL);
index 9ede2dfa4ceb6888d13a07bc82d305161ad1c0b5..4c60d4c17d095941a60bbf1ea42a972d1992e1af 100644 (file)
@@ -3326,6 +3326,34 @@ qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
        return result;
 }
 
+static void
+qpz_search_init(qpz_search_t *search, qpzonedb_t *db, qpz_version_t *version,
+               unsigned int options) {
+       /*
+        * qpz_search_t contains two structures with large buffers (dns_qpiter_t
+        * and dns_qpchain_t). Those two structures will be initialized later by
+        * dns_qp_lookup anyway.
+        * To avoid the overhead of zero initialization, we avoid designated
+        * initializers and initialize all "small" fields manually.
+        */
+       search->qpdb = db;
+       search->version = version;
+       search->qpr = (dns_qpread_t){};
+       search->serial = version->serial;
+       search->options = options;
+       /*
+        * qpch->in -- init in dns_qp_lookup
+        * qpiter -- init in dns_qp_lookup
+        */
+       search->copy_name = false;
+       search->need_cleanup = false;
+       search->wild = false;
+       search->zonecut = NULL;
+       search->zonecut_header = NULL;
+       search->zonecut_sigheader = NULL;
+       dns_fixedname_init(&search->zonecut_name);
+}
+
 static isc_result_t
 qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
            dns_rdatatype_t type, unsigned int options,
@@ -3335,7 +3363,6 @@ qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
        isc_result_t result;
        qpzonedb_t *qpdb = (qpzonedb_t *)db;
        qpznode_t *node = NULL;
-       qpz_search_t search;
        bool cname_ok = true, close_version = false;
        bool maybe_zonecut = false, at_zonecut = false;
        bool wild = false, empty_node = false;
@@ -3361,13 +3388,9 @@ qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
                close_version = true;
        }
 
-       search = (qpz_search_t){
-               .qpdb = (qpzonedb_t *)db,
-               .version = (qpz_version_t *)version,
-               .serial = ((qpz_version_t *)version)->serial,
-               .options = options,
-       };
-       dns_fixedname_init(&search.zonecut_name);
+       qpz_search_t search;
+       qpz_search_init(&search, (qpzonedb_t *)db, (qpz_version_t *)version,
+                       options);
 
        if ((options & DNS_DBFIND_FORCENSEC3) != 0) {
                dns_qpmulti_query(qpdb->nsec3, &search.qpr);