Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions score/mw/com/impl/bindings/lola/event_data_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,23 @@ SlotIndexType EventDataStorage::GetNumberOfSlots() const
}

void AddEventDataStorageShmSizeAllocation(std::vector<score::memory::DataTypeSizeInfo>& allocation_sequence,
memory::DataTypeSizeInfo event_sample_array_size_info)
EventDataStorageSizeInfo event_data_storage_size_info)
{
std::ignore = allocation_sequence.emplace_back(sizeof(EventDataStorage), alignof(EventDataStorage));

// This mirrors exactly how EventDataStorage's constructor computes the size of its type_erased_data_slots_
// allocation (see above): number_of_slots * per_sample_size_info.Size(), aligned to per_sample_size_info's
// alignment.
const auto& per_sample_size_info = event_data_storage_size_info.per_sample_size_info;
const auto storage_bytes_needed_result =
safe_math::Multiply<safe_math::ReturnMode::kReturnResultOnError, std::size_t>(
event_data_storage_size_info.number_of_slots, per_sample_size_info.Size());
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(
storage_bytes_needed_result.has_value(),
"Overflow while calculating the total size of the raw event-data slot-array.");

std::ignore =
allocation_sequence.emplace_back(event_sample_array_size_info.Size(), event_sample_array_size_info.Alignment());
allocation_sequence.emplace_back(storage_bytes_needed_result.value(), per_sample_size_info.Alignment());
}

} // namespace score::mw::com::impl::lola
20 changes: 14 additions & 6 deletions score/mw/com/impl/bindings/lola/event_data_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <cstddef>
#include <optional>
#include <vector>

namespace score::mw::com::impl::lola
{
Expand Down Expand Up @@ -90,16 +91,23 @@ class EventDataStorage final
std::size_t type_erased_data_slots_storage_size_in_bytes_;
};

/// \brief Per service-element (event/field) information required to analytically size the EventDataStorage of a
/// service-element, i.e. the exact number of (type-erased) slots plus the size/alignment of a single slot.
struct EventDataStorageSizeInfo
{
/// \brief Number of (type-erased) event-data slots for the service-element.
std::size_t number_of_slots;
/// \brief Size/alignment of a single sample of the service-element's datatype.
memory::DataTypeSizeInfo per_sample_size_info;
};

/// \brief Adds allocation done by EventDataStorage to an existing allocation_sequence
/// \details Gets called by the "parent" CalculateServiceDataStorageShmSize() in its calculation.
/// \param allocation_sequence The sequence of allocations to which the EventDataStorage allocations will be added.
/// \param event_sample_array_size_info The size information of the event sample array.
/// \todo Handing over the complete event sample array should be changed, because it already contains the expectation,
/// how EventDataStorage will internally store the events/slots! But it needs a rework in the call chain!
/// I.e. we should hand down number_of_slots/DataTypeSizeInfo per single event separately.
/// Ticket: SWP-281780
/// \param event_data_storage_size_info The number of slots plus the size/alignment of a single slot of the
/// service-element's EventDataStorage.
void AddEventDataStorageShmSizeAllocation(std::vector<score::memory::DataTypeSizeInfo>& allocation_sequence,
memory::DataTypeSizeInfo event_sample_array_size_info);
EventDataStorageSizeInfo event_data_storage_size_info);

} // namespace score::mw::com::impl::lola

Expand Down
11 changes: 4 additions & 7 deletions score/mw/com/impl/bindings/lola/service_data_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace score::mw::com::impl::lola
{

std::size_t CalculateServiceDataStorageShmSize(
const score::cpp::span<const score::memory::DataTypeSizeInfo> event_and_fields_size_info)
const score::cpp::span<const EventDataStorageSizeInfo> event_and_fields_size_info)
{
// The number of events + fields determines the (fixed) capacity of the two LinearSearchMaps within the
// ServiceDataStorage. It equals the number of sizing entries handed over.
Expand All @@ -52,12 +52,9 @@ std::size_t CalculateServiceDataStorageShmSize(
alignof(ServiceDataStorage::EventMetaInfoMap::value_type));

// (3) For each event/field (in the exact order it gets registered/offered): the EventDataStorage object plus its
// data-slot-array (type_erased_data_slots_). The exact size/alignment of the slot-array (see
// SkeletonMemoryManager::CreateEventDataInCreatedSharedMemory()) is provided by the caller.
// \ToDo see also comment in AddEventDataStorageShmSizeAllocation(): We should eventually hand down number_of_slots/
// event sample size info separated, instead of aggregated arrays as it "anticipates", what EventDataStorage does!
// Ticket: SWP-281780

// data-slot-array (type_erased_data_slots_). The number of slots plus the size/alignment of a single slot is
// provided by the caller; AddEventDataStorageShmSizeAllocation() itself computes the actual slot-array allocation
// size/alignment needs.
for (const auto& service_element : event_and_fields_size_info)
{
AddEventDataStorageShmSizeAllocation(allocation_sequence, service_element);
Expand Down
9 changes: 4 additions & 5 deletions score/mw/com/impl/bindings/lola/service_data_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,14 @@ class ServiceDataStorage
/// aligned location) and we know the size/alignment/order of every individual allocation performed by the
/// real construction, we can reconstruct the exact same sequence of allocations here and compute the exact
/// alignment-padding between them (see score::memory::shared::CalculateAlignedSizeOfSequence()).
/// \param event_and_fields_size_info per service-element sizing information (Size() being the exact size, in bytes,
/// of the raw slot-array that will be allocated for the service-element; Alignment() being its required
/// alignment). The caller (SkeletonMemoryManager) is responsible for computing these values
/// (see SkeletonMemoryManager::CreateEventDataInCreatedSharedMemory()).
/// \param event_and_fields_size_info per service-element sizing information: the number of (type-erased) slots plus
/// the size/alignment of a single slot. The caller (SkeletonMemoryManager) is responsible for providing these
/// values (see SkeletonMemoryManager::CalculateDataShmResourceStorageSize()).
/// The size of the span equals the number of service-elements (events + fields), which is the fixed capacity
/// the ServiceDataStorage containers are constructed with.
/// \return the exact number of bytes needed for the data shm-object.
std::size_t CalculateServiceDataStorageShmSize(
score::cpp::span<const score::memory::DataTypeSizeInfo> event_and_fields_size_info);
score::cpp::span<const EventDataStorageSizeInfo> event_and_fields_size_info);

} // namespace score::mw::com::impl::lola

Expand Down
70 changes: 23 additions & 47 deletions score/mw/com/impl/bindings/lola/service_data_storage_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,16 @@ TEST_F(ServiceDataStorageFixture, GetsUidFromRuntimAndStoresItOnConstruction)
TEST(ServiceDataStorageShmSizeTest, IncreasingAlignedSlotArraySizeOfAServiceElementIncreasesCalculatedSize)
{
// Given two sizing infos for a single service-element that only differ in the size of their raw slot-array
const std::vector<score::memory::DataTypeSizeInfo> service_elements_with_smaller_slot_array{
score::memory::DataTypeSizeInfo{32U, 16U}};
const std::vector<score::memory::DataTypeSizeInfo> service_elements_with_bigger_slot_array{
score::memory::DataTypeSizeInfo{320U, 16U}};
const std::vector<EventDataStorageSizeInfo> service_elements_with_smaller_slot_array{
EventDataStorageSizeInfo{2U, score::memory::DataTypeSizeInfo{32U, 16U}}};
const std::vector<EventDataStorageSizeInfo> service_elements_with_bigger_slot_array{
EventDataStorageSizeInfo{20U, score::memory::DataTypeSizeInfo{32U, 16U}}};

// When calculating the required shm-size for both sizing infos
const auto size_with_fewer_slots = CalculateServiceDataStorageShmSize(
score::cpp::span<const score::memory::DataTypeSizeInfo>{service_elements_with_smaller_slot_array});
score::cpp::span<const EventDataStorageSizeInfo>{service_elements_with_smaller_slot_array});
const auto size_with_more_slots = CalculateServiceDataStorageShmSize(
score::cpp::span<const score::memory::DataTypeSizeInfo>{service_elements_with_bigger_slot_array});
score::cpp::span<const EventDataStorageSizeInfo>{service_elements_with_bigger_slot_array});

// Then the calculated size for the service-element with the bigger raw slot-array is bigger.
EXPECT_GT(size_with_more_slots, size_with_fewer_slots);
Expand All @@ -131,31 +131,23 @@ TEST(ServiceDataStorageShmSizeTest, AddingAnAdditionalServiceElementIncreasesCal
{
// Given the sizing information of one service-element and, additionally, the very same sizing information for
// two service-elements
const std::vector<score::memory::DataTypeSizeInfo> single_service_element{
score::memory::DataTypeSizeInfo{48U, 16U}};
const std::vector<score::memory::DataTypeSizeInfo> two_service_elements{score::memory::DataTypeSizeInfo{48U, 16U},
score::memory::DataTypeSizeInfo{48U, 16U}};
const std::vector<EventDataStorageSizeInfo> single_service_element{
EventDataStorageSizeInfo{1U, score::memory::DataTypeSizeInfo{48U, 16U}}};
const std::vector<EventDataStorageSizeInfo> two_service_elements{
EventDataStorageSizeInfo{1U, score::memory::DataTypeSizeInfo{48U, 16U}},
EventDataStorageSizeInfo{1U, score::memory::DataTypeSizeInfo{48U, 16U}}};

// When calculating the required shm-size for both sizing infos
const auto size_for_single_service_element = CalculateServiceDataStorageShmSize(
score::cpp::span<const score::memory::DataTypeSizeInfo>{single_service_element});
const auto size_for_two_service_elements = CalculateServiceDataStorageShmSize(
score::cpp::span<const score::memory::DataTypeSizeInfo>{two_service_elements});
const auto size_for_single_service_element =
CalculateServiceDataStorageShmSize(score::cpp::span<const EventDataStorageSizeInfo>{single_service_element});
const auto size_for_two_service_elements =
CalculateServiceDataStorageShmSize(score::cpp::span<const EventDataStorageSizeInfo>{two_service_elements});

// Then the calculated size for two service-elements is bigger than for a single one.
EXPECT_GT(size_for_two_service_elements, size_for_single_service_element);
}

/// \brief Sizing information of a single service-element (event/field): the size/alignment of a single sample of
/// its datatype plus the number of slots in its raw slot-array. This mirrors exactly what
/// SkeletonMemoryManager::CreateEventDataInCreatedSharedMemory() passes to EventDataStorage's constructor at runtime.
struct EventOrFieldSizeInfo
{
score::memory::DataTypeSizeInfo per_sample_size_info;
std::size_t number_of_slots;
};

using EventsOrFieldsSizeInfo = std::vector<EventOrFieldSizeInfo>;
using EventsOrFieldsSizeInfo = std::vector<EventDataStorageSizeInfo>;

/// \brief Constructs a real ServiceDataStorage on the given resource and, for each entry of
/// service_elements_size_info, a real EventDataStorage whose raw slot-array's size/alignment matches the entry
Expand All @@ -179,23 +171,6 @@ std::size_t ConstructServiceDataStorageAndGetAllocatedBytes(const EventsOrFields
return resource.GetUserAllocatedBytes();
}

/// \brief Converts the given per-service-element sizing information (one sample's size/alignment plus the number of
/// slots) into the per-service-element TOTAL raw slot-array sizing information expected by
/// CalculateServiceDataStorageShmSize().
std::vector<score::memory::DataTypeSizeInfo> ToSlotArraySizeInfos(
const EventsOrFieldsSizeInfo& service_elements_size_info)
{
std::vector<score::memory::DataTypeSizeInfo> slot_array_size_infos{};
slot_array_size_infos.reserve(service_elements_size_info.size());
for (const auto& service_element : service_elements_size_info)
{
slot_array_size_infos.emplace_back(
service_element.number_of_slots * service_element.per_sample_size_info.Size(),
service_element.per_sample_size_info.Alignment());
}
return slot_array_size_infos;
}

class ServiceDataStorageShmSizeParameterizedTestFixture : public ServiceDataStorageFixture,
public ::testing::WithParamInterface<EventsOrFieldsSizeInfo>
{
Expand All @@ -208,9 +183,8 @@ TEST_P(ServiceDataStorageShmSizeParameterizedTestFixture, CalculatedSizeMatchesA
const auto& service_elements_size_info = GetParam();

// When calculating the required shm-size for a ServiceDataStorage holding these service-elements
const auto slot_array_size_infos = ToSlotArraySizeInfos(service_elements_size_info);
const auto calculated_size = CalculateServiceDataStorageShmSize(
score::cpp::span<const score::memory::DataTypeSizeInfo>{slot_array_size_infos});
score::cpp::span<const EventDataStorageSizeInfo>{service_elements_size_info});

// Then the calculated size exactly matches the number of bytes actually allocated when constructing a real
// ServiceDataStorage (and its EventDataStorages) with the very same sizing information.
Expand All @@ -228,12 +202,14 @@ INSTANTIATE_TEST_SUITE_P(
// No service-elements at all (an empty span)
EventsOrFieldsSizeInfo{},
// A single service-element (event/field): 5 slots of a datatype of size/alignment 16
EventsOrFieldsSizeInfo{EventOrFieldSizeInfo{score::memory::DataTypeSizeInfo{16U, 16U}, 5U}},
EventsOrFieldsSizeInfo{EventDataStorageSizeInfo{5U, score::memory::DataTypeSizeInfo{16U, 16U}}},
// Multiple service-elements (events/fields) with differing per-sample sizes/alignments and slot-counts
EventsOrFieldsSizeInfo{
EventOrFieldSizeInfo{score::memory::DataTypeSizeInfo{8U, 8U}, 2U},
EventOrFieldSizeInfo{score::memory::DataTypeSizeInfo{kMaxSupportedAlignment, kMaxSupportedAlignment}, 14U},
EventOrFieldSizeInfo{score::memory::DataTypeSizeInfo{kMaxSupportedAlignment, kMaxSupportedAlignment}, 8U},
EventDataStorageSizeInfo{2U, score::memory::DataTypeSizeInfo{8U, 8U}},
EventDataStorageSizeInfo{14U,
score::memory::DataTypeSizeInfo{kMaxSupportedAlignment, kMaxSupportedAlignment}},
EventDataStorageSizeInfo{8U,
score::memory::DataTypeSizeInfo{kMaxSupportedAlignment, kMaxSupportedAlignment}},
}));

} // namespace
Expand Down
28 changes: 13 additions & 15 deletions score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,21 +536,19 @@ std::size_t SkeletonMemoryManager::CalculateDataShmResourceStorageSize(
// event bindings. The layout-dependent size algorithm itself lives next to ServiceDataStorage
// (CalculateServiceDataStorageShmSize), so that the data-structure and the algorithm reasoning about its memory
// footprint stay closely coupled.
const auto collect_service_elements =
[this](std::vector<score::memory::DataTypeSizeInfo>& events_and_fields_size_infos,
auto& bindings,
const bool are_fields) {
for (const auto& binding : bindings)
{
const std::size_t number_of_slots = GetNumberOfSampleSlotsFromConfig(binding.first, are_fields);
SkeletonEventBinding& event_binding = binding.second.get();

const std::size_t slot_array_size = number_of_slots * event_binding.GetEventDataTypeSizeInfo().Size();
std::ignore = events_and_fields_size_infos.emplace_back(
slot_array_size, event_binding.GetEventDataTypeSizeInfo().Alignment());
}
};
std::vector<score::memory::DataTypeSizeInfo> events_and_fields_size_infos{};
const auto collect_service_elements = [this](std::vector<EventDataStorageSizeInfo>& events_and_fields_size_infos,
auto& bindings,
const bool are_fields) {
for (const auto& binding : bindings)
{
const std::size_t number_of_slots = GetNumberOfSampleSlotsFromConfig(binding.first, are_fields);
SkeletonEventBinding& event_binding = binding.second.get();

std::ignore = events_and_fields_size_infos.emplace_back(
EventDataStorageSizeInfo{number_of_slots, event_binding.GetEventDataTypeSizeInfo()});
}
};
std::vector<EventDataStorageSizeInfo> events_and_fields_size_infos{};
collect_service_elements(events_and_fields_size_infos, events, false);
collect_service_elements(events_and_fields_size_infos, fields, true);

Expand Down
Loading