impl/lola: Added shm-size calculation by analysis for DATA/CONTROL - #760
impl/lola: Added shm-size calculation by analysis for DATA/CONTROL#760crimson11 wants to merge 10 commits into
Conversation
c72a678 to
a090932
Compare
a090932 to
59cd98d
Compare
| enum class ShmSizeCalculationMode : std::uint8_t | ||
| { | ||
| kSimulation, | ||
| kEstimation, |
There was a problem hiding this comment.
This is no longer an estimation - this is now an calculation! We should be clear in the wording.
59cd98d to
e088dba
Compare
f8aab17 to
d04e2bf
Compare
Currently we determine shm-sizes of the CTRL and DATA shm-objects by a simulation run. I.e. we initialize the content of both section 1st within a heap-allocated resource. At the end we use the sizes to correctly size the shm-objects. This "SIMULATION" method is exact but has high runtime costs and might consume lots of memory during startup. This change now redesigns the containers/dynamic data types being used within the DATA section, to use only classes, which we are in control of and where we exactly know based on our configuration, who much size they will need. Thus the whole simulation canbe skipped and we calculate the size correctly from the configuration settins for the service instance. We re-introduce therefore the ESTIMATION mode in parallel to the SIMULATION mode.
d04e2bf to
93af38c
Compare
93af38c to
798fdc0
Compare
| /// service-elements (events + fields), which is the fixed capacity the event_controls_ container is constructed | ||
| /// with. | ||
| /// \return needed size (in bytes) for a single control shm-object. | ||
| std::size_t CalculateServiceDataControlShmSize( |
There was a problem hiding this comment.
We're missing tests for this?
| /// service-elements (events + fields), which is the fixed capacity the ServiceDataStorage containers are | ||
| /// constructed with. | ||
| /// \return needed size (in bytes) for the data shm-object. | ||
| std::size_t CalculateServiceDataStorageShmSize( |
There was a problem hiding this comment.
We're missing tests for this?
e3af40f to
fc21d3a
Compare
Added analytical estimate/ANALYSIS mode for the shm-size calculation for the CONTROL section.
Adapted signature of LinearSearchMap to support custom KeqEqual just like std::unordered_map.
In the skeleton component tests we were testing the lola::Skeleton with a event and field service element. But we only provided the config/ deployment info for these elements, but did never register them at their parent Skeleton. Thus, essential tests checking the shm-size calculation were off! The tests now correctly register the elements.
Fixed review comments for ne ANALYSIS based size calculations. Added unit test for parsing of new ANALYSIS mode.
Moved the shm-size calc for ServiceDataStorage and ServiceDataControl out of SkeletonMemoryManager to the correspoinding data structures itself.
Added death-test for LinearSearchMap for capacity overflow. SkeletonMemoryManager now uses GetServiceElementInstanceDeployment helper.
Added tests for ServiceDataControl for size calculation.
Added tests for ServiceDataStorage for size calculation.
fc21d3a to
595c6bb
Compare
| GetServiceElementInstanceDeployment<ServiceElementType::FIELD>(lola_service_instance_deployment_, name); | ||
| SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE( | ||
| deployment.lola_event_instance_deployment_.max_subscribers_.has_value(), | ||
| "Number of sample slots need to be specified for event on provider side!"); |
There was a problem hiding this comment.
| "Number of sample slots need to be specified for event on provider side!"); | |
| "Max subscribers need to be specified for field on provider side!"); |
| // When searching via the const overload of find | ||
| const auto it = const_unit.find(kSomeKey); | ||
|
|
||
| // Then an existing key is found and |
There was a problem hiding this comment.
| // Then an existing key is found and | |
| // Then an existing key is found |
| /// needed the maximum possible alignment padding. This mirrors what the real construction allocates on the | ||
| /// (monotonic) shared-memory resource, eventually slightly overestimating it, as we have to assume that | ||
| /// memory allocation starts from a worst-case aligned situation. | ||
| std::pair<std::size_t, std::size_t> CalculateServiceDataStorageShmSize( |
There was a problem hiding this comment.
Better to return a struct than a pair so that the values are named rather than accessing via .first / .second.
|
|
||
| // (1) The ServiceDataStorage object itself (including the inline bookkeeping of its two LinearSearchMaps). | ||
| std::size_t total_size = CalculateWorstCaseAllocationSize(sizeof(ServiceDataStorage), alignof(ServiceDataStorage)); | ||
| AccumulateAllocationSize(sizeof(ServiceDataStorage), alignof(ServiceDataStorage), minimal_size, worst_case_size); |
There was a problem hiding this comment.
Why do we need to calculate the size using worst case alignment for every allocation? I would have thought that we would do this for the first allocation, but after that, the size / alignment calculations would be deterministic for all other allocations, assuming that we calculate them all in the same order as they're allocated in production code (and obviously don't miss any allocations).
And if we actually do the first allocation in shared memory using max_align_t then wouldn't the simulation run then calculate the same size as the analysis run?
| const std::vector<ServiceElementControlSizeInfo> service_elements_size_info{ | ||
| ServiceElementControlSizeInfo{kEventProperties.GetTotalNumberOfSlots(), kEventProperties.max_subscribers}, | ||
| ServiceElementControlSizeInfo{kEventProperties.GetTotalNumberOfSlots(), kEventProperties.max_subscribers}}; | ||
| const auto [minimal_size, worst_case_size] = CalculateServiceDataControlShmSize( |
There was a problem hiding this comment.
I don't really like that we are modifying the production function just to use the minimal_size here in a test. I'd like to understand this point better and then see if we can come up with a better solution: https://github.com/eclipse-score/communication/pull/760/changes/13d59fa31253a687bbed7c29f94174b16b08494a..c60cea9e544f63cf221586f77d524dd3f08b1716#r3747958827
c60cea9 to
3dbaee4
Compare
The size calculation by analysis has now been changed: We don't estimate additional padding/alignment buffer anymore, since we are now "in total control" of the allocation. Thus the analyzed size shall exactly match the size resulting from simulation. Skeleton component tests were added to verify this.
3dbaee4 to
0e56382
Compare
| bool AreServiceElementBindingsGeneric(const SkeletonBinding::SkeletonEventBindings& events, | ||
| const SkeletonBinding::SkeletonFieldBindings& fields) | ||
| { | ||
| const auto* const first_binding_map = !events.empty() ? &events : (!fields.empty() ? &fields : nullptr); |
| // exactly number_of_slots * sizeof(SampleType) bytes, aligned to alignof(SampleType) - no rounding. | ||
| if (are_bindings_generic) | ||
| { | ||
| const auto& generic_event_binding = static_cast<const GenericSkeletonEventBinding&>(event_binding); |
Currently we determine shm-sizes of the
CTRL and DATA shm-objects by a simulation run.
I.e. we initialize the content of both section
1st within a heap-allocated resource. At the end
we use the sizes to correctly size the shm-objects. This "SIMULATION" method is exact but has high runtime costs and might consume lots of memory during startup.
This change now redesigns the containers/dynamic data types being used within the DATA section, to use only classes, which we are in control of and where we exactly know based on our configuration, who much size they will need. Thus the whole simulation canbe skipped and we calculate the size correctly from the configuration settins for the service instance.
We re-introduce therefore the ESTIMATION mode in parallel to the SIMULATION mode.
Tackles issue #761