From ed99d300b93777787aad82549a4b0c4be129df35 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Thu, 17 Sep 2020 18:12:06 -0700 Subject: [PATCH] Flat bitmap: Add longest-range computation. This will come in handy in the (upcoming) page-slab set assertions. --- include/jemalloc/internal/flat_bitmap.h | 25 +++++++++++++++ test/unit/flat_bitmap.c | 41 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/include/jemalloc/internal/flat_bitmap.h b/include/jemalloc/internal/flat_bitmap.h index 7b894d53..0faf447e 100644 --- a/include/jemalloc/internal/flat_bitmap.h +++ b/include/jemalloc/internal/flat_bitmap.h @@ -284,4 +284,29 @@ fb_urange_riter(fb_group_t *fb, size_t nbits, size_t start, size_t *r_begin, /* val */ false, /* forward */ false); } +JEMALLOC_ALWAYS_INLINE size_t +fb_range_longest_impl(fb_group_t *fb, size_t nbits, bool val) { + size_t begin = 0; + size_t longest_len = 0; + size_t len = 0; + while (begin < nbits && fb_iter_range_impl(fb, nbits, begin, &begin, + &len, val, /* forward */ true)) { + if (len > longest_len) { + longest_len = len; + } + begin += len; + } + return longest_len; +} + +static inline size_t +fb_srange_longest(fb_group_t *fb, size_t nbits) { + return fb_range_longest_impl(fb, nbits, /* val */ true); +} + +static inline size_t +fb_urange_longest(fb_group_t *fb, size_t nbits) { + return fb_range_longest_impl(fb, nbits, /* val */ false); +} + #endif /* JEMALLOC_INTERNAL_FB_H */ diff --git a/test/unit/flat_bitmap.c b/test/unit/flat_bitmap.c index 410e94ff..2f360d30 100644 --- a/test/unit/flat_bitmap.c +++ b/test/unit/flat_bitmap.c @@ -301,6 +301,10 @@ TEST_BEGIN(test_empty_full) { } TEST_END +/* + * This tests both iter_range and the longest range functionality, which is + * built closely on top of it. + */ TEST_BEGIN(test_iter_range_simple) { size_t set_limit = 30; size_t nbits = 100; @@ -318,6 +322,10 @@ TEST_BEGIN(test_iter_range_simple) { /* A set of checks with only the first set_limit bits *set*. */ fb_set_range(fb, nbits, 0, set_limit); + expect_zu_eq(set_limit, fb_srange_longest(fb, nbits), + "Incorrect longest set range"); + expect_zu_eq(nbits - set_limit, fb_urange_longest(fb, nbits), + "Incorrect longest unset range"); for (size_t i = 0; i < set_limit; i++) { result = fb_srange_iter(fb, nbits, i, &begin, &len); expect_true(result, "Should have found a range at %zu", i); @@ -360,6 +368,10 @@ TEST_BEGIN(test_iter_range_simple) { /* A set of checks with only the first set_limit bits *unset*. */ fb_unset_range(fb, nbits, 0, set_limit); fb_set_range(fb, nbits, set_limit, nbits - set_limit); + expect_zu_eq(nbits - set_limit, fb_srange_longest(fb, nbits), + "Incorrect longest set range"); + expect_zu_eq(set_limit, fb_urange_longest(fb, nbits), + "Incorrect longest unset range"); for (size_t i = 0; i < set_limit; i++) { result = fb_srange_iter(fb, nbits, i, &begin, &len); expect_true(result, "Should have found a range at %zu", i); @@ -436,6 +448,27 @@ fb_iter_simple(fb_group_t *fb, size_t nbits, size_t start, size_t *r_begin, return false; } +/* Similar, but for finding longest ranges. */ +static size_t +fb_range_longest_simple(fb_group_t *fb, size_t nbits, bool val) { + size_t longest_so_far = 0; + for (size_t begin = 0; begin < nbits; begin++) { + if (fb_get(fb, nbits, begin) != val) { + continue; + } + size_t end = begin + 1; + for (; end < nbits; end++) { + if (fb_get(fb, nbits, end) != val) { + break; + } + } + if (end - begin > longest_so_far) { + longest_so_far = end - begin; + } + } + return longest_so_far; +} + static void expect_iter_results_at(fb_group_t *fb, size_t nbits, size_t pos, bool val, bool forward) { @@ -487,6 +520,10 @@ expect_iter_results(fb_group_t *fb, size_t nbits) { expect_iter_results_at(fb, nbits, i, true, false); expect_iter_results_at(fb, nbits, i, true, true); } + expect_zu_eq(fb_range_longest_simple(fb, nbits, true), + fb_srange_longest(fb, nbits), "Longest range mismatch"); + expect_zu_eq(fb_range_longest_simple(fb, nbits, false), + fb_urange_longest(fb, nbits), "Longest range mismatch"); } static void @@ -527,6 +564,10 @@ do_test_iter_range_exhaustive(size_t nbits) { free(fb); } +/* + * Like test_iter_range_simple, this tests both iteration and longest-range + * computation. + */ TEST_BEGIN(test_iter_range_exhaustive) { #define NB(nbits) \ do_test_iter_range_exhaustive(nbits);