bomb.run: support configuration of many parameters

Adjust bomb to specify the various hard-coded parameters and set up bomb.run
this way that it manages at our test machine to succeed in the given time.

Issue #1615
This commit is contained in:
Alexander Boettcher 2015-07-02 14:24:51 +02:00 committed by Christian Helmuth
parent 4ee8919f29
commit cb1e0711ec
3 changed files with 84 additions and 29 deletions

View File

@ -21,12 +21,13 @@ install_config {
<any-service> <parent/> <any-child/> </any-service> <any-service> <parent/> <any-child/> </any-service>
</default-route> </default-route>
<start name="timer"> <start name="timer">
<resource name="RAM" quantum="768K"/> <resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides> <provides><service name="Timer"/></provides>
</start> </start>
<start name="bomb" priority="-1"> <start name="bomb-master" priority="-1">
<binary name="bomb"/>
<resource name="RAM" quantum="2G"/> <resource name="RAM" quantum="2G"/>
<config rounds="20"/> <config rounds="20" generations="6" sleep="1500"/>
</start> </start>
</config>} </config>}

View File

@ -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
-------------
! ...
! <config rounds="1" generations="1" children="2" sleep="2000" demand="1048576"/>
! ...
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.

View File

@ -29,6 +29,7 @@
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <os/config.h> #include <os/config.h>
#include <os/child_policy_dynamic_rom.h>
#include <util/xml_node.h> #include <util/xml_node.h>
using namespace Genode; using namespace Genode;
@ -75,8 +76,9 @@ class Bomb_child : private Bomb_child_resources,
enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) }; enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
Genode::Rpc_entrypoint _entrypoint; Genode::Rpc_entrypoint _entrypoint;
Genode::Child _child; Genode::Child _child;
Genode::Service_registry *_parent_services; Genode::Service_registry *_parent_services;
Genode::Child_policy_dynamic_rom_file _config_policy;
public: public:
@ -84,15 +86,24 @@ class Bomb_child : private Bomb_child_resources,
const char *unique_name, const char *unique_name,
Genode::size_t ram_quota, Genode::size_t ram_quota,
Cap_session *cap_session, Cap_session *cap_session,
Service_registry *parent_services) Service_registry *parent_services,
unsigned generation)
: :
Bomb_child_resources(file_name, unique_name, ram_quota), Bomb_child_resources(file_name, unique_name, ram_quota),
Init::Child_policy_enforce_labeling(Bomb_child_resources::_name), 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(), _child(_rom.dataspace(), _pd.cap(), _ram.cap(), _cpu.cap(),
_rm.cap(), &_entrypoint, this), _rm.cap(), &_entrypoint, this),
_parent_services(parent_services) { _parent_services(parent_services),
_entrypoint.activate(); } _config_policy("config", _entrypoint, &_ram)
{
char client_config[64];
snprintf(client_config, sizeof(client_config),
"<config generations=\"%u\"/>", generation);
_config_policy.load(client_config, strlen(client_config) + 1);
_entrypoint.activate();
}
~Bomb_child() { PLOG("%s", __PRETTY_FUNCTION__); } ~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; } 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); 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, Service *resolve_session_request(const char *service_name,
const char *args) 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); 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 * If a program with the filename as name already exists, we
* add a counting number as suffix. * 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); 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++) { for (int cnt = 1; true; cnt++) {
/* build program name composed of filename and numeric suffix */ /* 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 such a program name does not exist yet, we are happy */
if (!child_name_exists(buf)) { 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 * Start a child
*/ */
static int start_child(const char *file_name, Cap_session *cap_session, 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]; 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 *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); Lock::Guard lock_guard(_children_lock);
_children.insert(c); _children.insert(c);
@ -217,11 +238,13 @@ Timer::Session *timer()
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
unsigned long rounds = 5; Genode::Xml_node node = config()->xml_node();
try { unsigned const rounds = node.attribute_value("rounds", 1U);
config()->xml_node().attribute("rounds").value(&rounds); unsigned const generation = node.attribute_value("generations", 1U);
} catch(...) { } 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"); printf("--- bomb started ---\n");
@ -236,24 +259,26 @@ int main(int argc, char **argv)
for (unsigned i = 0; names[i]; i++) for (unsigned i = 0; names[i]; i++)
parent_services.insert(new (env()->heap()) Parent_service(names[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(); unsigned long avail = env()->ram_session()->avail();
long amount = (avail - demand) / children; unsigned long amount = (avail - demand) / children;
if (amount < (children * demand)) { if (amount < (demand * children)) {
PLOG("I'm a leaf node."); 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(); sleep_forever();
} }
for (unsigned round = 1; round < rounds ; ++round) { for (unsigned round = 0; round < rounds ; ++round) {
for (unsigned i = children; i; --i) 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? */ /* is init our parent? */
if (!timer()) sleep_forever(); if (!timer()) sleep_forever();
timer()->msleep(2000); timer()->msleep(sleeptime);
PINF("[%03d] It's time to kill all my children...", round); PINF("[%03d] It's time to kill all my children...", round);
while (1) { while (1) {
@ -271,7 +296,9 @@ int main(int argc, char **argv)
PINF("[%03d] Done.", round); PINF("[%03d] Done.", round);
} }
PINF("Done. Going to sleep"); /* master if rounds != 0 */
if (rounds != 0)
PINF("Done. Going to sleep");
sleep_forever(); sleep_forever();
return 0; return 0;