ipcz: Trim primary buffer size
Up until now the primary buffer on each NodeLink has been 2 MB, with
regions reserved for BlockAllocators of various block sizes.
Most use of dynamic shared memory allocation will be disabled for
initial MojoIpcz launch, and it will be re-enabled later via
separate field trial(s). In order to reduce the baseline memory
footprint at launch, the primary buffer is dropped to 128 kB here,
with most space being reserved for a single BlockAllocator of 64-byte
blocks. (NOTE: 64-byte blocks are still used for RouterLinkStates,
and a typical browser process connection via MojoIpcz maintains
somewhere between 1000 and 2000 of them on average. Hence we
keep this initial allocator around.)
When we're ready to experiment with more shared memory usage
an additional buffer can be allocated during node connection time,
and its layout can include many of the allocators being dropped by
this CL.
Bug: 1380476
Change-Id: I834b3046ddb6c670b2a537bac3ea309215134c84
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3996144
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/main@{#1066334}
NOKEYCHECK=True
GitOrigin-RevId: 343d13102d41f210514ec9ce787b2f6d7e80fcf0
diff --git a/src/ipcz/node_link_memory.cc b/src/ipcz/node_link_memory.cc
index 2e67c91..3a909e8 100644
--- a/src/ipcz/node_link_memory.cc
+++ b/src/ipcz/node_link_memory.cc
@@ -27,8 +27,8 @@
constexpr BufferId kPrimaryBufferId{0};
-// Fixed allocation size for each NodeLink's primary shared buffer. (2 MB)
-constexpr size_t kPrimaryBufferSize = 2 * 1024 * 1024;
+// Fixed allocation size for each NodeLink's primary shared buffer. (128 kB)
+constexpr size_t kPrimaryBufferSize = 128 * 1024;
// The front of the primary buffer is reserved for special current and future
// uses which require synchronous availability throughout a link's lifetime.
@@ -115,54 +115,16 @@
// portals.
InitialRouterLinkStateArray initial_link_states;
- // Reserved memory for a series of fixed block allocators. Additional
- // allocators may be adopted by a NodeLinkMemory over its lifetime, but these
- // ones remain fixed within the primary buffer.
- std::array<uint8_t, 64 * 64> mem_for_64_byte_blocks;
- std::array<uint8_t, 256 * 48> mem_for_256_byte_blocks;
- std::array<uint8_t, 512 * 30> mem_for_512_byte_blocks;
- std::array<uint8_t, 1024 * 11> mem_for_1k_blocks;
- std::array<uint8_t, 2048 * 8> mem_for_2k_blocks;
- std::array<uint8_t, 4096 * 16> mem_for_4k_blocks;
- std::array<uint8_t, 16384 * 16> mem_for_16k_blocks;
- std::array<uint8_t, 32768 * 8> mem_for_32k_blocks;
- std::array<uint8_t, 65536 * 22> mem_for_64k_blocks;
+ // Reserved memory for 64-byte block allocators required for RouterLinkState
+ // allocation, as well as (optional) small message and parcel data buffer
+ // allocation. Additional allocators for this and other block sizes may be
+ // adopted by a NodeLinkMemory over its lifetime, but this one remains fixed
+ // within the primary buffer.
+ std::array<uint8_t, 64 * 2032> mem_for_64_byte_blocks;
BlockAllocator block_allocator_64() {
return BlockAllocator(absl::MakeSpan(mem_for_64_byte_blocks), 64);
}
-
- BlockAllocator block_allocator_256() {
- return BlockAllocator(absl::MakeSpan(mem_for_256_byte_blocks), 256);
- }
-
- BlockAllocator block_allocator_512() {
- return BlockAllocator(absl::MakeSpan(mem_for_512_byte_blocks), 512);
- }
-
- BlockAllocator block_allocator_1k() {
- return BlockAllocator(absl::MakeSpan(mem_for_1k_blocks), 1024);
- }
-
- BlockAllocator block_allocator_2k() {
- return BlockAllocator(absl::MakeSpan(mem_for_2k_blocks), 2 * 1024);
- }
-
- BlockAllocator block_allocator_4k() {
- return BlockAllocator(absl::MakeSpan(mem_for_4k_blocks), 4 * 1024);
- }
-
- BlockAllocator block_allocator_16k() {
- return BlockAllocator(absl::MakeSpan(mem_for_16k_blocks), 16 * 1024);
- }
-
- BlockAllocator block_allocator_32k() {
- return BlockAllocator(absl::MakeSpan(mem_for_32k_blocks), 32 * 1024);
- }
-
- BlockAllocator block_allocator_64k() {
- return BlockAllocator(absl::MakeSpan(mem_for_64k_blocks), 64 * 1024);
- }
};
NodeLinkMemory::NodeLinkMemory(Ref<Node> node,
@@ -178,18 +140,7 @@
"PrimaryBuffer structure is too large.");
ABSL_HARDENING_ASSERT(primary_buffer_memory_.size() >= kPrimaryBufferSize);
- const BlockAllocator allocators[] = {
- primary_buffer_.block_allocator_64(),
- primary_buffer_.block_allocator_256(),
- primary_buffer_.block_allocator_512(),
- primary_buffer_.block_allocator_1k(),
- primary_buffer_.block_allocator_2k(),
- primary_buffer_.block_allocator_4k(),
- primary_buffer_.block_allocator_16k(),
- primary_buffer_.block_allocator_32k(),
- primary_buffer_.block_allocator_64k(),
- };
-
+ const BlockAllocator allocators[] = {primary_buffer_.block_allocator_64()};
buffer_pool_.AddBlockBuffer(kPrimaryBufferId,
std::move(primary_buffer_memory), allocators);
}
@@ -240,18 +191,9 @@
primary_buffer.header.next_sublink_id.store(kMaxInitialPortals,
std::memory_order_relaxed);
- // Note: Each InitializeRegion() performs an atomic release, so atomic stores
+ // Note: InitializeRegion() performs an atomic release, so atomic stores
// before this section can be relaxed.
primary_buffer.block_allocator_64().InitializeRegion();
- primary_buffer.block_allocator_256().InitializeRegion();
- primary_buffer.block_allocator_512().InitializeRegion();
- primary_buffer.block_allocator_1k().InitializeRegion();
- primary_buffer.block_allocator_2k().InitializeRegion();
- primary_buffer.block_allocator_4k().InitializeRegion();
- primary_buffer.block_allocator_16k().InitializeRegion();
- primary_buffer.block_allocator_32k().InitializeRegion();
- primary_buffer.block_allocator_64k().InitializeRegion();
-
return {std::move(memory), std::move(mapping)};
}
diff --git a/src/ipcz/node_link_memory_test.cc b/src/ipcz/node_link_memory_test.cc
index 2a1cd3b..88cc26d 100644
--- a/src/ipcz/node_link_memory_test.cc
+++ b/src/ipcz/node_link_memory_test.cc
@@ -60,6 +60,18 @@
return links;
}
+ static void AddBlocksToMemory(NodeLinkMemory& memory, size_t block_size) {
+ constexpr size_t kNumBlocks = 32;
+ auto mapping = DriverMemory(kTestDriver, block_size * kNumBlocks).Map();
+
+ BlockAllocator allocator(mapping.bytes(),
+ static_cast<uint32_t>(block_size));
+ allocator.InitializeRegion();
+
+ const BufferId id = memory.AllocateNewBufferId();
+ memory.AddBlockBuffer(id, block_size, std::move(mapping));
+ }
+
void SetUp() override {
node_a_->SetAssignedName(kTestBrokerName);
node_b_->SetAssignedName(kTestNonBrokerName);
@@ -112,10 +124,21 @@
}
TEST_F(NodeLinkMemoryTest, RoundUpSize) {
+ AddBlocksToMemory(memory_a(), /*block_size=*/256);
+ AddBlocksToMemory(memory_a(), /*block_size=*/512);
+
// Fragment sizes are rounded up to the nearest power of 2.
- Fragment fragment = memory_a().AllocateFragment(250);
+ Fragment fragment = memory_a().AllocateFragment(32);
+ EXPECT_TRUE(fragment.is_addressable());
+ EXPECT_EQ(64u, fragment.size());
+
+ fragment = memory_a().AllocateFragment(250);
EXPECT_TRUE(fragment.is_addressable());
EXPECT_EQ(256u, fragment.size());
+
+ fragment = memory_a().AllocateFragment(257);
+ EXPECT_TRUE(fragment.is_addressable());
+ EXPECT_EQ(512u, fragment.size());
}
TEST_F(NodeLinkMemoryTest, SharedPrimaryBuffer) {