]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/generic/array: improve the growth strategy hints-huge-tmp
authorVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 9 Mar 2020 14:39:15 +0000 (15:39 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 9 Mar 2020 15:14:59 +0000 (16:14 +0100)
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.

.gitlab-ci.yml
lib/generic/array.h
lib/utils.c

index 6cc339b580103b3be0888f816de4619a173d01f0..1c870cebd0f3a9e2c00805c4ed3159aa4f063058 100644 (file)
@@ -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
index e29a3fbe2fa9c07fa1675a3bf7386a2a7aa6f2b4..a3b2ba1bfc6bb29db9bd3077d8ef5b3655b884c7 100644 (file)
 #pragma once
 #include <stdlib.h>
 
-/** 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;
index 36d2feee066b2ff584801b9d9b27b6314dc34759..ae76a30f15b4d9c67da19280faca71d7a5138e69 100644 (file)
@@ -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 */