CPU session: apply quota via relative weightings

Physical CPU quota was previously given to a thread on construction only
by directly specifying a percentage of the quota of the according CPU
session. Now, a new thread is given a weighting that can be any value.
The physical counter-value of such a weighting depends on the weightings
of the other threads at the CPU session. Thus, the physical quota of all
threads of a CPU session must be updated when a weighting is added or
removed. This is each time the session creates or destroys a thread.

This commit also adapts the "cpu_quota" test in base-hw accordingly.

Ref #1464
devel
Martin Stein 8 years ago committed by Christian Helmuth
parent 955977b516
commit c9272937e7

@ -55,7 +55,8 @@ void Thread_base::start()
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(0, buf);
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
_thread_cap = _cpu_session->create_thread(WEIGHT, buf);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);

@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
return Ram_dataspace_capability();
}
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }

@ -152,6 +152,11 @@ namespace Genode {
***********************/
addr_t utcb() const { return _utcb; }
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota) { /* not supported*/ }
};
}

@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
return Ram_dataspace_capability();
}
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }

@ -150,6 +150,11 @@ namespace Genode {
unsigned long pager_object_badge() const {
return convert_native_thread_id_to_badge(_l4_thread_id); }
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota) { /* not supported*/ }
/*******************************
** Fiasco-specific Accessors **

@ -25,8 +25,8 @@ namespace Genode {
explicit Foc_cpu_session_client(Cpu_session_capability session)
: Rpc_client<Foc_cpu_session>(static_cap_cast<Foc_cpu_session>(session)) { }
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(0, name, utcb); }
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(weight, name, utcb); }
Ram_dataspace_capability utcb(Thread_capability thread) {
return call<Rpc_utcb>(thread); }
@ -100,9 +100,7 @@ namespace Genode {
int transfer_quota(Cpu_session_capability session, size_t amount) {
return call<Rpc_transfer_quota>(session, amount); }
size_t quota() { return call<Rpc_quota>(); }
size_t used() { return call<Rpc_used>(); }
Quota quota() override { return call<Rpc_quota>(); }
};
}

@ -186,7 +186,7 @@ void Thread_base::free_secondary_stack(void* stack_addr)
}
Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
Type const type, Cpu_session *cpu_session)
:
_cpu_session(cpu_session),
@ -195,13 +195,13 @@ Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
_join_lock(Lock::LOCKED)
{
strncpy(_context->name, name, sizeof(_context->name));
_init_platform_thread(0, type);
_init_platform_thread(weight, type);
}
Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
Type type)
: Thread_base(0, name, stack_size, type, nullptr) { }
: Thread_base(weight, name, stack_size, type, nullptr) { }
Thread_base::~Thread_base()

@ -39,7 +39,7 @@ void Thread_base::_deinit_platform_thread()
}
void Thread_base::_init_platform_thread(size_t, Type type)
void Thread_base::_init_platform_thread(size_t weight, Type type)
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
@ -50,7 +50,7 @@ void Thread_base::_init_platform_thread(size_t, Type type)
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(0, buf);
_thread_cap = _cpu_session->create_thread(weight, buf);
/* assign thread to protection domain */
if (!_thread_cap.valid() ||

@ -107,3 +107,6 @@ void Genode::Cpu_session_component::single_step(Genode::Thread_capability thread
Fiasco::l4_thread_ex_regs(tid, ~0UL, ~0UL, flags);
}
Genode::Cpu_session::Quota Genode::Cpu_session_component::quota() { return Quota(); }

@ -64,7 +64,9 @@ namespace Genode {
public:
Cpu_thread_component(size_t, Session_label const &label,
Cpu_thread_component(size_t const weight,
size_t const quota,
Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Signal_context_capability sigh,
@ -88,7 +90,8 @@ namespace Genode {
bool bound() const { return _bound; }
void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; }
size_t quota() { return 0; }
size_t weight() const { return Cpu_session::DEFAULT_WEIGHT; }
void sigh(Signal_context_capability sigh)
{
@ -138,24 +141,26 @@ namespace Genode {
session */
Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area;
Cpu_session_component * _ref;
size_t _used;
size_t _weight;
size_t _quota;
Cpu_session_component * _ref;
List<Cpu_session_component> _ref_members;
Lock _ref_members_lock;
size_t _global_to_local(size_t const q) const { return 0; }
size_t _avail() { return 0; }
void _deinit_ref_account();
void _deinit_threads();
size_t _local_to_global(size_t) const { return 0; }
void _insuff_for_consume(size_t);
int _insuff_for_transfer(size_t);
int _transfer_back(size_t) { return -1; }
int _transfer_forth(Cpu_session_component *, size_t) { return -1; }
void _incr_weight(size_t);
void _decr_weight(size_t);
size_t _weight_to_quota(size_t) const;
void _decr_quota(size_t);
void _incr_quota(size_t);
void _update_thread_quota(Cpu_thread_component *) const;
void _update_each_thread_quota();
void _transfer_quota(Cpu_session_component *, size_t);
void _insert_ref_member(Cpu_session_component *) { }
void _remove_ref_member(Cpu_session_component *) { }
void _unsync_remove_ref_member(Cpu_session_component *) { }
void _remove_ref_member(Cpu_session_component *) { }
void _deinit_ref_account();
void _deinit_threads();
/**
* Exception handler that will be invoked unless overridden by a
@ -224,8 +229,7 @@ namespace Genode {
Dataspace_capability trace_policy(Thread_capability);
int ref_account(Cpu_session_capability c);
int transfer_quota(Cpu_session_capability c, size_t q);
size_t used();
size_t quota();
Quota quota() override;
/***********************************

@ -167,6 +167,11 @@ namespace Genode {
unsigned long pager_object_badge() {
return (unsigned long) _thread.local.dst(); }
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota) { /* not supported*/ }
/*******************************
** Fiasco-specific Accessors **

@ -1,161 +0,0 @@
#
# Build
#
build "core init drivers/timer test/cpu_quota"
#
# Boot image
#
create_boot_directory
install_config {
<config prio_levels="4">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="10M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="init_1" priority="-1">
<binary name="init"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="10"/>
<config prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<!-- should receive 10 % of the CPU time -->
<start name="test_slow" priority="-1">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="50"/>
</start>
</config>
</start>
<start name="init_2" priority="-2">
<binary name="init"/>
<resource name="RAM" quantum="100M"/>
<resource name="CPU" quantum="80"/>
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="RM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
</parent-provides>
<default-route>
<any-service><parent/></any-service>
</default-route>
<!-- should receive 25 % of the CPU time -->
<start name="test_middle">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="25"/>
</start>
<!-- should receive 65 % of the CPU time -->
<start name="test_fast">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="75"/>
</start>
</config>
</start>
</config>
}
build_boot_image "core init timer test-cpu_quota"
#
# Execution
#
append qemu_args "-nographic -m 64"
run_genode_until "test.*\n.*test.*\n.*test.*\n" 60
#
# Conclusion
#
set slow_opt 0.10
set middle_opt 0.25
set fast_opt 0.65
set err 0.02
regexp {[0-9]+} [regexp -inline {slow.*[0-9]+} $output] slow_cnt
regexp {[0-9]+} [regexp -inline {middle.*[0-9]+} $output] middle_cnt
regexp {[0-9]+} [regexp -inline {fast.*[0-9]+} $output] fast_cnt
set total_cnt [expr $fast_cnt + $middle_cnt + $slow_cnt]
set slow_fac [expr $slow_cnt / double($total_cnt) ]
set middle_fac [expr $middle_cnt / double($total_cnt) ]
set fast_fac [expr $fast_cnt / double($total_cnt) ]
set failed 0
if {[expr $slow_fac > $slow_opt + $err || $slow_fac < $slow_opt - $err]} {
set is_pc [expr round($slow_fac * 10000) / 100]
set opt_pc [expr round($slow_opt * 10000) / 100]
puts stderr "Error: Slow counter received $is_pc% of the CPU time."
puts stderr " Should receive $opt_pc%."
set failed 1
}
if {[expr $middle_fac > $middle_opt + $err || $middle_fac < $middle_opt - $err]} {
set is_pc [expr round($middle_fac * 10000) / 100]
set opt_pc [expr round($middle_opt * 10000) / 100]
puts stderr "Error: Middle counter received $is_pc% of the CPU time."
puts stderr " Should receive $opt_pc%."
set failed 1
}
if {[expr $fast_fac > $fast_opt + $err || $fast_fac < $fast_opt - $err]} {
set is_pc [expr round($fast_fac * 10000) / 100]
set opt_pc [expr round($fast_opt * 10000) / 100]
puts stderr "Error: Fast counter received $is_pc% of the CPU time."
puts stderr " Should receive $opt_pc%."
set failed 1
}
if {$failed} {
exit -1
} else {
puts "Test succeeded"
}

@ -30,7 +30,7 @@ extern Native_thread_id _main_thread_id;
** Thread_base **
*****************/
void Thread_base::_init_platform_thread(size_t quota, Type type)
void Thread_base::_init_platform_thread(size_t weight, Type type)
{
if (!_cpu_session) { _cpu_session = env()->cpu_session(); }
if (type == NORMAL) {
@ -38,7 +38,8 @@ void Thread_base::_init_platform_thread(size_t quota, Type type)
/* create server object */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(quota, buf, (addr_t)&_context->utcb);
addr_t const utcb = (addr_t)&_context->utcb;
_thread_cap = _cpu_session->create_thread(weight, buf, utcb);
return;
}
/* if we got reinitialized we have to get rid of the old UTCB */

@ -16,6 +16,7 @@
/* core includes */
#include <cpu_session_component.h>
#include <kernel/configuration.h>
using namespace Genode;
@ -30,3 +31,10 @@ Cpu_session_component::utcb(Thread_capability thread_cap)
return t->platform_thread()->utcb();
}
Cpu_session::Quota Cpu_session_component::quota()
{
size_t const spu = Kernel::cpu_quota_ms * 1000;
size_t const u = quota_lim_downscale<sizet_arithm_t>(_quota, spu);
return { spu, u };
}

@ -157,6 +157,11 @@ class Kernel::Thread
*/
int _read_reg(addr_t const id, addr_t & value) const;
/**
* Return amount of timer tics that 'quota' is worth
*/
size_t _core_to_kernel_quota(size_t const quota) const;
/**
* Override a thread register
*

@ -75,12 +75,6 @@ namespace Genode {
*/
bool _attaches_utcb_by_itself();
static size_t _generic_to_platform_quota(size_t const q)
{
assert(Kernel::cpu_quota_ms <= Cpu_session::QUOTA_LIMIT);
return (q * Kernel::cpu_quota_ms) >> 15;
}
public:
/**
@ -143,6 +137,11 @@ namespace Genode {
*/
void cancel_blocking() { resume(); }
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota);
/**
* Get raw thread state
*/

@ -29,6 +29,8 @@ namespace Genode
* CPU driver for core
*/
class Arm;
typedef Genode::uint64_t sizet_arithm_t;
}
class Genode::Arm

@ -13,8 +13,8 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_H_
#define _CPU_H_
#ifndef _SPEC__X86__CPU_SUPPORT_H_
#define _SPEC__X86__CPU_SUPPORT_H_
/* Genode includes */
#include <util/register.h>
@ -445,4 +445,4 @@ class Genode::Cpu
};
#endif /* _CPU_H_ */
#endif /* _SPEC__X86__CPU_SUPPORT_H_ */

@ -0,0 +1,22 @@
/*
* \brief CPU driver for core
* \author Martin stein
* \date 2015-04-20
*/
/*
* 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 _CPU_H_
#define _CPU_H_
/* core includes */
#include <spec/x86/cpu_support.h>
namespace Genode { typedef __uint128_t sizet_arithm_t; }
#endif /* _CPU_H_ */

@ -46,6 +46,8 @@ extern void * _start_secondary_cpus;
extern int _prog_img_beg;
extern int _prog_img_end;
static_assert(sizeof(Genode::sizet_arithm_t) >= 2 * sizeof(size_t),
"Bad result type for size_t arithmetics.");
namespace Kernel
{

@ -15,6 +15,7 @@
/* Genode includes */
#include <base/thread_state.h>
#include <unmanaged_singleton.h>
#include <cpu_session/cpu_session.h>
/* core includes */
#include <kernel/kernel.h>
@ -224,12 +225,21 @@ void Thread::_call_new_pd()
void Thread::_call_delete_pd() { reinterpret_cast<Pd*>(user_arg_1())->~Pd(); }
size_t Thread::_core_to_kernel_quota(size_t const quota) const
{
using Genode::Cpu_session;
using Genode::sizet_arithm_t;
size_t const tics = cpu_pool()->timer()->ms_to_tics(Kernel::cpu_quota_ms);
return Cpu_session::quota_lim_downscale<sizet_arithm_t>(quota, tics);
}
void Thread::_call_new_thread()
{
/* create new thread */
void * const p = (void *)user_arg_1();
unsigned const priority = user_arg_2();
unsigned const quota = cpu_pool()->timer()->ms_to_tics(user_arg_3());
unsigned const quota = _core_to_kernel_quota(user_arg_3());
char const * const label = (char *)user_arg_4();
Thread * const t = new (p) Thread(priority, quota, label);
user_arg_0(t->id());
@ -239,8 +249,7 @@ void Thread::_call_new_thread()
void Thread::_call_thread_quota()
{
Thread * const thread = (Thread *)user_arg_1();
unsigned const quota = cpu_pool()->timer()->ms_to_tics(user_arg_2());
thread->Cpu_job::quota(quota);
thread->Cpu_job::quota(_core_to_kernel_quota(user_arg_2()));
}

@ -78,6 +78,10 @@ Platform_thread::~Platform_thread()
}
void Platform_thread::quota(size_t const quota) {
Kernel::thread_quota((Kernel::Thread *)_kernel_thread, quota); }
Platform_thread::Platform_thread(const char * const label,
Native_utcb * utcb)
: _pd(Kernel::core_pd()->platform_pd()),
@ -110,7 +114,8 @@ Platform_thread::Platform_thread(const char * const label,
}
Platform_thread::Platform_thread(size_t quota, const char * const label,
Platform_thread::Platform_thread(size_t const quota,
const char * const label,
unsigned const virt_prio,
addr_t const utcb)
:
@ -139,7 +144,6 @@ Platform_thread::Platform_thread(size_t quota, const char * const label,
/* create kernel object */
constexpr unsigned max_prio = Kernel::Cpu_priority::max;
auto const phys_prio = Cpu_session::scale_priority(max_prio, virt_prio);
quota = _generic_to_platform_quota(quota);
_id = Kernel::new_thread(_kernel_thread, phys_prio, quota, _label);
if (!_id) {
PERR("failed to create kernel object");

@ -0,0 +1,30 @@
/*
* \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_ */

@ -0,0 +1,43 @@
/*
* \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_ */

@ -0,0 +1,59 @@
/*
* \brief Connection to Sync service
* \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__CONNECTION_H_
#define _SYNC_SESSION__CONNECTION_H_
/* Genode includes */
#include <base/connection.h>
/* local includes */
#include <sync_session/client.h>
namespace Sync
{
using Genode::Parent;
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() :
Genode::Connection<Session>(_create_session()),
Session_client(cap())
{ }
};
#endif /* _SYNC_SESSION__CONNECTION_H_ */

@ -0,0 +1,56 @@
/*
* \brief 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__SYNC_SESSION_H_
#define _SYNC_SESSION__SYNC_SESSION_H_
/* Genode includes */
#include <session/session.h>
#include <signal_session/signal_session.h>
namespace Sync
{
using Genode::Signal_context_capability;
struct 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;
/**
* 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_INTERFACE(Rpc_threshold, Rpc_submit);
};
#endif /* _SYNC_SESSION__SYNC_SESSION_H_ */

@ -1,5 +1,5 @@
/*
* \brief Diversified test of the Register and MMIO framework
* \brief Test the distribution and application of CPU quota
* \author Martin Stein
* \date 2012-01-09
*/
@ -14,50 +14,150 @@
/* Genode includes */
#include <base/printf.h>
#include <base/thread.h>
#include <base/env.h>
#include <base/sleep.h>
#include <timer_session/connection.h>
#include <sync_session/connection.h>
using namespace Genode;
class My_thread : public Thread<8 * 1024>
enum { SYNC_SIG = 0 };
namespace Sync { class Signal; }
class Single_signal
{
private:
Signal_receiver * const _sigr;
bool volatile _stop;
Signal_receiver _sigr;
Signal_context _sigx;
Signal_context_capability _sigc;
Signal_transmitter _sigt;
public:
My_thread(Signal_receiver * const sigr)
: Thread(Cpu_session::pc_to_quota(100), "counter"),
_sigr(sigr), _stop(0) { }
Single_signal() : _sigc(_sigr.manage(&_sigx)), _sigt(_sigc) { }
~Single_signal() { _sigr.dissolve(&_sigx); }
void receive() { _sigr.wait_for_signal(); }
void submit() { _sigt.submit(); }
};
class Sync::Signal
{
private:
Signal_receiver _sigr;
Signal_context _sigx;
Signal_context_capability _sigc;
Session * const _session;
unsigned const _id;
public:
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();
}
};
class Counter : private Thread<8 * 1024>
{
private:
char const _name;
unsigned volatile _value;
Sync::Signal _sync_sig;
unsigned volatile _stage;
Single_signal _stage_1_end;
Single_signal _stage_2_reached;
inline void _stage_0_and_1(unsigned volatile & value)
{
_stage_1_end.receive();
_stage = 0;
_sync_sig.sync();
while(_stage == 0) { value++; }
}
void entry()
{
_sigr->wait_for_signal();
unsigned volatile i = 0;
while(!_stop) { i++; }
printf("%u\n", i);
unsigned volatile value = 0;
while (_stage < 2) { _stage_0_and_1(value); }
_value = value;
_stage_2_reached.submit();
sleep_forever();
}
void stop() { _stop = 1; }
public:
Counter(char const name, size_t const weight,
Sync::Session * const sync)
:
Thread(weight, "counter"), _name(name), _value(0) ,
_sync_sig(sync, SYNC_SIG), _stage(1)
{
Thread::start();
}
void destruct()
{
_stage = 2;
_stage_2_reached.receive();
this->~Counter();
}
void pause() { _stage = 1; }
void go() { _stage_1_end.submit(); }
void result() { printf("counter %c %u\n", _name, _value); }
};
int main()
{
/* prepare */
Timer::Connection timer;
Signal_receiver sigr;
Signal_context sigx;
Signal_context_capability sigc = sigr.manage(&sigx);
Signal_transmitter sigt(sigc);
My_thread thread(&sigr);
thread.start();
timer.msleep(3000);
sigt.submit();
timer.msleep(30000);
thread.stop();
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);
/* measure stage 1 */
sync_sig.threshold(9);
counter_a.go();
counter_b.go();
sync_sig.sync();
timer.msleep(45000);
counter_a.pause();
counter_b.destruct();
/* measure stage 2 */
sync_sig.threshold(6);
counter_a.go();
sync_sig.sync();
timer.msleep(15000);
counter_a.destruct();
/* print results */
sync_sig.threshold(3);
sync_sig.sync();
Cpu_session::Quota quota = Genode::env()->cpu_session()->quota();
Genode::printf("quota super period %zu\n", quota.super_period_us);
Genode::printf("quota %zu\n", quota.us);
counter_a.result();
counter_b.result();
printf("done\n");
sleep_forever();
}

@ -0,0 +1,152 @@
/*
* \brief Provide sync signals for cross-component synchronization
* \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.
*/
/* Genode includes */
#include <os/server.h>
#include <root/component.h>
/* local includes */
#include <sync_session/connection.h>
namespace Sync
{
enum { NR_OF_SIGNALS = 1 };
using Server::Entrypoint;
using Genode::Rpc_object;
using Genode::env;
using Genode::Root_component;
using Genode::Allocator;
using Genode::Signal_transmitter;
class Signal;
class Session_component;
class Root;
struct Main;
}
class Sync::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 2 * 1024 * sizeof(long); }
void construct(Entrypoint & ep) { static Main main(ep); }
}

@ -0,0 +1,17 @@
#
# \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
INC_DIR += $(PRG_DIR)/../include
# Add libraries
LIBS = base server

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

@ -24,8 +24,8 @@ namespace Genode {
explicit Linux_cpu_session_client(Capability<Linux_cpu_session> session)
: Rpc_client<Linux_cpu_session>(session) { }
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(0, name, utcb); }
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb = 0) {
return call<Rpc_create_thread>(weight, name, utcb); }
Ram_dataspace_capability utcb(Thread_capability thread) {
return call<Rpc_utcb>(thread); }
@ -84,9 +84,7 @@ namespace Genode {
int transfer_quota(Cpu_session_capability session, size_t amount) {
return call<Rpc_transfer_quota>(session, amount); }
size_t quota() { return call<Rpc_quota>(); }
size_t used() { return call<Rpc_used>(); }
Quota quota() override { return call<Rpc_quota>(); }
/*****************************
* Linux-specific extension **

@ -44,10 +44,10 @@ struct Genode::Expanding_cpu_session_client
Expanding_cpu_session_client(Genode::Capability<Linux_cpu_session> cap)
: Upgradeable_client<Genode::Linux_cpu_session_client>(cap) { }
Thread_capability create_thread(size_t, Name const &name, addr_t utcb)
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb)
{
return retry<Cpu_session::Out_of_metadata>(
[&] () { return Linux_cpu_session_client::create_thread(0, name, utcb); },
[&] () { return Linux_cpu_session_client::create_thread(weight, name, utcb); },
[&] () { upgrade_ram(8*1024); });
}
};

@ -80,7 +80,8 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
* thread. Those information will be provided to core by the constructor of
* the 'Platform_env' of the new process.
*/
_thread0_cap = _cpu_session_client.create_thread(0, name);
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
_thread0_cap = _cpu_session_client.create_thread(WEIGHT, name);
Linux_pd_session_client lx_pd(static_cap_cast<Linux_pd_session>(_pd.cap()));

@ -69,7 +69,7 @@ void Thread_base::_thread_start()
}
void Thread_base::_init_platform_thread(size_t, Type type)
void Thread_base::_init_platform_thread(size_t weight, Type type)
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
@ -77,7 +77,7 @@ void Thread_base::_init_platform_thread(size_t, Type type)
/* for normal threads create an object at the CPU session */
if (type == NORMAL) {
_thread_cap = _cpu_session->create_thread(0, _context->name);
_thread_cap = _cpu_session->create_thread(weight, _context->name);
return;
}
/* adjust initial object state for main threads */

@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
return Ram_dataspace_capability();
}
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }

@ -63,7 +63,9 @@ namespace Genode {
public:
Cpu_thread_component(size_t, Session_label const &label,
Cpu_thread_component(size_t const weight,
size_t const quota,
Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Signal_context_capability sigh,
@ -87,7 +89,8 @@ namespace Genode {
bool bound() const { return _bound; }
void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; }
size_t quota() { return 0; }
size_t weight() const { return Cpu_session::DEFAULT_WEIGHT; }
void sigh(Signal_context_capability sigh)
{
@ -131,24 +134,26 @@ namespace Genode {
session */
Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area;
Cpu_session_component * _ref;
size_t _used;
size_t _weight;
size_t _quota;
Cpu_session_component * _ref;
List<Cpu_session_component> _ref_members;
Lock _ref_members_lock;
size_t _global_to_local(size_t const q) const { return 0; }
size_t _avail() { return 0; }
void _deinit_ref_account();
void _deinit_threads();
size_t _local_to_global(size_t) const { return 0; }
void _insuff_for_consume(size_t);
int _insuff_for_transfer(size_t);
int _transfer_back(size_t) { return -1; }
int _transfer_forth(Cpu_session_component *, size_t) { return -1; }
void _incr_weight(size_t);
void _decr_weight(size_t);
size_t _weight_to_quota(size_t) const;
void _decr_quota(size_t);
void _incr_quota(size_t);
void _update_thread_quota(Cpu_thread_component *) const;
void _update_each_thread_quota();
void _transfer_quota(Cpu_session_component *, size_t);
void _insert_ref_member(Cpu_session_component *) { }
void _remove_ref_member(Cpu_session_component *) { }
void _unsync_remove_ref_member(Cpu_session_component *) { }
void _remove_ref_member(Cpu_session_component *) { }
void _deinit_ref_account();
void _deinit_threads();
/**
* Exception handler that will be invoked unless overridden by a
@ -214,8 +219,7 @@ namespace Genode {
Dataspace_capability trace_policy(Thread_capability);
int ref_account(Cpu_session_capability c);
int transfer_quota(Cpu_session_capability c, size_t q);
size_t used();
size_t quota();
Quota quota() override;
/*******************************

@ -153,6 +153,11 @@ namespace Genode {
{
_registry()->submit_exception(pid);
}
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota) { /* not supported*/ }
};
}

@ -401,7 +401,7 @@ void Thread_base::join()
}
Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
Type type, Cpu_session * cpu_sess)
: _cpu_session(cpu_sess)
{