diff --git a/score/mw/com/impl/bindings/lola/event_data_storage.cpp b/score/mw/com/impl/bindings/lola/event_data_storage.cpp index 5dbcdbf4a..64efc1047 100644 --- a/score/mw/com/impl/bindings/lola/event_data_storage.cpp +++ b/score/mw/com/impl/bindings/lola/event_data_storage.cpp @@ -115,11 +115,23 @@ SlotIndexType EventDataStorage::GetNumberOfSlots() const } void AddEventDataStorageShmSizeAllocation(std::vector& 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( + 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 diff --git a/score/mw/com/impl/bindings/lola/event_data_storage.h b/score/mw/com/impl/bindings/lola/event_data_storage.h index b71e833d4..08a82ca77 100644 --- a/score/mw/com/impl/bindings/lola/event_data_storage.h +++ b/score/mw/com/impl/bindings/lola/event_data_storage.h @@ -21,6 +21,7 @@ #include #include +#include namespace score::mw::com::impl::lola { @@ -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& allocation_sequence, - memory::DataTypeSizeInfo event_sample_array_size_info); + EventDataStorageSizeInfo event_data_storage_size_info); } // namespace score::mw::com::impl::lola diff --git a/score/mw/com/impl/bindings/lola/service_data_storage.cpp b/score/mw/com/impl/bindings/lola/service_data_storage.cpp index 42b2fd632..991eedb35 100644 --- a/score/mw/com/impl/bindings/lola/service_data_storage.cpp +++ b/score/mw/com/impl/bindings/lola/service_data_storage.cpp @@ -25,7 +25,7 @@ namespace score::mw::com::impl::lola { std::size_t CalculateServiceDataStorageShmSize( - const score::cpp::span event_and_fields_size_info) + const score::cpp::span 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. @@ -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); diff --git a/score/mw/com/impl/bindings/lola/service_data_storage.h b/score/mw/com/impl/bindings/lola/service_data_storage.h index 005f9c1c2..0a3cf7c1f 100644 --- a/score/mw/com/impl/bindings/lola/service_data_storage.h +++ b/score/mw/com/impl/bindings/lola/service_data_storage.h @@ -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 event_and_fields_size_info); + score::cpp::span event_and_fields_size_info); } // namespace score::mw::com::impl::lola diff --git a/score/mw/com/impl/bindings/lola/service_data_storage_test.cpp b/score/mw/com/impl/bindings/lola/service_data_storage_test.cpp index 7a44b4b9b..1dbc4204c 100644 --- a/score/mw/com/impl/bindings/lola/service_data_storage_test.cpp +++ b/score/mw/com/impl/bindings/lola/service_data_storage_test.cpp @@ -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 service_elements_with_smaller_slot_array{ - score::memory::DataTypeSizeInfo{32U, 16U}}; - const std::vector service_elements_with_bigger_slot_array{ - score::memory::DataTypeSizeInfo{320U, 16U}}; + const std::vector service_elements_with_smaller_slot_array{ + EventDataStorageSizeInfo{2U, score::memory::DataTypeSizeInfo{32U, 16U}}}; + const std::vector 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{service_elements_with_smaller_slot_array}); + score::cpp::span{service_elements_with_smaller_slot_array}); const auto size_with_more_slots = CalculateServiceDataStorageShmSize( - score::cpp::span{service_elements_with_bigger_slot_array}); + score::cpp::span{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); @@ -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 single_service_element{ - score::memory::DataTypeSizeInfo{48U, 16U}}; - const std::vector two_service_elements{score::memory::DataTypeSizeInfo{48U, 16U}, - score::memory::DataTypeSizeInfo{48U, 16U}}; + const std::vector single_service_element{ + EventDataStorageSizeInfo{1U, score::memory::DataTypeSizeInfo{48U, 16U}}}; + const std::vector 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{single_service_element}); - const auto size_for_two_service_elements = CalculateServiceDataStorageShmSize( - score::cpp::span{two_service_elements}); + const auto size_for_single_service_element = + CalculateServiceDataStorageShmSize(score::cpp::span{single_service_element}); + const auto size_for_two_service_elements = + CalculateServiceDataStorageShmSize(score::cpp::span{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; +using EventsOrFieldsSizeInfo = std::vector; /// \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 @@ -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 ToSlotArraySizeInfos( - const EventsOrFieldsSizeInfo& service_elements_size_info) -{ - std::vector 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 { @@ -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{slot_array_size_infos}); + score::cpp::span{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. @@ -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 diff --git a/score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp b/score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp index 8ffa7c0c0..322e2a8bb 100644 --- a/score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp +++ b/score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp @@ -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& 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 events_and_fields_size_infos{}; + const auto collect_service_elements = [this](std::vector& 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 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);