diff --git a/repos/os/src/hoitaja/core_allocator.h b/repos/os/src/hoitaja/core_allocator.h index 6b8dcb58c3..6fb60d9306 100644 --- a/repos/os/src/hoitaja/core_allocator.h +++ b/repos/os/src/hoitaja/core_allocator.h @@ -12,13 +12,18 @@ * under the terms of the GNU Affero General Public License version 3. */ +#pragma once /* Genode includes */ #include #include +#include +#include +#include /** Hoitaja includes **/ #include "load_controller.h" #include "cell_controller.h" +#include namespace Hoitaja { @@ -28,13 +33,77 @@ namespace Hoitaja class Hoitaja::Core_allocator { private: - Sandbox::Child *_cells_to_grow; - Sandbox::Child *_cells_to_shrink; + Genode::Affinity::Space &_affinity_space; + + ::Sandbox::Prio_levels &_prio_levels; + + double _resource_coeff; // Coefficient used for calculating resource shares + + void _shrink(Cell &cell, unsigned int cores) + { + char yield_args_str[10]; + Genode::snprintf(yield_args_str, 7, "cores=%d", cores); + Genode::Parent::Resource_args yield_args(yield_args_str); + + cell.yield(yield_args); + } public: + inline unsigned int _calculate_resource_share(long priority) { + double ref_share = static_cast(_affinity_space.total()) / _resource_coeff; + return static_cast((1.0 / static_cast(priority)) * ref_share); + } + + Core_allocator(Genode::Affinity::Space &affinity_space, ::Sandbox::Prio_levels prio_levels) : _affinity_space(affinity_space), _prio_levels(prio_levels), _resource_coeff(0.0) + { + Genode::log("Created core allocator for ", affinity_space.total(), " cores and ", prio_levels.value, " priorities."); + } + + Genode::Affinity::Location allocate_cores_for_cell(Genode::Xml_node const &start_node) + { + // Calculate affinity from global affinity space and priority + long priority = ::Sandbox::priority_from_xml(start_node, _prio_levels); + priority = (priority == 0) ? 1 : priority; + _resource_coeff += (1.0/static_cast(priority)); // treat priority 0 same as 1, to avoid division by zero here + + unsigned int cores_share = _calculate_resource_share(priority); + + Genode::log("Child ", start_node.attribute_value("name", Genode::String<8>("unknown")), "'s share is ", cores_share, " of ", _affinity_space.total(), " cores, coeff=", _resource_coeff, " priority=", priority); + + return Genode::Affinity::Location( _affinity_space.total()-cores_share, 0, cores_share, 1 ); /* always use the core_share last cores, for now */ + } + + void free_cores_from_cell(Cell &cell) + { + /* Remove cell's coefficient from the global resource coefficient. + * This is necessary in order to be able to redistribute the freed resources correctly. We do not trigger the redistribution itself here, because the child has not been fully destroyed yet, thus its resources might still be occupied at this point. */ + _resource_coeff -= 1.0 / static_cast(cell.resources().priority); + } + /** * @brief Update core allocations for cells reported by Cell controller * */ - void update(); + void update(Hoitaja::Cell &cell, int *xpos) { + Cell::Resources resources = cell.resources(); + long priority = (resources.priority == 0)? 1 : resources.priority; + + unsigned int cores_share = _calculate_resource_share(priority); + unsigned int cores_to_reclaim = resources.affinity.location().width() * resources.affinity.location().height() - cores_share; + + cores_to_reclaim = (static_cast(cores_to_reclaim) < 0) ? 0 : cores_to_reclaim; + + Genode::Affinity::Location location(*xpos - cores_share, resources.affinity.location().ypos(), cores_share, resources.affinity.location().height()); + cell.update_affinity(Genode::Affinity(resources.affinity.space(), location)); + + *xpos = location.xpos(); + // TODO: Update affinity of existing sessions for cell + // TODO: Send yield request to cell + log("Need to reclaim ", cores_to_reclaim, " cores from ", cell.name()); + + if (cores_to_reclaim > 0) { + _shrink(cell, cores_to_reclaim); + } + } + }; \ No newline at end of file