From: Vladimír Čunát Date: Mon, 9 Mar 2020 14:39:15 +0000 (+0100) Subject: lib/generic/array: improve the growth strategy X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db7024393c864c36e2885d3c81bb4f9eda0f11e9;p=thirdparty%2Fknot-resolver.git lib/generic/array: improve the growth strategy For large arrays it was linear, so huge amount of +1 would need quadratic time together. I've been hating that for a long time, but now I finally have a use case where it makes a large difference. The one from GCC looks good to me (theoretically) and it surely has lots of practical deployment. CI scan-build: I still have no idea about these array allocation errors; I had just given up and believe they're false alarms. --- diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6cc339b58..1c870cebd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -241,7 +241,7 @@ lint:scan-build: script: - export SCANBUILD="scan-build --status-bugs -no-failure-reports $(./scripts/get-scanbuild-args.sh)" - ninja -C build_ci* scan-build || true - - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 38 # we have this many errors ATM :-) + - test "$(ls build_ci*/meson-logs/scanbuild/*/report-*.html | wc -l)" = 43 # we have this many errors ATM :-) lint:tidy: <<: *test diff --git a/lib/generic/array.h b/lib/generic/array.h index e29a3fbe2..a3b2ba1bf 100644 --- a/lib/generic/array.h +++ b/lib/generic/array.h @@ -53,14 +53,25 @@ #pragma once #include -/** Simplified Qt containers growth strategy. */ -static inline size_t array_next_count(size_t want) +/** Growth strategy agorithm from GCC libstdc++ (also GPL 3+) + https://github.com/gcc-mirror/gcc/blob/releases/gcc-9.2.0/gcc/vec.c#L159 + */ +static inline size_t array_next_count(size_t alloc, size_t desired) { - if (want < 2048) { - return (want < 20) ? want + 4 : want * 2; - } else { - return want + 2048; - } + /* Exponential growth. */ + if (!alloc) + alloc = 4; + else if (alloc < 16) + /* Double when small. */ + alloc = alloc * 2; + else + /* Grow slower when large. */ + alloc = (alloc * 3 / 2); + + /* If this is still too small, set it to the right size. */ + if (alloc < desired) + alloc = desired; + return alloc; } /** @internal Incremental memory reservation */ @@ -70,7 +81,7 @@ static inline int array_std_reserve(void *baton, char **mem, size_t elm_size, si return 0; } /* Simplified Qt containers growth strategy */ - size_t next_size = array_next_count(want); + size_t next_size = array_next_count(*have, want); void *mem_new = realloc(*mem, next_size * elm_size); if (mem_new != NULL) { *mem = mem_new; diff --git a/lib/utils.c b/lib/utils.c index 36d2feee0..ae76a30f1 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -219,7 +219,7 @@ int kr_memreserve(void *baton, char **mem, size_t elm_size, size_t want, size_t return 0; } else { knot_mm_t *pool = baton; - size_t next_size = array_next_count(want); + size_t next_size = array_next_count(*have, want); void *mem_new = mm_alloc(pool, next_size * elm_size); if (mem_new != NULL) { if (*mem) { /* 0-length memcpy from NULL isn't technically OK */