genode/repos/base-hw/src/test/cpu_quota/main.cc
Martin Stein 574a1bd198 test/cpu_quota: tolerate errors in session quota
Previously we pre-calculated the translation errors for the session
quota to make a discret check in the test. But since the order, in which
init childs get their CPU quota isn't always the same anymore (we should
have never made assumptions about that) the translation errors differ
from trial to trial. However, the errors are below 0.01% of the super
period. We now tolerate them in the run script.

Ref #2304
2017-03-15 12:24:44 +01:00

163 lines
4.0 KiB
C++

/*
* \brief Test the distribution and application of CPU quota
* \author Martin Stein
* \date 2012-01-09
*/
/*
* Copyright (C) 2012-2017 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.
*/
/* Genode includes */
#include <base/thread.h>
#include <base/component.h>
#include <base/sleep.h>
#include <timer_session/connection.h>
/* local includes */
#include <sync_session/connection.h>
using namespace Genode;
struct Single_signal
{
Signal_receiver receiver;
Signal_context context;
Signal_context_capability cap;
Signal_transmitter transmitter;
Single_signal() : cap(receiver.manage(&context)), transmitter(cap) { }
~Single_signal() { receiver.dissolve(&context); }
void receive() { receiver.wait_for_signal(); }
void submit() { transmitter.submit(); }
};
struct Synchronizer
{
Single_signal signal;
Sync::Session &session;
Synchronizer(Sync::Session &session) : session(session) { }
void threshold(unsigned threshold) { session.threshold(threshold); }
void synchronize()
{
session.submit(signal.cap);
signal.receive();
}
};
class Counter : public Thread
{
private:
enum { STACK_SIZE = 2 * 1024 * sizeof(addr_t) };
enum Stage { PAUSE, MEASUREMENT, DESTRUCTION };
Name const &_name;
unsigned long long volatile _value { 0 };
Stage volatile _stage { PAUSE };
Single_signal _start_measurement;
Single_signal _start_destruction;
Synchronizer _synchronizer;
void entry()
{
unsigned long long volatile value = 0;
while (_stage == PAUSE) {
_start_measurement.receive();
_stage = MEASUREMENT;
_synchronizer.synchronize();
while (_stage == MEASUREMENT) { value++; }
}
_value = value;
_start_destruction.submit();
}
public:
Counter(Env &env, Name const &name, unsigned cpu_percent, Sync::Session &sync)
:
Thread(env, name, STACK_SIZE, Location(),
Weight(Cpu_session::quota_lim_upscale(cpu_percent, 100)),
env.cpu()),
_name(name), _synchronizer(sync) { start(); }
void destruct()
{
_stage = DESTRUCTION;
_start_destruction.receive();
this->~Counter();
}
void pause() { _stage = PAUSE; }
void measure() { _start_measurement.submit(); }
void print(Output &output) const { Genode::print(output, _name, " ", _value); }
};
struct Main
{
enum { DURATION_BASE_SEC = 20,
MEASUREMENT_1_NR_OF_THREADS = 9,
MEASUREMENT_2_NR_OF_THREADS = 6,
CONCLUSION_NR_OF_THREADS = 3, };
Env &env;
Single_signal timer_signal;
Timer::Connection timer { env };
Sync::Connection sync { env };
Synchronizer synchronizer { sync };
Counter::Name const name_a { "counter A" };
Counter::Name const name_b { "counter B" };
Counter counter_a { env, name_a, 10, sync };
Counter counter_b { env, name_b, 90, sync };
Main(Env &env) : env(env)
{
Cpu_session::Quota quota = env.cpu().quota();
log("quota super period ", quota.super_period_us);
log("quota ", quota.us);
log("start measurement ...");
timer.sigh(timer_signal.cap);
auto measure = [&] (unsigned duration_sec) {
timer.trigger_once(duration_sec * 1000 * 1000);
synchronizer.synchronize();
timer_signal.receive();
};
/* measurement 1 */
synchronizer.threshold(MEASUREMENT_1_NR_OF_THREADS);
counter_a.measure();
counter_b.measure();
measure(3 * DURATION_BASE_SEC);
counter_a.pause();
counter_b.destruct();
/* measurement 2 */
synchronizer.threshold(MEASUREMENT_2_NR_OF_THREADS);
counter_a.measure();
measure(DURATION_BASE_SEC);
counter_a.destruct();
/* conclusion */
synchronizer.threshold(CONCLUSION_NR_OF_THREADS);
synchronizer.synchronize();
log(counter_a);
log(counter_b);
log("done");
}
};
void Component::construct(Env &env) { static Main main(env); }