mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-30 08:03:59 +00:00
os: add init_loop test
This test monitors the RAM quota of a dynamic init and a server hosted within the dynamic init in the presence of a repeatedly created and destructed client.
This commit is contained in:
parent
91b2e023b8
commit
7088e4faaa
68
repos/os/run/init_loop.run
Normal file
68
repos/os/run/init_loop.run
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
create_boot_directory
|
||||||
|
|
||||||
|
import_from_depot genodelabs/src/[base_src] \
|
||||||
|
genodelabs/src/report_rom
|
||||||
|
|
||||||
|
install_config {
|
||||||
|
<config>
|
||||||
|
<parent-provides>
|
||||||
|
<service name="ROM"/>
|
||||||
|
<service name="CPU"/>
|
||||||
|
<service name="PD"/>
|
||||||
|
<service name="LOG"/>
|
||||||
|
<service name="IRQ"/>
|
||||||
|
<service name="IO_MEM"/>
|
||||||
|
<service name="IO_PORT"/>
|
||||||
|
</parent-provides>
|
||||||
|
|
||||||
|
<default caps="100"/>
|
||||||
|
|
||||||
|
<start name="timer">
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<provides><service name="Timer"/></provides>
|
||||||
|
<route> <any-service> <parent/> </any-service> </route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="report_rom">
|
||||||
|
<resource name="RAM" quantum="2M"/>
|
||||||
|
<provides> <service name="ROM"/> <service name="Report"/> </provides>
|
||||||
|
<config verbose="no">
|
||||||
|
<policy label="init -> config" report="test-init_loop -> init.config"/>
|
||||||
|
<policy label="test-init_loop -> state" report="init -> state"/>
|
||||||
|
</config>
|
||||||
|
<route> <any-service> <parent/> </any-service> </route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="test-init_loop">
|
||||||
|
<resource name="RAM" quantum="4M"/>
|
||||||
|
<provides> <service name="LOG"/> </provides>
|
||||||
|
<config/>
|
||||||
|
<route>
|
||||||
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
|
<service name="ROM" label="state"> <child name="report_rom"/> </service>
|
||||||
|
<service name="Timer"> <child name="timer"/> </service>
|
||||||
|
<any-service> <parent/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="init" caps="2000">
|
||||||
|
<binary name="init"/>
|
||||||
|
<resource name="RAM" quantum="8M"/>
|
||||||
|
<route>
|
||||||
|
<service name="ROM" label="config"> <child name="report_rom"/> </service>
|
||||||
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
|
<service name="Timer"> <child name="timer"/> </service>
|
||||||
|
<any-service> <parent/> </any-service>
|
||||||
|
</route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
</config>}
|
||||||
|
|
||||||
|
build { lib/ld init app/dummy test/init_loop }
|
||||||
|
|
||||||
|
build_boot_image { ld.lib.so init dummy test-init_loop }
|
||||||
|
|
||||||
|
append qemu_args " -nographic "
|
||||||
|
|
||||||
|
run_genode_until {.*child "test-init_loop" exited with exit value 0.*} 100
|
||||||
|
|
257
repos/os/src/test/init_loop/main.cc
Normal file
257
repos/os/src/test/init_loop/main.cc
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* \brief Test for the repeated child creation in a dynamic init
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2018-06-07
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <base/heap.h>
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <base/session_state.h>
|
||||||
|
#include <log_session/log_session.h>
|
||||||
|
#include <os/reporter.h>
|
||||||
|
|
||||||
|
namespace Test {
|
||||||
|
struct Main;
|
||||||
|
using namespace Genode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Test::Main
|
||||||
|
{
|
||||||
|
Env &_env;
|
||||||
|
|
||||||
|
bool _client_starting = false;
|
||||||
|
|
||||||
|
Expanding_reporter _init_config_reporter { _env, "config", "init.config" };
|
||||||
|
|
||||||
|
void _gen_log_server_start_content(Xml_generator &xml) const
|
||||||
|
{
|
||||||
|
xml.attribute("name", "server");
|
||||||
|
xml.attribute("caps", "100");
|
||||||
|
xml.node("resource", [&] () {
|
||||||
|
xml.attribute("name", "RAM");
|
||||||
|
xml.attribute("quantum", "1M"); });
|
||||||
|
|
||||||
|
xml.node("binary", [&] () {
|
||||||
|
xml.attribute("name", "dummy"); });
|
||||||
|
|
||||||
|
xml.node("config", [&] () {
|
||||||
|
xml.node("log_service", [&] () {}); });
|
||||||
|
|
||||||
|
xml.node("provides", [&] () {
|
||||||
|
xml.node("service", [&] () {
|
||||||
|
xml.attribute("name", Log_session::service_name()); }); });
|
||||||
|
|
||||||
|
xml.node("route", [&] () {
|
||||||
|
xml.node("any-service", [&] () {
|
||||||
|
xml.node("parent", [&] () {}); }); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void _gen_log_client_start_content(Xml_generator &xml) const
|
||||||
|
{
|
||||||
|
xml.attribute("name", "client");
|
||||||
|
xml.attribute("caps", "200");
|
||||||
|
xml.node("resource", [&] () {
|
||||||
|
xml.attribute("name", "RAM");
|
||||||
|
xml.attribute("quantum", "1M"); });
|
||||||
|
|
||||||
|
xml.node("binary", [&] () {
|
||||||
|
xml.attribute("name", "dummy"); });
|
||||||
|
|
||||||
|
xml.node("config", [&] () {
|
||||||
|
xml.node("create_log_connections", [&] () {
|
||||||
|
xml.attribute("count", 1);
|
||||||
|
xml.attribute("ram_upgrade", "64K");
|
||||||
|
});
|
||||||
|
xml.node("log", [&] () {
|
||||||
|
xml.attribute("string", "client started"); }); });
|
||||||
|
|
||||||
|
xml.node("route", [&] () {
|
||||||
|
|
||||||
|
xml.node("service", [&] () {
|
||||||
|
xml.attribute("name", Log_session::service_name());
|
||||||
|
xml.node("child", [&] () {
|
||||||
|
xml.attribute("name", "server"); });
|
||||||
|
});
|
||||||
|
|
||||||
|
xml.node("any-service", [&] () {
|
||||||
|
xml.node("parent", [&] () {}); });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _gen_init_config(Xml_generator &xml) const
|
||||||
|
{
|
||||||
|
xml.node("report", [&] () {
|
||||||
|
xml.attribute("requested", "yes");
|
||||||
|
xml.attribute("init_ram", "yes");
|
||||||
|
xml.attribute("init_caps", "yes");
|
||||||
|
xml.attribute("child_ram", "yes");
|
||||||
|
xml.attribute("child_caps", "yes");
|
||||||
|
xml.attribute("delay_ms", 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto gen_service = [&] (char const *name) {
|
||||||
|
xml.node("service", [&] () { xml.attribute("name", name); }); };
|
||||||
|
|
||||||
|
xml.node("parent-provides", [&] () {
|
||||||
|
gen_service("ROM");
|
||||||
|
gen_service("CPU");
|
||||||
|
gen_service("PD");
|
||||||
|
gen_service("RM");
|
||||||
|
gen_service("LOG");
|
||||||
|
});
|
||||||
|
|
||||||
|
xml.node("start", [&] () {
|
||||||
|
_gen_log_server_start_content(xml); });
|
||||||
|
|
||||||
|
if (_client_starting)
|
||||||
|
xml.node("start", [&] () {
|
||||||
|
_gen_log_client_start_content(xml); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_init_config()
|
||||||
|
{
|
||||||
|
_init_config_reporter.generate([&] (Xml_generator &xml) {
|
||||||
|
_gen_init_config(xml); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handling of state reports generated by init
|
||||||
|
*/
|
||||||
|
Attached_rom_dataspace _init_state { _env, "state" };
|
||||||
|
|
||||||
|
Signal_handler<Main> _init_state_handler {
|
||||||
|
_env.ep(), *this, &Main::_handle_init_state };
|
||||||
|
|
||||||
|
/* counter for iterations */
|
||||||
|
unsigned _cnt = 0;
|
||||||
|
|
||||||
|
struct Ram_tracker
|
||||||
|
{
|
||||||
|
typedef String<32> Name;
|
||||||
|
|
||||||
|
Name const _name;
|
||||||
|
|
||||||
|
/* RAM quota of previous iteration */
|
||||||
|
size_t _previous = 0;
|
||||||
|
|
||||||
|
size_t total_loss = 0;
|
||||||
|
|
||||||
|
void update(Xml_node ram)
|
||||||
|
{
|
||||||
|
size_t const current = ram.attribute_value("quota", Number_of_bytes());
|
||||||
|
|
||||||
|
log(_name, " RAM: ", Number_of_bytes(current));
|
||||||
|
if (_previous) {
|
||||||
|
|
||||||
|
if (current < _previous) {
|
||||||
|
total_loss += _previous - current;
|
||||||
|
log(_name, " lost ", _previous - current, ", bytes", " "
|
||||||
|
"(total ", total_loss, " bytes)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current > _previous)
|
||||||
|
log(_name, " gained ", current - _previous, ", bytes");
|
||||||
|
}
|
||||||
|
_previous = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ram_tracker(Name const &name) : _name(name) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
Ram_tracker _init_ram_tracker { "init" };
|
||||||
|
Ram_tracker _server_ram_tracker { "server" };
|
||||||
|
|
||||||
|
static Number_of_bytes _init_ram(Xml_node state)
|
||||||
|
{
|
||||||
|
/* \throw Nonexistent_sub_node */
|
||||||
|
return state.sub_node("ram").attribute_value("quota", Number_of_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef String<32> Name;
|
||||||
|
|
||||||
|
template <typename FN>
|
||||||
|
void _apply_child(Xml_node state, Name const &name, FN const &fn)
|
||||||
|
{
|
||||||
|
state.for_each_sub_node("child", [&] (Xml_node child) {
|
||||||
|
if (child.attribute_value("name", Name()) == name)
|
||||||
|
fn(child); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handle_init_state()
|
||||||
|
{
|
||||||
|
_init_state.update();
|
||||||
|
|
||||||
|
Xml_node const state = _init_state.xml();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detect state where the client is running and has established a
|
||||||
|
* session to the LOG server.
|
||||||
|
*/
|
||||||
|
bool client_present = false;
|
||||||
|
bool client_complete = false;
|
||||||
|
|
||||||
|
_apply_child(state, "client", [&] (Xml_node child) {
|
||||||
|
client_present = true;
|
||||||
|
child.for_each_sub_node("requested", [&] (Xml_node requested) {
|
||||||
|
requested.for_each_sub_node("session", [&] (Xml_node session) {
|
||||||
|
if (session.attribute_value("service", String<16>()) == "LOG"
|
||||||
|
&& session.attribute_value("state", String<16>()) == "CAP_HANDED_OUT")
|
||||||
|
client_complete = true; }); }); });
|
||||||
|
|
||||||
|
if (_client_starting) {
|
||||||
|
|
||||||
|
/* kill client as soon as it started up completely */
|
||||||
|
if (client_complete)
|
||||||
|
_client_starting = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* restart client as soon as it vanished */
|
||||||
|
if (!client_present) {
|
||||||
|
_cnt++;
|
||||||
|
log("iteration ", _cnt);
|
||||||
|
|
||||||
|
if (state.has_sub_node("ram"))
|
||||||
|
_init_ram_tracker.update(state.sub_node("ram"));
|
||||||
|
|
||||||
|
_apply_child(state, "server", [&] (Xml_node child) {
|
||||||
|
_server_ram_tracker.update(child.sub_node("ram")); });
|
||||||
|
|
||||||
|
_client_starting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_init_ram_tracker.total_loss > 16*1024
|
||||||
|
|| _server_ram_tracker.total_loss > 16*1024) {
|
||||||
|
|
||||||
|
error("unexpected quota distribution");
|
||||||
|
_env.parent().exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success after 50 iterations without any accounting issues */
|
||||||
|
if (_cnt == 50)
|
||||||
|
_env.parent().exit(0);
|
||||||
|
|
||||||
|
generate_init_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
Main(Env &env) : _env(env)
|
||||||
|
{
|
||||||
|
_init_state.sigh(_init_state_handler);
|
||||||
|
|
||||||
|
generate_init_config();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void Component::construct(Genode::Env &env) { static Test::Main main(env); }
|
||||||
|
|
3
repos/os/src/test/init_loop/target.mk
Normal file
3
repos/os/src/test/init_loop/target.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
TARGET = test-init_loop
|
||||||
|
SRC_CC = main.cc
|
||||||
|
LIBS += base
|
@ -19,6 +19,7 @@ fs_log
|
|||||||
fs_report
|
fs_report
|
||||||
gdb_monitor
|
gdb_monitor
|
||||||
init
|
init
|
||||||
|
init_loop
|
||||||
init_smp
|
init_smp
|
||||||
input_filter
|
input_filter
|
||||||
ldso
|
ldso
|
||||||
|
Loading…
x
Reference in New Issue
Block a user