Commit graph

26 commits

Author SHA1 Message Date
Ondřej Surý
d9048b3db1
Remove ISC_MEM_ZERO and isc_mem_*x() API
Use the new isc_mem_c*() calloc-like API for allocations that are
zeroed.

In turn, this also fixes couple of incorrect usage of the ISC_MEM_ZERO
for structures that need to be zeroed explicitly.

There are few places where isc_mem_cput() is used on structures with a
flexible member (or similar).
2023-08-31 22:08:35 +02:00
Ondřej Surý
55c29b8d83
Do extra manual isc_mem_cget() conversions
Some of the cases weren't caught by the coccinelle and there were some
places where cget+memmove() could get converted to simple creget().
2023-08-31 22:08:35 +02:00
Evan Hunt
62d70966f2 remove dns_name_towire2()
we don't need two versions of dns_name_towire(), we can just add NULL
to the calls that don't need to specify a compression offset.
2023-08-31 10:29:16 -07:00
Tony Finch
b38c71961d
Improve qp-trie leaf return values
Make the `pval_r` and `ival_r` out arguments optional.

Add `pval_r` and `ival_r` out arguments to `dns_qp_deletekey()`
and `dns_qp_deletename()`, to return the deleted leaf.
2023-08-15 14:24:39 +02:00
Ondřej Surý
b570750382
Make the load-names benchmark multithreaded
The load-names benchmark was originally only measuring single thread
performance of the data structures.  As this is not how those are used
in the real life, it was refactored to be multi-threaded with proper
protections in place (rwlock for ht, hashmap and rbt; transactions for
qp).

The qp test has been extended to see effect of the dns_qp_compact() and
rcu_barrier() on the overall speed and memory consumption.
2023-07-31 15:51:15 +02:00
Tony Finch
c890b9b124
Get the tests working with liburcu
Mostly a few qp-trie details to adjust.
2023-05-12 20:48:31 +01:00
Tony Finch
9882a6ef90
The zone table no longer depends on the loop manager
This reverts some of the changes in commit b171cacf4f
because now it isn't necessary to pass the loopmgr around.
2023-05-12 20:48:31 +01:00
Tony Finch
06f534fa69
Avoid spurious compilation failures in liburcu headers
When liburcu is not installed from a system package, its headers are
not treated as system headers by the compiler, so BIND's -Werror and
other warning options take effect. The liburcu headers have a lot
of inline functions, some of which do not use all their arguments,
which BIND's build treats as an error.
2023-04-27 12:38:53 +02:00
Tony Finch
b3e35fd120 A few qp-trie cleanups
Revert refcount debug tracing (commit a8b29f0365), there are better
ways to do it.

Use the dns_qpmethods_t typedef where appropriate.

Some stylistic improvements.
2023-04-05 12:35:04 +01:00
Tony Finch
39f38754e2 Compact more in dns_qp_compact(DNS_QPGC_ALL)
Commit 0858514ae8 enriched dns_qp_compact() to give callers more
control over how thoroughly the trie should be compacted.

In the DNS_QPGC_ALL case, if the trie is small it might be compacted
to a new position in the same memory chunk. In this situation it will
still be holding references to old leaf objects which have been
removed from the trie but will not be completely detached until the
chunk containing the references is freed.

This change resets the qp-trie allocator to a fresh chunk before a
DNS_QPGC_ALL compaction, so all the old memory chunks will be
evacuated and old leaf objects can be detached sooner.
2023-04-05 12:35:04 +01:00
Tony Finch
906d434aea Fix Coverity complaints in the qp-trie tests
The main problem was `qp_test_keytoname()` not using `qpkey_bit()`
to do bounds checking.
2023-04-03 15:10:47 +00:00
Ondřej Surý
a5f5f68502
Refactor isc_time_now() to return time, and not result
The isc_time_now() and isc_time_now_hires() were used inconsistently
through the code - either with status check, or without status check,
or via TIME_NOW() macro with RUNTIME_CHECK() on failure.

Refactor the isc_time_now() and isc_time_now_hires() to always fail when
getting current time has failed, and return the isc_time_t value as
return value instead of passing the pointer to result in the argument.
2023-03-31 15:02:06 +02:00
Tony Finch
a8b29f0365 Improve qp-trie refcount debugging
Add some qp-trie tracing macros which can be enabled by a
developer. These print a message when a leaf is attached or
detached, indicating which part of the qp-trie implementation
did so. The refcount methods must now return the refcount value
so it can be printed by the trace macros.
2023-02-27 13:47:57 +00:00
Tony Finch
4b5ec07bb7 Refactor qp-trie to use QSBR
The first working multi-threaded qp-trie was stuck with an unpleasant
trade-off:

  * Use `isc_rwlock`, which has acceptable write performance, but
    terrible read scalability because the qp-trie made all accesses
    through a single lock.

  * Use `liburcu`, which has great read scalability, but terrible
    write performance, because I was relying on `rcu_synchronize()`
    which is rather slow. And `liburcu` is LGPL.

To get the best of both worlds, we need our own scalable read side,
which we now have with `isc_qsbr`. And we need to modify the write
side so that it is not blocked by readers.

Better write performance requires an async cleanup function like
`call_rcu()`, instead of the blocking `rcu_synchronize()`. (There
is no blocking cleanup in `isc_qsbr`, because I have concluded
that it would be an attractive nuisance.)

Until now, all my multithreading qp-trie designs have been based
around two versions, read-only and mutable. This is too few to
work with asynchronous cleanup. The bare minimum (as in epoch
based reclamation) is three, but it makes more sense to support an
arbitrary number. Doing multi-version support "properly" makes
fewer assumptions about how safe memory reclamation works, and it
makes snapshots and rollbacks simpler.

To avoid making the memory management even more complicated, I
have introduced a new kind of "packed reader node" to anchor the
root of a version of the trie. This is simpler because it re-uses
the existing chunk lifetime logic - see the discussion under
"packed reader nodes" in `qp_p.h`.

I have also made the chunk lifetime logic simpler. The idea of a
"generation" is gone; instead, chunks are either mutable or
immutable. And the QSBR phase number is used to indicate when a
chunk can be reclaimed.

Instead of the `shared_base` flag (which was basically a one-bit
reference count, with a two version limit) the base array now has a
refcount, which replaces the confusing ad-hoc lifetime logic with
something more familiar and systematic.
2023-02-27 13:47:55 +00:00
Tony Finch
549854f63b Some minor qp-trie improvements
Adjust the dns_qp_memusage() and dns_qp_compact() functions
to be more informative and flexible about handling fragmentation.

Avoid wasting space in runt chunks.

Switch from twigs_mutable() to cells_immutable() because that is the
sense we usually want.

Drop the redundant evacuate() function and rename evacuate_twigs() to
evacuate(). Move some chunk test functions closer to their point of
use.

Clarify compact_recursive(). Some small cleanups to comments.

Use isc_time_monotonic() for qp-trie timing stats.

Use #define constants to control debug logging.

Set up DNS name label offsets in dns_qpkey_fromname() so it is easier
to use in cases where the name is not fully hydrated.
2023-02-27 13:47:25 +00:00
Tony Finch
a9d57b91db Benchmarks for the qp-trie
The main benchmark is `qpmulti`, which exercizes the qp-trie
transactional API with differing numbers of threads and differing data
sizes, to get some idea of how its performance scales.

The `load-names` benchmark compares the times to populate and query
and the memory used by various BIND data structures: qp-trie, hash
table (chained), hash map (closed), and red-black tree.

The `qp-dump` program is a test utility rather than a benchmark. It
populates a qp-trie and prints it out, either in an ad-hoc text
format, or as input to the graphviz `dot` program.
2023-02-27 13:47:25 +00:00
Tony Finch
50ab648f8a Remove unused support for fromwire(DNS_NAME_DOWNCASE)
Most of this change is fixing dns_rdata_fromwire() so
it does not propagate the unused options variable.
2023-02-06 13:26:36 +00:00
Ondřej Surý
cfbe01c62f Add microbenchmark for isc_iterated_hash()
Add microbenchmark for isc_iterated_hash() to measure the speed of NSEC3
per second.
2023-01-18 18:32:57 +01:00
Tony Finch
04f3000dfc Fuzzing and benchmarking for dns_name_fromwire()
Since this is very sensitive code which has often had security
problems in many DNS implementations, it needs a decent amount of
validation. This fuzzer ensures that the new code has the same output
as the old code, and that it doesn't take longer than a second.

The benchmark uses the fuzzer's copy of the old dns_name_fromwire()
code to compare a number of scenarios: many compression pointers, many
labels, long labels, random data, with/without downcasing.
2022-11-17 08:45:17 +00:00
Tony Finch
c51fda86ac Delete the render benchmark
Instead of fixing a Coverity complaint (and other style nits),
delete it because it needs input data that can't be generated
with the tools that ship with BIND.
2022-10-21 09:52:40 +00:00
Tony Finch
7ab81eab1c
A couple of compression microbenchmarks
The `render` benchmark loads some binary DNS message dumps and
repeatedly passes them to `dns_message_render`.

The `compress` benchmark loads a list of domain names and packs them
into 4KiB chunks using `dns_name_towire`.
2022-10-17 08:45:44 +02:00
Tony Finch
cf715d488b Suppress division by zero warning
Coverity is optimistic that we might do thousands of hashes in less
than a microsecond.

    /tests/bench/siphash.c: 54 in main()
    48     			count++;
    49     		}
    50
    51     		isc_time_now_hires(&finish);
    52
    53     		us = isc_time_microdiff(&finish, &start);
    >>>     CID 358309:  Integer handling issues  (DIVIDE_BY_ZERO)
    >>>     In expression "count * 1000UL / us", division by expression "us" which may be zero has undefined behavior.
    54     		printf("%f us wide-lower len %3zu, %7llu kh/s (%llx)\n",
    55     		       (double)us / 1000000.0, len,
    56     		       (unsigned long long)(count * 1000 / us),
    57     		       (unsigned long long)sum);
    58     	}
    59
2022-10-05 12:31:42 +01:00
Ondřej Surý
c14a4ac763
Add a case-insensitive option directly to siphash 2-4 implementation
Formerly, the isc_hash32() would have to change the key in a local copy
to make it case insensitive.  Change the isc_siphash24() and
isc_halfsiphash24() functions to lowercase the input directly when
reading it from the memory and converting the uint8_t * array to
64-bit (respectively 32-bit numbers).
2022-10-04 10:32:40 +02:00
Tony Finch
de10d697ab
A simple siphash benchmark
To see the effect of adding a case-insentitive option.
2022-10-04 10:32:40 +02:00
Ondřej Surý
f6e4f620b3
Use the semantic patch to do the unsigned -> unsigned int change
Apply the semantic patch on the whole code base to get rid of 'unsigned'
usage in favor of explicit 'unsigned int'.
2022-09-19 15:56:02 +02:00
Tony Finch
68029bfc9d Tests and benchmark for isc_ascii
The test is to verify basic functionality. The benchmark compares a
number of alternative tolower() implementations on large and small
strings.
2022-09-12 12:23:39 +01:00