diff --git a/repos/os/run/bomb.run b/repos/os/run/bomb.run index 1d297d464..cf5ab48fa 100644 --- a/repos/os/run/bomb.run +++ b/repos/os/run/bomb.run @@ -21,12 +21,13 @@ install_config { - + - + + - + } diff --git a/repos/os/src/test/bomb/README b/repos/os/src/test/bomb/README new file mode 100644 index 000000000..3e5f30c59 --- /dev/null +++ b/repos/os/src/test/bomb/README @@ -0,0 +1,27 @@ +The bomb test starts as many components as configured and as RAM +resources admit. This utilitiy acts as a fork bomb to stress test core, init, +and of course the kernel. + +The master component (bomb-master) starts a given number of children and it +donates the available memory in equal shares to the children. The children +again start new children until all their memory resources are depleted or a +given generation count of children is reached (depth of the fork tree). +The bomb-master begins to kill all children after a given period of time and +restarts the creation of children afterwards. + +Configuration +------------- + +! ... +! +! ... + +rounds: solely used by master bomb - number of start/kill rounds +generations: maximum generations of children, i.e. tree depth, to create +children: number of children per bomb parent to create +sleep: time in ms to wait between creation and killing of children by + bomb-master +demand: amount of RAM in bytes which are required to spawn a new child + +The xml attributes are all optional. If the XML attributes are not set, +the values given in the example config are used as default by the bomb-master. diff --git a/repos/os/src/test/bomb/main.cc b/repos/os/src/test/bomb/main.cc index fcd59d5a5..5a4f02184 100644 --- a/repos/os/src/test/bomb/main.cc +++ b/repos/os/src/test/bomb/main.cc @@ -29,6 +29,7 @@ #include #include +#include #include using namespace Genode; @@ -75,8 +76,9 @@ class Bomb_child : private Bomb_child_resources, enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) }; Genode::Rpc_entrypoint _entrypoint; - Genode::Child _child; - Genode::Service_registry *_parent_services; + Genode::Child _child; + Genode::Service_registry *_parent_services; + Genode::Child_policy_dynamic_rom_file _config_policy; public: @@ -84,15 +86,24 @@ class Bomb_child : private Bomb_child_resources, const char *unique_name, Genode::size_t ram_quota, Cap_session *cap_session, - Service_registry *parent_services) + Service_registry *parent_services, + unsigned generation) : Bomb_child_resources(file_name, unique_name, ram_quota), Init::Child_policy_enforce_labeling(Bomb_child_resources::_name), - _entrypoint(cap_session, STACK_SIZE, "bomb", false), + _entrypoint(cap_session, STACK_SIZE, "bomb_ep_child", false), _child(_rom.dataspace(), _pd.cap(), _ram.cap(), _cpu.cap(), _rm.cap(), &_entrypoint, this), - _parent_services(parent_services) { - _entrypoint.activate(); } + _parent_services(parent_services), + _config_policy("config", _entrypoint, &_ram) + { + char client_config[64]; + snprintf(client_config, sizeof(client_config), + "", generation); + _config_policy.load(client_config, strlen(client_config) + 1); + + _entrypoint.activate(); + } ~Bomb_child() { PLOG("%s", __PRETTY_FUNCTION__); } @@ -103,7 +114,7 @@ class Bomb_child : private Bomb_child_resources, const char *name() const { return Bomb_child_resources::_name; } - void filter_session_args(const char *, char *args, Genode::size_t args_len) + void filter_session_args(const char * x, char *args, Genode::size_t args_len) { Child_policy_enforce_labeling::filter_session_args(0, args, args_len); } @@ -111,6 +122,13 @@ class Bomb_child : private Bomb_child_resources, Service *resolve_session_request(const char *service_name, const char *args) { + Service * service = nullptr; + + /* check for config file request */ + if ((service = _config_policy.resolve_session_request(service_name, + args))) + return service; + return _parent_services->find(service_name); } }; @@ -147,7 +165,8 @@ static bool child_name_exists(const char *name) * If a program with the filename as name already exists, we * add a counting number as suffix. */ -static void get_unique_child_name(const char *filename, char *dst, size_t dst_len) +static void get_unique_child_name(const char *filename, char *dst, + size_t dst_len, unsigned generation) { Lock::Guard lock_guard(_children_lock); @@ -158,7 +177,7 @@ static void get_unique_child_name(const char *filename, char *dst, size_t dst_le for (int cnt = 1; true; cnt++) { /* build program name composed of filename and numeric suffix */ - snprintf(buf, sizeof(buf), "%s%s", filename, suffix); + snprintf(buf, sizeof(buf), "%s_g%u%s", filename, generation, suffix); /* if such a program name does not exist yet, we are happy */ if (!child_name_exists(buf)) { @@ -176,13 +195,15 @@ static void get_unique_child_name(const char *filename, char *dst, size_t dst_le * Start a child */ static int start_child(const char *file_name, Cap_session *cap_session, - size_t ram_quota, Service_registry *parent_services) + size_t ram_quota, Service_registry *parent_services, + unsigned generation) { char name[64]; - get_unique_child_name(file_name, name, sizeof(name)); + get_unique_child_name(file_name, name, sizeof(name), generation); Bomb_child *c = new (env()->heap()) - Bomb_child(file_name, name, ram_quota, cap_session, parent_services); + Bomb_child(file_name, name, ram_quota, cap_session, parent_services, + generation); Lock::Guard lock_guard(_children_lock); _children.insert(c); @@ -217,11 +238,13 @@ Timer::Session *timer() int main(int argc, char **argv) { - unsigned long rounds = 5; + Genode::Xml_node node = config()->xml_node(); - try { - config()->xml_node().attribute("rounds").value(&rounds); - } catch(...) { } + unsigned const rounds = node.attribute_value("rounds", 1U); + unsigned const generation = node.attribute_value("generations", 1U); + unsigned const children = node.attribute_value("children", 2U); + unsigned const sleeptime = node.attribute_value("sleep", 2000U); + unsigned long const demand = node.attribute_value("demand", 1024UL * 1024); printf("--- bomb started ---\n"); @@ -236,24 +259,26 @@ int main(int argc, char **argv) for (unsigned i = 0; names[i]; i++) parent_services.insert(new (env()->heap()) Parent_service(names[i])); - const long children = 2; - const long demand = 1024 * 1024; - unsigned long avail = env()->ram_session()->avail(); - long amount = (avail - demand) / children; - if (amount < (children * demand)) { - PLOG("I'm a leaf node."); + unsigned long amount = (avail - demand) / children; + if (amount < (demand * children)) { + PLOG("I'm a leaf node - generation %u - not enough memory.", + generation); + sleep_forever(); + } + if (generation == 0) { + PLOG("I'm a leaf node - generation 0"); sleep_forever(); } - for (unsigned round = 1; round < rounds ; ++round) { + for (unsigned round = 0; round < rounds ; ++round) { for (unsigned i = children; i; --i) - start_child("bomb", &cap, amount, &parent_services); + start_child("bomb", &cap, amount, &parent_services, generation - 1); /* is init our parent? */ if (!timer()) sleep_forever(); - timer()->msleep(2000); + timer()->msleep(sleeptime); PINF("[%03d] It's time to kill all my children...", round); while (1) { @@ -271,7 +296,9 @@ int main(int argc, char **argv) PINF("[%03d] Done.", round); } - PINF("Done. Going to sleep"); + /* master if rounds != 0 */ + if (rounds != 0) + PINF("Done. Going to sleep"); sleep_forever(); return 0;