Skip to content

Commit

Permalink
iobuf: update the allocator schedule
Browse files Browse the repository at this point in the history
iobuf uses a growing schedule of allocations (growth factor 1.5) for
each fragment. This schedule was not aware of the seastar allocation
sizes, so it would request, for example 66K allocation, but seastar
internally rounds that up to 128K, so for that allocation we waste
~50% of the memory which is invisible to iobuf.

In this change we update the schedule to be seastar allocator aware,
i.e., using the same ~1.5x growth factor, but rounding up to the next
seastar allocator boundary. At 16K or below, these boundaries are
log-linear: every 2^n size, plus 3 evenly spread sizes in between
each power of 2. Above 16K, sizes are 2^n.

This change slightly reduces the total number of steps until we get
to the max size of 128K, as from 32K to 128K we use doubling steps
instead of 1.5. For large iobufs this results in 1 fewer total
which is why some tests which tested the exact number of fragments
needed to be decreased by 1.

Fixes CORE-8478.
  • Loading branch information
travisdowns committed Dec 6, 2024
1 parent 8ebd54a commit 7deb38b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 49 deletions.
56 changes: 37 additions & 19 deletions src/v/bytes/details/io_allocation_size.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,46 @@ class io_allocation_size {
static constexpr size_t ss_max_small_allocation = 16384;

public:
// >>> x=512
// >>> while x < int((1024*128)):
// ... print(x)
// ... x=int(((x*3)+1)/2)
// ... x=int(min(1024*128,x))
// print(1024*128)
// This script computes the table immediately below, which are "ideal"
// allocation sizes: rounded up to the next true size supported by
// the seastar allocator. At <= 16K we apply the small pool indexing
// logic, and above we use powers of 2 since we are in the buddy allocator
// which only supports power-of-two sizes.
//
// We scale the target size by 1.47, i.e., 1.5 tweaked slightly to ensure
// we hit 16K at the small<->big pool boundary.
//
// def lg2(size: int):
// return size.bit_length() - 1
// def p(v: object):
// print(f"{v},")
// s = 512
// fb = 2 # idx_frac_bits
// while s <= 2**14:
// # The size calculation below is doing idx_to_size(size_to_idx(s)),
// # i.e., figuring out which small point index the allocation falls in
// # then seeing what the size of that small pool is, i.e., the size of
// # the smallest small pool that can fix this allocation.
// # See the corresponding routines in src/core/memory.cc:
// #https://github.com/scylladb/seastar/blob/f840b860432e7e716e3cfc004690897b50dc122c/src/core/memory.cc#L478-L499
// idx = ((lg2(s) << fb) - ((1 << fb) - 1)) + ((s - 1) >> (lg2(s) - fb))
// p((((1 << fb) | (idx & ((1 << fb) - 1))) << (idx >> fb)) >> fb)
// s = int(s * 1.47)
// for e in [15, 16, 17]:
// p(2**e)
static constexpr auto alloc_table = std::to_array<uint32_t>(
// computed from a python script above
{512,
768,
1152,
1728,
2592,
3888,
5832,
8748,
13122,
19683,
29525,
44288,
66432,
99648,
1280,
1792,
2560,
3584,
6144,
8192,
12288,
16384,
32768,
65536,
131072});
static size_t next_allocation_size(size_t data_size);

Expand Down
58 changes: 28 additions & 30 deletions src/v/bytes/tests/iobuf_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -379,38 +379,36 @@ SEASTAR_THREAD_TEST_CASE(iobuf_as_ostream) {
}

SEASTAR_THREAD_TEST_CASE(alloctor_forward_progress) {
static constexpr std::array<uint32_t, 14> src = {{
static constexpr auto src = std::to_array<uint32_t>({
512,
768,
1152,
1728,
2592,
3888,
5832,
8748,
13122,
19683,
29525,
44288,
66432,
99648,
}};
static constexpr std::array<uint32_t, 14> expected = {{
1280,
1792,
2560,
3584,
6144,
8192,
12288,
16384,
32768,
65536,
131072,
});
static constexpr auto expected = std::to_array<uint32_t>({
768,
1152,
1728,
2592,
3888,
5832,
8748,
13122,
19683,
29525,
44288,
66432,
99648,
1280,
1792,
2560,
3584,
6144,
8192,
12288,
16384,
32768,
65536,
131072,
131072,
}};
});
BOOST_REQUIRE_EQUAL(src.size(), expected.size());
for (size_t i = 0; i < src.size(); ++i) {
BOOST_REQUIRE_EQUAL(
Expand All @@ -429,7 +427,7 @@ SEASTAR_THREAD_TEST_CASE(test_next_chunk_allocation_append_temp_buf) {
}
// slow but tha'ts life.
auto distance = std::distance(buf.begin(), buf.end());
BOOST_REQUIRE_EQUAL(distance, 324);
BOOST_REQUIRE_EQUAL(distance, 323);
constexpr size_t sz = 40000 * 1024;
auto msg = iobuf_as_scattered(std::move(buf));
BOOST_REQUIRE_EQUAL(msg.size(), sz);
Expand All @@ -445,7 +443,7 @@ SEASTAR_THREAD_TEST_CASE(test_next_chunk_allocation_append_iobuf) {
}
// slow but tha'ts life.
auto distance = std::distance(buf.begin(), buf.end());
BOOST_REQUIRE_EQUAL(distance, 324);
BOOST_REQUIRE_EQUAL(distance, 323);
constexpr size_t sz = 40000 * 1024;
auto msg = iobuf_as_scattered(std::move(buf));
BOOST_REQUIRE_EQUAL(msg.size(), sz);
Expand Down

0 comments on commit 7deb38b

Please sign in to comment.