init: ram quota as start-node attribute

This patch allows for the assignment of RAM to a start node via a new
'ram' attribute as an alternative to traditional '<resource name="RAM">'
nodes. This makes configurations more concise.

It also adds support for defining a configuration-global default RAM
quota, following the existing pattern of the default caps definition,
e.g. the following <default> node alleviates the need to repeatedly
state reasonable 'ram' and 'caps' values in each single start node.

  <default caps="100" ram="1M"/>

Fixes #5448
This commit is contained in:
Norman Feske 2025-02-07 17:29:35 +01:00 committed by Christian Helmuth
parent 71e0fa201b
commit feb253c10f
6 changed files with 47 additions and 28 deletions

View File

@ -108,6 +108,7 @@
<xs:element name="default">
<xs:complexType>
<xs:attribute name="caps" type="xs:int" />
<xs:attribute name="ram" type="Number_of_bytes" />
</xs:complexType>
</xs:element> <!-- "default" -->
@ -200,6 +201,7 @@
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="ld" type="Boolean" />
<xs:attribute name="caps" type="xs:int" />
<xs:attribute name="ram" type="Number_of_bytes" />
<xs:attribute name="priority" type="xs:int" />
<xs:attribute name="managing_system" type="Boolean" />
</xs:complexType>

View File

@ -196,11 +196,19 @@ void Sandbox::Child::evaluate_dependencies()
Sandbox::Ram_quota Sandbox::Child::_configured_ram_quota() const
{
size_t assigned = 0;
Xml_node const &xml = _start_node->xml();
_start_node->xml().for_each_sub_node("resource", [&] (Xml_node resource) {
if (resource.attribute_value("name", String<8>()) == "RAM")
assigned = resource.attribute_value("quantum", Number_of_bytes()); });
Number_of_bytes const default_ram { _default_quota_accessor.default_ram().value };
size_t assigned = xml.attribute_value("ram", default_ram);
xml.for_each_sub_node("resource", [&] (Xml_node resource) {
if (resource.attribute_value("name", String<8>()) == "RAM") {
if (assigned)
warning(name(), ": ambigious RAM-quota definition");
assigned = resource.attribute_value("quantum", Number_of_bytes());
}
});
return Ram_quota { assigned };
}
@ -208,7 +216,7 @@ Sandbox::Ram_quota Sandbox::Child::_configured_ram_quota() const
Sandbox::Cap_quota Sandbox::Child::_configured_cap_quota() const
{
size_t const default_caps = _default_caps_accessor.default_caps().value;
size_t const default_caps = _default_quota_accessor.default_caps().value;
return Cap_quota { _start_node->xml().attribute_value("caps", default_caps) };
}
@ -742,7 +750,7 @@ Sandbox::Child::Child(Env &env,
Report_update_trigger &report_update_trigger,
Xml_node start_node,
Default_route_accessor &default_route_accessor,
Default_caps_accessor &default_caps_accessor,
Default_quota_accessor &default_quota_accessor,
Name_registry &name_registry,
Ram_limit_accessor &ram_limit_accessor,
Cap_limit_accessor &cap_limit_accessor,
@ -760,7 +768,7 @@ Sandbox::Child::Child(Env &env,
_list_element(this),
_start_node(_alloc, start_node),
_default_route_accessor(default_route_accessor),
_default_caps_accessor(default_caps_accessor),
_default_quota_accessor(default_quota_accessor),
_ram_limit_accessor(ram_limit_accessor),
_cap_limit_accessor(cap_limit_accessor),
_cpu_limit_accessor(cpu_limit_accessor),
@ -768,7 +776,8 @@ Sandbox::Child::Child(Env &env,
_name_registry(name_registry),
_heartbeat_enabled(start_node.has_sub_node("heartbeat")),
_resources(_resources_from_start_node(start_node, prio_levels, affinity_space,
default_caps_accessor.default_caps())),
default_quota_accessor.default_caps(),
default_quota_accessor.default_ram())),
_pd_intrinsics(pd_intrinsics),
_parent_services(parent_services),
_child_services(child_services),

View File

@ -62,9 +62,10 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
}
};
struct Default_caps_accessor : Interface
struct Default_quota_accessor : Interface
{
virtual Cap_quota default_caps() = 0;
virtual Ram_quota default_ram() = 0;
};
template <typename QUOTA>
@ -173,7 +174,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
bool const _use_ld = _start_node->xml().attribute_value("ld", true);
Default_route_accessor &_default_route_accessor;
Default_caps_accessor &_default_caps_accessor;
Default_quota_accessor &_default_quota_accessor;
Ram_limit_accessor &_ram_limit_accessor;
Cap_limit_accessor &_cap_limit_accessor;
Cpu_limit_accessor &_cpu_limit_accessor;
@ -271,33 +272,32 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
static
Resources _resources_from_start_node(Xml_node start_node, Prio_levels prio_levels,
Affinity::Space const &affinity_space,
Cap_quota default_cap_quota)
Cap_quota default_cap_quota,
Ram_quota default_ram_quota)
{
unsigned cpu_percent = 0;
Number_of_bytes ram_bytes = 0;
Number_of_bytes const default_ram { default_ram_quota.value };
size_t caps = start_node.attribute_value("caps", default_cap_quota.value);
Number_of_bytes ram { start_node.attribute_value("ram", default_ram) };
size_t caps { start_node.attribute_value("caps", default_cap_quota.value) };
unsigned cpu_percent = 0;
start_node.for_each_sub_node("resource", [&] (Xml_node rsc) {
using Name = String<8>;
Name const name = rsc.attribute_value("name", Name());
if (name == "RAM")
ram_bytes = rsc.attribute_value("quantum", ram_bytes);
if (name == "CPU")
cpu_percent = rsc.attribute_value("quantum", 0U);
if (name == "CAP")
caps = rsc.attribute_value("quantum", 0UL);
if (name == "RAM") ram = rsc.attribute_value("quantum", ram);
if (name == "CPU") cpu_percent = rsc.attribute_value("quantum", 0U);
if (name == "CAP") caps = rsc.attribute_value("quantum", 0UL);
});
return Resources { log2(prio_levels.value),
priority_from_xml(start_node, prio_levels),
Affinity(affinity_space,
affinity_location_from_xml(affinity_space, start_node)),
Ram_quota { ram_bytes },
Ram_quota { ram },
Cap_quota { caps },
Cpu_quota { cpu_percent } };
}
@ -583,7 +583,7 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup
Report_update_trigger &report_update_trigger,
Xml_node start_node,
Default_route_accessor &default_route_accessor,
Default_caps_accessor &default_caps_accessor,
Default_quota_accessor &default_quota_accessor,
Name_registry &name_registry,
Ram_limit_accessor &ram_limit_accessor,
Cap_limit_accessor &cap_limit_accessor,

View File

@ -87,14 +87,17 @@ struct Config_model::Default_node : Node
}
Cap_quota &_default_caps;
Ram_quota &_default_ram;
Default_node(Cap_quota &default_caps) : _default_caps(default_caps) { }
Default_node(Cap_quota &default_caps, Ram_quota &default_ram)
: _default_caps(default_caps), _default_ram(default_ram) { }
bool matches(Xml_node const &xml) const override { return type_matches(xml); }
void update(Xml_node const &xml) override
{
_default_caps = Cap_quota { xml.attribute_value("caps", 0UL) };
_default_ram = Ram_quota { xml.attribute_value("ram", Number_of_bytes()) };
}
};
@ -325,6 +328,7 @@ void Config_model::update_from_xml(Xml_node const &xml,
Preservation &preservation,
Constructible<Buffered_xml> &default_route,
Cap_quota &default_caps,
Ram_quota &default_ram,
Prio_levels &prio_levels,
Constructible<Affinity::Space> &affinity_space,
Start_model::Factory &child_factory,
@ -358,7 +362,7 @@ void Config_model::update_from_xml(Xml_node const &xml,
return *new (alloc) Default_route_node(alloc, default_route);
if (Default_node::type_matches(xml))
return *new (alloc) Default_node(default_caps);
return *new (alloc) Default_node(default_caps, default_ram);
if (Start_node::type_matches(xml))
return *new (alloc) Start_node(child_factory, xml);

View File

@ -273,6 +273,7 @@ class Sandbox::Config_model : Noncopyable
Preservation &,
Constructible<Buffered_xml> &,
Cap_quota &,
Ram_quota &,
Prio_levels &,
Constructible<Affinity::Space> &,
Start_model::Factory &,

View File

@ -24,7 +24,7 @@
struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
::Sandbox::Child::Default_route_accessor,
::Sandbox::Child::Default_caps_accessor,
::Sandbox::Child::Default_quota_accessor,
::Sandbox::Child::Ram_limit_accessor,
::Sandbox::Child::Cap_limit_accessor,
::Sandbox::Child::Cpu_limit_accessor,
@ -68,6 +68,7 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
Config_model::Version _version { };
Constructible<Buffered_xml> _default_route { };
Cap_quota _default_caps { 0 };
Ram_quota _default_ram { 0 };
Prio_levels _prio_levels { };
Constructible<Affinity::Space> _affinity_space { };
Preservation _preservation { };
@ -196,9 +197,10 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
}
/**
* Default_caps_accessor interface
* Default_quota_accessor interface
*/
Cap_quota default_caps() override { return _default_caps; }
Ram_quota default_ram() override { return _default_ram; }
void _update_aliases_from_config(Xml_node const &);
void _update_parent_services_from_config(Xml_node const &);
@ -442,6 +444,7 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config)
_preservation,
_default_route,
_default_caps,
_default_ram,
_prio_levels,
_affinity_space,
*this, *this, _server,