Skip to content

Commit

Permalink
[eclipse-iceoryx#497] Allocator can provide hint to adjust config to …
Browse files Browse the repository at this point in the history
…new requirements
  • Loading branch information
elfenpiff committed Nov 12, 2024
1 parent c9870d3 commit 7f4ec0b
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 26 deletions.
75 changes: 51 additions & 24 deletions iceoryx2-cal/src/resizable_shared_memory/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

use std::alloc::Layout;
use std::sync::atomic::Ordering;
use std::time::Duration;
use std::{fmt::Debug, marker::PhantomData};
Expand All @@ -22,6 +23,7 @@ use crate::shared_memory::{
use crate::shm_allocator::ShmAllocationError;
use iceoryx2_bb_container::semantic_string::SemanticString;
use iceoryx2_bb_container::slotmap::{SlotMap, SlotMapKey};
use iceoryx2_bb_elementary::allocator::AllocationError;
use iceoryx2_bb_log::fail;
use iceoryx2_bb_log::fatal_panic;
use iceoryx2_bb_system_types::file_name::FileName;
Expand All @@ -31,18 +33,25 @@ use iceoryx2_pal_concurrency_sync::iox_atomic::IoxAtomicBool;
use super::{
NamedConcept, NamedConceptBuilder, NamedConceptDoesExistError, NamedConceptListError,
NamedConceptMgmt, NamedConceptRemoveError, ResizableSharedMemory, ResizableSharedMemoryBuilder,
ResizableSharedMemoryView, MAX_DATASEGMENTS,
ResizableSharedMemoryView, ResizableShmAllocationError, MAX_DATASEGMENTS,
};

#[derive(Debug)]
struct BuilderConfig<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
base_name: FileName,
shm: Shm::Configuration,
allocator_config_hint: Allocator::Configuration,
shm_builder_timeout: Duration,
max_number_of_chunks_hint: usize,
}

#[derive(Debug)]
pub struct DynamicBuilder<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
where
Allocator: Debug,
{
base_name: FileName,
builder: Shm::Builder,
allocator_config_hint: Allocator::Configuration,
max_number_of_chunks_hint: usize,
config: BuilderConfig<Allocator, Shm>,
}

impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
Expand All @@ -55,14 +64,18 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>
.expect("Adding __0 results in a valid file name");
Self {
builder: Shm::Builder::new(name),
allocator_config_hint: Allocator::Configuration::default(),
max_number_of_chunks_hint: 1,
base_name: *name,
config: BuilderConfig {
base_name: *name,
shm_builder_timeout: Duration::ZERO,
allocator_config_hint: Allocator::Configuration::default(),
shm: Shm::Configuration::default(),
max_number_of_chunks_hint: 1,
},
}
}

fn config(mut self, config: &Shm::Configuration) -> Self {
self.builder = self.builder.config(config);
self.config.shm = config.clone();
self
}
}
Expand All @@ -84,31 +97,31 @@ where
}

fn allocator_config_hint(mut self, value: Allocator::Configuration) -> Self {
self.allocator_config_hint = value;
self.config.allocator_config_hint = value;
self
}

fn max_number_of_chunks_hint(mut self, value: usize) -> Self {
self.max_number_of_chunks_hint = value;
self.config.max_number_of_chunks_hint = value;
self
}

fn timeout(mut self, value: Duration) -> Self {
self.builder = self.builder.timeout(value);
self.config.shm_builder_timeout = value;
self
}

fn create(self) -> Result<DynamicMemory<Allocator, Shm>, SharedMemoryCreateError> {
let initial_size = Allocator::payload_size_hint(
&self.allocator_config_hint,
self.max_number_of_chunks_hint,
&self.config.allocator_config_hint,
self.config.max_number_of_chunks_hint,
);

let origin = format!("{:?}", self);
let shm = fail!(from origin, when self
.builder
.size(initial_size)
.create(&self.allocator_config_hint),
.create(&self.config.allocator_config_hint),
"Unable to create ResizableSharedMemory since the underlying shared memory could not be created.");

let mut shared_memory_map = SlotMap::new(MAX_DATASEGMENTS);
Expand All @@ -117,7 +130,7 @@ where
.expect("MAX_DATASEGMENTS is greater or equal 1");

Ok(DynamicMemory {
base_name: self.base_name,
builder_config: self.config,
shared_memory_map,
current_idx,
has_ownership: IoxAtomicBool::new(true),
Expand All @@ -138,7 +151,7 @@ where
.expect("MAX_DATASEGMENTS is greater or equal 1");

Ok(DynamicView {
base_name: self.base_name,
builder_config: self.config,
shared_memory_map,
current_idx,
_data: PhantomData,
Expand All @@ -147,7 +160,7 @@ where
}

pub struct DynamicView<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
base_name: FileName,
builder_config: BuilderConfig<Allocator, Shm>,
shared_memory_map: SlotMap<Shm>,
current_idx: SlotMapKey,
_data: PhantomData<Allocator>,
Expand Down Expand Up @@ -179,7 +192,7 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>>

#[derive(Debug)]
pub struct DynamicMemory<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> {
base_name: FileName,
builder_config: BuilderConfig<Allocator, Shm>,
shared_memory_map: SlotMap<Shm>,
current_idx: SlotMapKey,
has_ownership: IoxAtomicBool,
Expand All @@ -190,7 +203,7 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> NamedConcept
for DynamicMemory<Allocator, Shm>
{
fn name(&self) -> &FileName {
&self.base_name
&self.builder_config.base_name
}
}

Expand Down Expand Up @@ -222,6 +235,12 @@ impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> NamedConceptMgmt
}
}

impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> DynamicMemory<Allocator, Shm> {
fn create_new_segment(&self, layout: Layout) -> Result<(), SharedMemoryCreateError> {
todo!()
}
}

impl<Allocator: ShmAllocator, Shm: SharedMemory<Allocator>> ResizableSharedMemory<Allocator, Shm>
for DynamicMemory<Allocator, Shm>
where
Expand All @@ -230,15 +249,23 @@ where
type Builder = DynamicBuilder<Allocator, Shm>;
type View = DynamicView<Allocator, Shm>;

fn allocate(&self, layout: std::alloc::Layout) -> Result<ShmPointer, ShmAllocationError> {
match self.shared_memory_map.get(self.current_idx) {
Some(shm) => shm.allocate(layout),
None => fatal_panic!(from self,
fn allocate(&self, layout: Layout) -> Result<ShmPointer, ResizableShmAllocationError> {
loop {
match self.shared_memory_map.get(self.current_idx) {
Some(shm) => match shm.allocate(layout) {
Ok(ptr) => return Ok(ptr),
Err(ShmAllocationError::AllocationError(AllocationError::OutOfMemory)) => {
self.create_new_segment(layout)?;
}
Err(e) => return Err(e.into()),
},
None => fatal_panic!(from self,
"This should never happen! Current shared memory segment is not available!"),
}
}
}

unsafe fn deallocate(&self, offset: PointerOffset, layout: std::alloc::Layout) {
unsafe fn deallocate(&self, offset: PointerOffset, layout: Layout) {
match self.shared_memory_map.get(self.current_idx) {
Some(shm) => shm.deallocate(offset, layout),
None => fatal_panic!(from self,
Expand Down
13 changes: 12 additions & 1 deletion iceoryx2-cal/src/resizable_shared_memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod dynamic;
use std::fmt::Debug;
use std::time::Duration;

use iceoryx2_bb_elementary::enum_gen;

use crate::named_concept::*;
use crate::shared_memory::{
SharedMemory, SharedMemoryCreateError, SharedMemoryOpenError, ShmPointer,
Expand All @@ -23,6 +25,12 @@ use crate::shm_allocator::{PointerOffset, ShmAllocationError, ShmAllocator};

const MAX_DATASEGMENTS: usize = 256;

enum_gen! { ResizableShmAllocationError
mapping:
ShmAllocationError,
SharedMemoryCreateError
}

pub trait ResizableSharedMemoryBuilder<
Allocator: ShmAllocator,
Shm: SharedMemory<Allocator>,
Expand Down Expand Up @@ -62,7 +70,10 @@ pub trait ResizableSharedMemory<Allocator: ShmAllocator, Shm: SharedMemory<Alloc
type Builder: ResizableSharedMemoryBuilder<Allocator, Shm, Self, Self::View>;
type View: ResizableSharedMemoryView<Allocator, Shm>;

fn allocate(&self, layout: std::alloc::Layout) -> Result<ShmPointer, ShmAllocationError>;
fn allocate(
&self,
layout: std::alloc::Layout,
) -> Result<ShmPointer, ResizableShmAllocationError>;

/// Release previously allocated memory
///
Expand Down
20 changes: 20 additions & 0 deletions iceoryx2-cal/src/shm_allocator/bump_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ pub struct BumpAllocator {
impl ShmAllocator for BumpAllocator {
type Configuration = Config;

fn resize_hint(
&self,
layout: Layout,
strategy: AllocationStrategy,
) -> ResizeHint<Self::Configuration> {
let current_payload_size = self.allocator.total_space();

let payload_size = match strategy {
AllocationStrategy::BestFit => current_payload_size + layout.size(),
AllocationStrategy::PowerOfTwo => {
(current_payload_size + layout.size()).next_power_of_two()
}
};

ResizeHint {
payload_size,
config: Self::Configuration::default(),
}
}

fn payload_size_hint(_config: &Self::Configuration, max_number_of_chunks: usize) -> usize {
max_number_of_chunks
}
Expand Down
19 changes: 19 additions & 0 deletions iceoryx2-cal/src/shm_allocator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,36 @@ enum_gen! { ShmAllocationError
AllocationError
}

#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum AllocationStrategy {
BestFit,
PowerOfTwo,
}

#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum ShmAllocatorInitError {
MaxSupportedMemoryAlignmentInsufficient,
AllocationFailed,
}

pub struct ResizeHint<Config: ShmAllocatorConfig> {
payload_size: usize,
config: Config,
}

/// Every allocator implementation must be relocatable. The allocator itself must be stored either
/// in the same shared memory segment or in a separate shared memory segment of a different type
/// but accessible by all participating processes.
pub trait ShmAllocator: Debug + Send + Sync + 'static {
type Configuration: ShmAllocatorConfig;
/// Suggest a new payload size by considering the current allocation state in combination with
/// a provided [`AllocationStrategy`] and a `layout` that shall be allocatable.
fn resize_hint(
&self,
layout: Layout,
strategy: AllocationStrategy,
) -> ResizeHint<Self::Configuration>;

/// Suggest a managed payload size under a provided configuration assuming that at most
/// `max_number_of_chunks` of memory are in use in parallel.
fn payload_size_hint(config: &Self::Configuration, max_number_of_chunks: usize) -> usize;
Expand Down
43 changes: 42 additions & 1 deletion iceoryx2-cal/src/shm_allocator/pool_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use crate::shm_allocator::{ShmAllocator, ShmAllocatorConfig};
use iceoryx2_bb_elementary::allocator::BaseAllocator;
use iceoryx2_bb_log::fail;

use super::{PointerOffset, ShmAllocationError, ShmAllocatorInitError};
use super::{
AllocationStrategy, PointerOffset, ResizeHint, ShmAllocationError, ShmAllocatorInitError,
};

#[derive(Clone, Copy, Debug)]
pub struct Config {
Expand Down Expand Up @@ -56,6 +58,45 @@ impl PoolAllocator {
impl ShmAllocator for PoolAllocator {
type Configuration = Config;

fn resize_hint(
&self,
layout: Layout,
strategy: AllocationStrategy,
) -> ResizeHint<Self::Configuration> {
let current_layout = unsafe {
Layout::from_size_align_unchecked(
self.allocator.bucket_size(),
self.allocator.max_alignment(),
)
};
let adjusted_alignment = current_layout.align().max(layout.align());
let adjusted_size = current_layout
.size()
.max(layout.size())
.next_multiple_of(adjusted_alignment);

let adjusted_layout =
unsafe { Layout::from_size_align_unchecked(adjusted_size, adjusted_alignment) };

let config = Self::Configuration {
bucket_layout: adjusted_layout,
};
let payload_size = match strategy {
AllocationStrategy::BestFit => {
Self::payload_size_hint(&config, (self.allocator.number_of_buckets() + 1) as usize)
}
AllocationStrategy::PowerOfTwo => {
Self::payload_size_hint(&config, (self.allocator.number_of_buckets() + 1) as usize)
.next_power_of_two()
}
};

ResizeHint {
payload_size,
config,
}
}

fn payload_size_hint(config: &Self::Configuration, max_number_of_chunks: usize) -> usize {
config.bucket_layout.size() * max_number_of_chunks
}
Expand Down
1 change: 1 addition & 0 deletions iceoryx2-cal/tests/resizable_shared_memory_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ mod resizable_shared_memory {
assert_that!(unsafe{ *ptr_view }, eq test_value_2);
}

#[ignore]
#[test]
fn allocate_more_than_hinted_works<
Shm: SharedMemory<DefaultAllocator>,
Expand Down

0 comments on commit 7f4ec0b

Please sign in to comment.