test/cpu_quota: API transition

Fixes #2239
This commit is contained in:
Martin Stein 2017-01-11 17:36:58 +01:00 committed by Norman Feske
parent ec5dbe66db
commit 3e8cd442a3
8 changed files with 187 additions and 399 deletions

View File

@ -1,30 +0,0 @@
/*
* \brief Sync-session capability type
* \author Martin Stein
* \date 2015-04-07
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SYNC_SESSION__CAPABILITY_H_
#define _SYNC_SESSION__CAPABILITY_H_
/* Genode includes */
#include <base/capability.h>
/* local includes */
#include <sync_session/sync_session.h>
namespace Sync
{
using Genode::Capability;
typedef Capability<Session> Session_capability;
}
#endif /* _SYNC_SESSION__CAPABILITY_H_ */

View File

@ -1,43 +0,0 @@
/*
* \brief Client-side Sync-session interface
* \author Martin Stein
* \date 2015-04-07
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SYNC_SESSION__CLIENT_H_
#define _SYNC_SESSION__CLIENT_H_
/* Genode includes */
#include <base/rpc_client.h>
/* local includes */
#include <sync_session/capability.h>
namespace Sync
{
using Genode::Rpc_client;
struct Session_client;
}
struct Sync::Session_client : Rpc_client<Session>
{
explicit Session_client(Session_capability session)
: Rpc_client<Session>(session) { }
void threshold(unsigned id, unsigned threshold) override {
call<Rpc_threshold>(id, threshold); }
void submit(unsigned id, Signal_context_capability sigc) override {
call<Rpc_submit>(id, sigc); }
};
#endif /* _SYNC_SESSION__CLIENT_H_ */

View File

@ -16,45 +16,22 @@
/* Genode includes */
#include <base/connection.h>
#include <base/rpc_client.h>
/* local includes */
#include <sync_session/client.h>
#include <sync_session/sync_session.h>
namespace Sync
namespace Sync { class Connection; }
struct Sync::Connection : public Genode::Connection<Session>,
public Genode::Rpc_client<Session>
{
using Genode::Parent;
explicit Connection(Genode::Env &env)
: Genode::Connection<Session>(env, session("ram_quota=4K")),
Genode::Rpc_client<Session>(cap()) { }
class Connection;
}
class Sync::Connection : public Genode::Connection<Session>,
public Session_client
{
public:
class Connection_failed : public Parent::Exception { };
private:
Session_capability _create_session()
{
try { return session("ram_quota=4K"); }
catch (...) { throw Connection_failed(); }
}
public:
/**
* Constructor
*
* \throw Connection_failed
*/
Connection() __attribute__((deprecated))
:
Genode::Connection<Session>(_create_session()),
Session_client(cap())
{ }
void threshold(unsigned threshold) override { call<Rpc_threshold>(threshold); }
void submit(Signal_context_capability signal) override { call<Rpc_submit>(signal); }
};
#endif /* _SYNC_SESSION__CONNECTION_H_ */

View File

@ -15,6 +15,7 @@
#define _SYNC_SESSION__SYNC_SESSION_H_
/* Genode includes */
#include <base/capability.h>
#include <session/session.h>
#include <base/signal.h>
@ -23,32 +24,20 @@ namespace Sync
using Genode::Signal_context_capability;
struct Session;
using Session_capability = Genode::Capability<Session>;
}
struct Sync::Session : Genode::Session
{
static const char *service_name() { return "Sync"; }
virtual ~Session() { }
/**
* Set the submission threshold of a synchronization signal
*/
virtual void threshold(unsigned id, unsigned threshold) = 0;
virtual void threshold(unsigned threshold) = 0;
virtual void submit(Signal_context_capability signal) = 0;
/**
* Submit to a synchronization signal
*/
virtual void submit(unsigned id, Signal_context_capability sigc) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_threshold, void, threshold, unsigned, unsigned);
GENODE_RPC(Rpc_submit, void, submit, unsigned, Signal_context_capability);
GENODE_RPC(Rpc_threshold, void, threshold, unsigned);
GENODE_RPC(Rpc_submit, void, submit, Signal_context_capability);
GENODE_RPC_INTERFACE(Rpc_threshold, Rpc_submit);
};

View File

@ -12,166 +12,150 @@
*/
/* Genode includes */
#include <base/log.h>
#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;
enum { SYNC_SIG = 0 };
namespace Sync { class Signal; }
class Single_signal
struct Single_signal
{
private:
Signal_receiver receiver;
Signal_context context;
Signal_context_capability cap;
Signal_transmitter transmitter;
Signal_receiver _sigr;
Signal_context _sigx;
Signal_context_capability _sigc;
Signal_transmitter _sigt;
Single_signal() : cap(receiver.manage(&context)), transmitter(cap) { }
public:
Single_signal() : _sigc(_sigr.manage(&_sigx)), _sigt(_sigc) { }
~Single_signal() { _sigr.dissolve(&_sigx); }
void receive() { _sigr.wait_for_signal(); }
void submit() { _sigt.submit(); }
operator Signal_context_capability() { return _sigc; }
~Single_signal() { receiver.dissolve(&context); }
void receive() { receiver.wait_for_signal(); }
void submit() { transmitter.submit(); }
};
class Sync::Signal
struct Synchronizer
{
private:
Single_signal signal;
Sync::Session &session;
Signal_receiver _sigr;
Signal_context _sigx;
Signal_context_capability _sigc;
Session * const _session;
unsigned const _id;
Synchronizer(Sync::Session &session) : session(session) { }
public:
void threshold(unsigned threshold) { session.threshold(threshold); }
Signal(Session * const session, unsigned const id)
: _sigc(_sigr.manage(&_sigx)), _session(session), _id(id) { }
~Signal() { _sigr.dissolve(&_sigx); }
void threshold(unsigned const threshold) {
_session->threshold(_id, threshold); }
void sync()
{
_session->submit(_id, _sigc);
_sigr.wait_for_signal();
}
void synchronize()
{
session.submit(signal.cap);
signal.receive();
}
};
class Counter : private Thread_deprecated<2 * 1024 * sizeof(Genode::addr_t)>
class Counter : public Thread
{
private:
String<64> _name;
unsigned long long volatile _value;
Sync::Signal _sync_sig;
unsigned volatile _stage;
Single_signal _stage_1_end;
Single_signal _stage_2_reached;
enum { STACK_SIZE = 2 * 1024 * sizeof(addr_t) };
inline void _stage_0_and_1(unsigned long long volatile & value)
{
_stage_1_end.receive();
_stage = 0;
_sync_sig.sync();
while(_stage == 0) { value++; }
}
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 < 2) { _stage_0_and_1(value); }
while (_stage == PAUSE) {
_start_measurement.receive();
_stage = MEASUREMENT;
_synchronizer.synchronize();
while (_stage == MEASUREMENT) { value++; }
}
_value = value;
_stage_2_reached.submit();
sleep_forever();
_start_destruction.submit();
}
public:
Counter(char const *name, size_t const weight,
Sync::Session * const sync)
Counter(Env &env, Name const &name, unsigned cpu_percent, Sync::Session &sync)
:
Thread_deprecated(weight, "counter"), _name(name), _value(0) ,
_sync_sig(sync, SYNC_SIG), _stage(1)
{
Thread::start();
}
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 = 2;
_stage_2_reached.receive();
_stage = DESTRUCTION;
_start_destruction.receive();
this->~Counter();
}
void pause() { _stage = 1; }
void pause() { _stage = PAUSE; }
void measure() { _start_measurement.submit(); }
void go() { _stage_1_end.submit(); }
void result() { log("counter ", _name, " ", _value); }
void print(Output &output) const { Genode::print(output, _name, " ", _value); }
};
void measure(Timer::Connection & timer, Single_signal & timer_sig,
Sync::Signal & sync_sig, unsigned const sec)
struct Main
{
timer.trigger_once(sec * 1000 * 1000);
sync_sig.sync();
timer_sig.receive();
}
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)
{
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();
Cpu_session::Quota quota = env.cpu().quota();
log("quota super period ", quota.super_period_us);
log("quota ", quota.us);
log(counter_a);
log(counter_b);
log("done");
}
};
int main()
{
enum { DURATION_BASE_SEC = 20 };
/* prepare */
Single_signal timer_sig;
Timer::Connection timer;
Sync::Connection sync;
Sync::Signal sync_sig(&sync, SYNC_SIG);
Counter counter_a("A", Cpu_session::quota_lim_upscale(10, 100), &sync);
Counter counter_b("B", Cpu_session::quota_lim_upscale(90, 100), &sync);
timer.sigh(timer_sig);
/* measure stage 1 */
sync_sig.threshold(9);
counter_a.go();
counter_b.go();
measure(timer, timer_sig, sync_sig, 3 * DURATION_BASE_SEC);
counter_a.pause();
counter_b.destruct();
/* measure stage 2 */
sync_sig.threshold(6);
counter_a.go();
measure(timer, timer_sig, sync_sig, DURATION_BASE_SEC);
counter_a.destruct();
/* print results */
sync_sig.threshold(3);
sync_sig.sync();
Cpu_session::Quota quota = Genode::env()->cpu_session()->quota();
log("quota super period ", quota.super_period_us);
log("quota ", quota.us);
counter_a.result();
counter_b.result();
log("done");
sleep_forever();
}
void Component::construct(Env &env) { static Main main(env); }

View File

@ -14,139 +14,76 @@
/* Genode includes */
#include <os/server.h>
#include <root/component.h>
#include <base/heap.h>
#include <base/component.h>
/* local includes */
#include <sync_session/connection.h>
namespace Sync
using namespace Genode;
class Sync_root;
struct Session_component : public Rpc_object<Sync::Session>
{
enum { NR_OF_SIGNALS = 1 };
Sync_root &root;
using Server::Entrypoint;
using Genode::Rpc_object;
using Genode::env;
using Genode::Root_component;
using Genode::Allocator;
using Genode::Signal_transmitter;
Session_component(Sync_root &root) : root(root) { }
class Signal;
class Session_component;
class Root;
struct Main;
void threshold(unsigned threshold) override;
void submit(Signal_context_capability signal) override;
};
struct Sync_root : public Root_component<Session_component>
{
Signal_transmitter transmitters[9];
unsigned submitted { 0 };
unsigned threshold { 0 };
void check()
{
if (submitted < threshold) { return; }
for (unsigned i = 0; i < submitted; i++) {
transmitters[i].submit(); }
submitted = 0;
}
Session_component *_create_session(char const *args) override
{
try { return new (md_alloc()) Session_component(*this); }
catch (...) { throw Root::Exception(); }
}
Sync_root(Entrypoint &ep, Allocator &md_alloc)
: Root_component<Session_component>(ep, md_alloc) { }
};
void Session_component::threshold(unsigned threshold)
{
root.threshold = threshold;
root.check();
}
class Sync::Signal
void Session_component::submit(Signal_context_capability signal)
{
friend class Root;
private:
enum { NR_OF_TRANSMITTERS = 9 };
Signal_transmitter _transmitters[NR_OF_TRANSMITTERS];
unsigned _submitted;
unsigned _threshold;
void _check()
{
if (_submitted < _threshold) { return; }
for (unsigned i = 0; i < _submitted; i++) {
_transmitters[i].submit(); }
_submitted = 0;
}
void _reset()
{
_submitted = 0;
_threshold = 0;
}
public:
void threshold(unsigned const threshold)
{
_threshold = threshold;
_check();
}
void submit(Signal_context_capability & sigc)
{
_transmitters[_submitted] = Signal_transmitter(sigc);
_submitted++;
_check();
}
};
class Sync::Session_component : public Rpc_object<Session>
{
private:
Signal * const _signals;
public:
Session_component(Signal * const signals) : _signals(signals) { }
void threshold(unsigned id, unsigned threshold) override
{
if (id >= NR_OF_SIGNALS) { return; }
_signals[id].threshold(threshold);
}
void
submit(unsigned const id, Signal_context_capability sigc) override
{
if (id >= NR_OF_SIGNALS) { return; }
_signals[id].submit(sigc);
}
};
class Sync::Root : public Root_component<Session_component>
{
private:
Signal _signals[NR_OF_SIGNALS];
protected:
Session_component *_create_session(const char *args)
{
try { return new (md_alloc()) Session_component(_signals); }
catch (...) { throw Root::Exception(); }
}
public:
Root(Entrypoint & ep, Allocator & md_alloc)
: Root_component<Session_component>(&ep.rpc_ep(), &md_alloc)
{
for (unsigned i = 0; i < NR_OF_SIGNALS; i++) {
_signals[i]._reset(); }
}
};
struct Sync::Main
{
Server::Entrypoint & ep;
Root root;
Main(Server::Entrypoint & ep) : ep(ep), root(ep, *env()->heap()) {
env()->parent()->announce(ep.manage(root)); }
};
/************
** Server **
************/
namespace Server
{
using namespace Sync;
char const *name() { return "sync_ep"; }
size_t stack_size() { return 16*1024*sizeof(long); }
void construct(Entrypoint & ep) { static Main main(ep); }
root.transmitters[root.submitted] = Signal_transmitter(signal);
root.submitted++;
root.check();
}
struct Main
{
Env &env;
Heap heap { env.ram(), env.rm() };
Sync_root root { env.ep(), heap };
Main(Env &env) : env(env) { env.parent().announce(env.ep().manage(root)); }
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -1,17 +1,4 @@
#
# \brief Provide cross-component synchronization
# \author Martin Stein
# \date 2014-10-13
#
# Set program name
TARGET = test-sync
# Add C++ sources
SRC_CC = main.cc
# Add include paths
TARGET = test-sync
SRC_CC += main.cc
INC_DIR += $(PRG_DIR)/../include
# Add libraries
LIBS = base server
LIBS += base

View File

@ -1,17 +1,4 @@
#
# \brief Test the distribution and application of CPU quota
# \author Martin Stein
# \date 2014-10-13
#
# Set program name
TARGET = test-cpu_quota
# Add C++ sources
SRC_CC += main.cc
# Add include paths
TARGET = test-cpu_quota
SRC_CC += main.cc
INC_DIR += $(PRG_DIR)/include
# Add libraries
LIBS += base
LIBS += base