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
This commit is contained in:
Martin Stein 2015-03-27 14:05:55 +01:00 committed by Christian Helmuth
parent 955977b516
commit c9272937e7
71 changed files with 1230 additions and 483 deletions

View File

@ -55,7 +55,8 @@ void Thread_base::start()
/* create thread at core */ /* create thread at core */
char buf[48]; char buf[48];
name(buf, sizeof(buf)); 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 */ /* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap); env()->pd_session()->bind_thread(_thread_cap);

View File

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

View File

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

View File

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

View File

@ -150,6 +150,11 @@ namespace Genode {
unsigned long pager_object_badge() const { unsigned long pager_object_badge() const {
return convert_native_thread_id_to_badge(_l4_thread_id); } 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 ** ** Fiasco-specific Accessors **

View File

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

View File

@ -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) Type const type, Cpu_session *cpu_session)
: :
_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) _join_lock(Lock::LOCKED)
{ {
strncpy(_context->name, name, sizeof(_context->name)); 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) Type type)
: Thread_base(0, name, stack_size, type, nullptr) { } : Thread_base(weight, name, stack_size, type, nullptr) { }
Thread_base::~Thread_base() Thread_base::~Thread_base()

View File

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

View File

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

View File

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

View File

@ -167,6 +167,11 @@ namespace Genode {
unsigned long pager_object_badge() { unsigned long pager_object_badge() {
return (unsigned long) _thread.local.dst(); } 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 ** ** Fiasco-specific Accessors **

View File

@ -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"
}

View File

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

View File

@ -16,6 +16,7 @@
/* core includes */ /* core includes */
#include <cpu_session_component.h> #include <cpu_session_component.h>
#include <kernel/configuration.h>
using namespace Genode; using namespace Genode;
@ -30,3 +31,10 @@ Cpu_session_component::utcb(Thread_capability thread_cap)
return t->platform_thread()->utcb(); 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 };
}

View File

@ -157,6 +157,11 @@ class Kernel::Thread
*/ */
int _read_reg(addr_t const id, addr_t & value) const; 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 * Override a thread register
* *

View File

@ -75,12 +75,6 @@ namespace Genode {
*/ */
bool _attaches_utcb_by_itself(); 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: public:
/** /**
@ -143,6 +137,11 @@ namespace Genode {
*/ */
void cancel_blocking() { resume(); } void cancel_blocking() { resume(); }
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota);
/** /**
* Get raw thread state * Get raw thread state
*/ */

View File

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

View File

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

View File

@ -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_ */

View File

@ -46,6 +46,8 @@ extern void * _start_secondary_cpus;
extern int _prog_img_beg; extern int _prog_img_beg;
extern int _prog_img_end; 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 namespace Kernel
{ {

View File

@ -15,6 +15,7 @@
/* Genode includes */ /* Genode includes */
#include <base/thread_state.h> #include <base/thread_state.h>
#include <unmanaged_singleton.h> #include <unmanaged_singleton.h>
#include <cpu_session/cpu_session.h>
/* core includes */ /* core includes */
#include <kernel/kernel.h> #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(); } 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() void Thread::_call_new_thread()
{ {
/* create new thread */ /* create new thread */
void * const p = (void *)user_arg_1(); void * const p = (void *)user_arg_1();
unsigned const priority = user_arg_2(); 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(); char const * const label = (char *)user_arg_4();
Thread * const t = new (p) Thread(priority, quota, label); Thread * const t = new (p) Thread(priority, quota, label);
user_arg_0(t->id()); user_arg_0(t->id());
@ -239,8 +249,7 @@ void Thread::_call_new_thread()
void Thread::_call_thread_quota() void Thread::_call_thread_quota()
{ {
Thread * const thread = (Thread *)user_arg_1(); Thread * const thread = (Thread *)user_arg_1();
unsigned const quota = cpu_pool()->timer()->ms_to_tics(user_arg_2()); thread->Cpu_job::quota(_core_to_kernel_quota(user_arg_2()));
thread->Cpu_job::quota(quota);
} }

View File

@ -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, Platform_thread::Platform_thread(const char * const label,
Native_utcb * utcb) Native_utcb * utcb)
: _pd(Kernel::core_pd()->platform_pd()), : _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, unsigned const virt_prio,
addr_t const utcb) addr_t const utcb)
: :
@ -139,7 +144,6 @@ Platform_thread::Platform_thread(size_t quota, const char * const label,
/* create kernel object */ /* create kernel object */
constexpr unsigned max_prio = Kernel::Cpu_priority::max; constexpr unsigned max_prio = Kernel::Cpu_priority::max;
auto const phys_prio = Cpu_session::scale_priority(max_prio, virt_prio); 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); _id = Kernel::new_thread(_kernel_thread, phys_prio, quota, _label);
if (!_id) { if (!_id) {
PERR("failed to create kernel object"); PERR("failed to create kernel object");

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 * \author Martin Stein
* \date 2012-01-09 * \date 2012-01-09
*/ */
@ -14,50 +14,150 @@
/* Genode includes */ /* Genode includes */
#include <base/printf.h> #include <base/printf.h>
#include <base/thread.h> #include <base/thread.h>
#include <base/env.h>
#include <base/sleep.h> #include <base/sleep.h>
#include <timer_session/connection.h> #include <timer_session/connection.h>
#include <sync_session/connection.h>
using namespace Genode; using namespace Genode;
class My_thread : public Thread<8 * 1024> enum { SYNC_SIG = 0 };
namespace Sync { class Signal; }
class Single_signal
{ {
private: private:
Signal_receiver * const _sigr; Signal_receiver _sigr;
bool volatile _stop; Signal_context _sigx;
Signal_context_capability _sigc;
Signal_transmitter _sigt;
public: public:
My_thread(Signal_receiver * const sigr) Single_signal() : _sigc(_sigr.manage(&_sigx)), _sigt(_sigc) { }
: Thread(Cpu_session::pc_to_quota(100), "counter"),
_sigr(sigr), _stop(0) { } ~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() void entry()
{ {
_sigr->wait_for_signal(); unsigned volatile value = 0;
unsigned volatile i = 0; while (_stage < 2) { _stage_0_and_1(value); }
while(!_stop) { i++; } _value = value;
printf("%u\n", i); _stage_2_reached.submit();
sleep_forever(); 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() int main()
{ {
/* prepare */
Timer::Connection timer; Timer::Connection timer;
Signal_receiver sigr; Sync::Connection sync;
Signal_context sigx; Sync::Signal sync_sig(&sync, SYNC_SIG);
Signal_context_capability sigc = sigr.manage(&sigx); Counter counter_a('A', Cpu_session::quota_lim_upscale(10, 100), &sync);
Signal_transmitter sigt(sigc); Counter counter_b('B', Cpu_session::quota_lim_upscale(90, 100), &sync);
My_thread thread(&sigr);
thread.start(); /* measure stage 1 */
timer.msleep(3000); sync_sig.threshold(9);
sigt.submit(); counter_a.go();
timer.msleep(30000); counter_b.go();
thread.stop(); 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(); sleep_forever();
} }

View File

@ -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); }
}

View File

@ -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

View File

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

View File

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

View File

@ -44,10 +44,10 @@ struct Genode::Expanding_cpu_session_client
Expanding_cpu_session_client(Genode::Capability<Linux_cpu_session> cap) Expanding_cpu_session_client(Genode::Capability<Linux_cpu_session> cap)
: Upgradeable_client<Genode::Linux_cpu_session_client>(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 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); }); [&] () { upgrade_ram(8*1024); });
} }
}; };

View File

@ -80,7 +80,8 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
* thread. Those information will be provided to core by the constructor of * thread. Those information will be provided to core by the constructor of
* the 'Platform_env' of the new process. * 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())); Linux_pd_session_client lx_pd(static_cap_cast<Linux_pd_session>(_pd.cap()));

View File

@ -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 no cpu session is given, use it from the environment */
if (!_cpu_session) 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 */ /* for normal threads create an object at the CPU session */
if (type == NORMAL) { if (type == NORMAL) {
_thread_cap = _cpu_session->create_thread(0, _context->name); _thread_cap = _cpu_session->create_thread(weight, _context->name);
return; return;
} }
/* adjust initial object state for main threads */ /* adjust initial object state for main threads */

View File

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

View File

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

View File

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

View File

@ -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) Type type, Cpu_session * cpu_sess)
: _cpu_session(cpu_sess) : _cpu_session(cpu_sess)
{ {
@ -420,13 +420,14 @@ Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
Linux_cpu_session *cpu = cpu_session(_cpu_session); Linux_cpu_session *cpu = cpu_session(_cpu_session);
_thread_cap = cpu->create_thread(0, name); _thread_cap = cpu->create_thread(weight, name);
cpu->thread_id(_thread_cap, _tid.pid, _tid.tid); cpu->thread_id(_thread_cap, _tid.pid, _tid.tid);
} }
Thread_base::Thread_base(size_t, const char *name, size_t stack_size, Type type) Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
: Thread_base(0, name, stack_size, type, env()->cpu_session()) { } Type type)
: Thread_base(weight, name, stack_size, type, env()->cpu_session()) { }
void Thread_base::cancel_blocking() void Thread_base::cancel_blocking()
{ {

View File

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

View File

@ -599,7 +599,7 @@ Pager_object::~Pager_object()
Pager_activation_base::Pager_activation_base(const char *name, size_t stack_size) Pager_activation_base::Pager_activation_base(const char *name, size_t stack_size)
: :
Thread_base(0, name, stack_size), Thread_base(Cpu_session::DEFAULT_WEIGHT, name, stack_size),
_cap(Native_capability()), _ep(0), _cap_valid(Lock::LOCKED) _cap(Native_capability()), _ep(0), _cap_valid(Lock::LOCKED)
{ {
/* tell thread starting code on which CPU to let run the pager */ /* tell thread starting code on which CPU to let run the pager */

View File

@ -221,7 +221,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
const char *name, bool start_on_construction, const char *name, bool start_on_construction,
Affinity::Location location) Affinity::Location location)
: :
Thread_base(0, name, stack_size), Thread_base(Cpu_session::DEFAULT_WEIGHT, name, stack_size),
_curr_obj(start_on_construction ? 0 : (Rpc_object_base *)~0UL), _curr_obj(start_on_construction ? 0 : (Rpc_object_base *)~0UL),
_delay_start(Lock::LOCKED), _delay_start(Lock::LOCKED),
_cap_session(cap_session) _cap_session(cap_session)

View File

@ -65,7 +65,7 @@ void Thread_base::_thread_start()
** Thread base ** ** Thread base **
*****************/ *****************/
void Thread_base::_init_platform_thread(size_t, Type type) void Thread_base::_init_platform_thread(size_t weight, Type type)
{ {
using namespace Nova; using namespace Nova;
@ -101,7 +101,7 @@ void Thread_base::_init_platform_thread(size_t, Type type)
char buf[48]; char buf[48];
name(buf, sizeof(buf)); name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(0, buf); _thread_cap = _cpu_session->create_thread(weight, buf);
if (!_thread_cap.valid()) if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed(); throw Cpu_session::Thread_creation_failed();

View File

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

View File

@ -64,7 +64,9 @@ namespace Genode {
public: 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, Thread_name const &name,
unsigned priority, addr_t utcb, unsigned priority, addr_t utcb,
Signal_context_capability sigh, Signal_context_capability sigh,
@ -88,7 +90,8 @@ namespace Genode {
bool bound() const { return _bound; } bool bound() const { return _bound; }
void bound(bool b) { _bound = b; } void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; } 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) void sigh(Signal_context_capability sigh)
{ {
@ -138,24 +141,26 @@ namespace Genode {
session */ session */
Trace::Source_registry &_trace_sources; Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area; Trace::Control_area _trace_control_area;
Cpu_session_component * _ref;
size_t _used; size_t _weight;
size_t _quota; size_t _quota;
Cpu_session_component * _ref;
List<Cpu_session_component> _ref_members; List<Cpu_session_component> _ref_members;
Lock _ref_members_lock; Lock _ref_members_lock;
size_t _global_to_local(size_t const q) const { return 0; } void _incr_weight(size_t);
size_t _avail() { return 0; } 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 _unsync_remove_ref_member(Cpu_session_component *) { }
void _remove_ref_member(Cpu_session_component *) { }
void _deinit_ref_account(); void _deinit_ref_account();
void _deinit_threads(); 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 _insert_ref_member(Cpu_session_component *) { }
void _remove_ref_member(Cpu_session_component *) { }
void _unsync_remove_ref_member(Cpu_session_component *) { }
/** /**
* Exception handler that will be invoked unless overridden by a * Exception handler that will be invoked unless overridden by a
@ -222,8 +227,7 @@ namespace Genode {
Dataspace_capability trace_policy(Thread_capability); Dataspace_capability trace_policy(Thread_capability);
int ref_account(Cpu_session_capability c); int ref_account(Cpu_session_capability c);
int transfer_quota(Cpu_session_capability c, size_t q); int transfer_quota(Cpu_session_capability c, size_t q);
size_t used(); Quota quota() override;
size_t quota();
/****************************** /******************************

View File

@ -164,6 +164,11 @@ namespace Genode {
} }
Native_capability single_step(bool on); Native_capability single_step(bool on);
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota) { /* not supported*/ }
}; };
} }

View File

@ -41,6 +41,9 @@ class Irq_thread : public Thread_base
{ {
private: private:
enum { STACK_SIZE = 1024 * sizeof(addr_t) };
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
static void _thread_start() static void _thread_start()
{ {
Thread_base::myself()->entry(); Thread_base::myself()->entry();
@ -49,7 +52,8 @@ class Irq_thread : public Thread_base
public: public:
Irq_thread(char const *name) : Thread_base(0, name, 1024 * sizeof(addr_t)) { } Irq_thread(char const *name) : Thread_base(WEIGHT, name, STACK_SIZE)
{ }
/** /**
* Create global EC, associate it to SC * Create global EC, associate it to SC

View File

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

View File

@ -147,6 +147,11 @@ namespace Genode {
*/ */
Affinity::Location affinity() { return Affinity::Location(); } Affinity::Location affinity() { return Affinity::Location(); }
/**
* Set CPU quota of the thread
*/
void quota(size_t) { /* not supported */ }
/***************************** /*****************************
** OKL4-specific Accessors ** ** OKL4-specific Accessors **

View File

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

View File

@ -148,6 +148,11 @@ namespace Genode {
*/ */
Affinity::Location affinity(); Affinity::Location affinity();
/**
* Set CPU quota of the thread to 'quota'
*/
void quota(size_t const quota) { /* not supported*/ }
/********************************** /**********************************
** Pistachio-specific Accessors ** ** Pistachio-specific Accessors **

View File

@ -132,6 +132,8 @@ class Genode::Pager_activation_base: public Thread_base
{ {
private: private:
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
Native_capability _cap; Native_capability _cap;
Pager_entrypoint *_ep; /* entry point to which the Pager_entrypoint *_ep; /* entry point to which the
activation belongs */ activation belongs */
@ -142,9 +144,9 @@ class Genode::Pager_activation_base: public Thread_base
public: public:
Pager_activation_base(const char *name, size_t stack_size) : Pager_activation_base(const char *name, size_t stack_size)
Thread_base(0, name, stack_size), : Thread_base(WEIGHT, name, stack_size), _cap(Native_capability()),
_cap(Native_capability()), _ep(0), _cap_valid(Lock::LOCKED) { } _ep(0), _cap_valid(Lock::LOCKED) { }
/** /**
* Set entry point, which the activation serves * Set entry point, which the activation serves

View File

@ -330,10 +330,10 @@ class Genode::Thread_base
/** /**
* Hook for platform-specific constructor supplements * Hook for platform-specific constructor supplements
* *
* \param quota CPU quota that shall be granted to the thread * \param weight weighting regarding the CPU session quota
* \param type enables selection of special initialization * \param type enables selection of special initialization
*/ */
void _init_platform_thread(size_t quota, Type type); void _init_platform_thread(size_t weight, Type type);
public: public:
@ -347,14 +347,14 @@ class Genode::Thread_base
* at least set Context::ds_cap in a way that it references * at least set Context::ds_cap in a way that it references
* the dataspace of the already attached stack. * the dataspace of the already attached stack.
*/ */
Thread_base(size_t quota, const char *name, size_t stack_size, Thread_base(size_t weight, const char *name, size_t stack_size,
Type type); Type type);
/** /**
* Constructor * Constructor
* *
* \param quota CPU quota that shall be granted to the thread * \param weight weighting regarding the CPU session quota
* \param name thread name for DEBUGging * \param name thread name (for debugging)
* \param stack_size stack size * \param stack_size stack size
* *
* \throw Stack_too_large * \throw Stack_too_large
@ -366,10 +366,8 @@ class Genode::Thread_base
* internally used by the framework for storing thread-context * internally used by the framework for storing thread-context
* information such as the thread's name ('Context'). * information such as the thread's name ('Context').
*/ */
Thread_base(size_t quota, const char *name, size_t stack_size) Thread_base(size_t weight, const char *name, size_t stack_size)
: : Thread_base(weight, name, stack_size, NORMAL) { }
Thread_base(quota, name, stack_size, NORMAL)
{ }
/** /**
* Constructor * Constructor
@ -380,8 +378,8 @@ class Genode::Thread_base
* \noapi Using multiple CPU sessions within a single component is * \noapi Using multiple CPU sessions within a single component is
* an experimental feature. * an experimental feature.
* *
* \param quota CPU quota that shall be granted to the thread * \param weight weighting regarding the CPU session quota
* \param name thread name for debugging * \param name thread name (for debugging)
* \param stack_size stack size * \param stack_size stack size
* \param type enables selection of special construction * \param type enables selection of special construction
* \param cpu_session capability to cpu session used for construction * \param cpu_session capability to cpu session used for construction
@ -390,7 +388,7 @@ class Genode::Thread_base
* \throw Stack_alloc_failed * \throw Stack_alloc_failed
* \throw Context_alloc_failed * \throw Context_alloc_failed
*/ */
Thread_base(size_t quota, const char *name, size_t stack_size, Thread_base(size_t weight, const char *name, size_t stack_size,
Type type, Cpu_session *); Type type, Cpu_session *);
/** /**
@ -536,53 +534,54 @@ class Genode::Thread : public Thread_base
/** /**
* Constructor * Constructor
* *
* \param quota CPU quota that shall be granted to the thread * \param weight weighting regarding the CPU session quota
* \param name thread name (for debugging) * \param name thread name (for debugging)
* \param type enables selection of special construction * \param type enables selection of special construction
*/ */
explicit Thread(size_t quota, const char *name) explicit Thread(size_t weight, const char *name)
: Thread_base(quota, name, STACK_SIZE, Type::NORMAL) { } : Thread_base(weight, name, STACK_SIZE, Type::NORMAL) { }
/** /**
* Constructor * Constructor
* *
* \param quota CPU quota that shall be granted to the thread * \param weight weighting regarding the CPU session quota
* \param name thread name (for debugging) * \param name thread name (for debugging)
* \param type enables selection of special construction * \param type enables selection of special construction
* *
* \noapi * \noapi
*/ */
explicit Thread(size_t quota, const char *name, Type type) explicit Thread(size_t weight, const char *name, Type type)
: Thread_base(quota, name, STACK_SIZE, type) { } : Thread_base(weight, name, STACK_SIZE, type) { }
/** /**
* Constructor * Constructor
* *
* \param quota CPU quota that shall be granted to the thread * \param weight weighting regarding the CPU session quota
* \param name thread name (for debugging) * \param name thread name (for debugging)
* \param cpu_session thread created via specific cpu session * \param cpu_session thread created via specific cpu session
* *
* \noapi * \noapi
*/ */
explicit Thread(size_t quota, const char *name, Cpu_session * cpu_session) explicit Thread(size_t weight, const char *name,
: Thread_base(quota, name, STACK_SIZE, Type::NORMAL, cpu_session) Cpu_session * cpu_session)
{ } : Thread_base(weight, name, STACK_SIZE, Type::NORMAL, cpu_session) { }
/** /**
* Shortcut for 'Thread(0, name, type)' * Shortcut for 'Thread(DEFAULT_WEIGHT, name, type)'
* *
* \noapi * \noapi
*/ */
explicit Thread(const char *name, Type type = NORMAL) explicit Thread(const char *name, Type type = NORMAL)
: Thread_base(0, name, STACK_SIZE, type) { } : Thread_base(Cpu_session::DEFAULT_WEIGHT, name, STACK_SIZE, type) { }
/** /**
* Shortcut for 'Thread(0, name, cpu_session)' * Shortcut for 'Thread(DEFAULT_WEIGHT, name, cpu_session)'
* *
* \noapi * \noapi
*/ */
explicit Thread(const char *name, Cpu_session * cpu_session) explicit Thread(const char *name, Cpu_session * cpu_session)
: Thread_base(0, name, STACK_SIZE, Type::NORMAL, cpu_session) : Thread_base(Cpu_session::DEFAULT_WEIGHT, name, STACK_SIZE,
Type::NORMAL, cpu_session)
{ } { }
}; };

View File

@ -86,9 +86,7 @@ struct Genode::Cpu_session_client : Rpc_client<Cpu_session>
int transfer_quota(Cpu_session_capability session, size_t amount) override { int transfer_quota(Cpu_session_capability session, size_t amount) override {
return call<Rpc_transfer_quota>(session, amount); } return call<Rpc_transfer_quota>(session, amount); }
size_t quota() override { return call<Rpc_quota>(); } Quota quota() override { return call<Rpc_quota>(); }
size_t used() override { return call<Rpc_used>(); }
}; };
#endif /* _INCLUDE__CPU_SESSION__CLIENT_H_ */ #endif /* _INCLUDE__CPU_SESSION__CLIENT_H_ */

View File

@ -47,9 +47,15 @@ struct Genode::Cpu_session : Session
enum { QUOTA_LIMIT_LOG2 = 15 }; enum { QUOTA_LIMIT_LOG2 = 15 };
enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 }; enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 };
enum { DEFAULT_PRIORITY = 0 }; enum { DEFAULT_PRIORITY = 0 };
enum { DEFAULT_WEIGHT = 10 };
typedef Rpc_in_buffer<THREAD_NAME_LEN> Name; typedef Rpc_in_buffer<THREAD_NAME_LEN> Name;
/**
* Physical quota configuration
*/
struct Quota;
virtual ~Cpu_session() { } virtual ~Cpu_session() { }
/** /**
@ -264,7 +270,8 @@ struct Genode::Cpu_session : Session
* Transfer quota to another CPU session * Transfer quota to another CPU session
* *
* \param cpu_session receiver of quota donation * \param cpu_session receiver of quota donation
* \param amount amount of quota to donate * \param amount percentage of the session quota scaled up to
* the 'QUOTA_LIMIT' space
* \return 0 on success * \return 0 on success
* *
* Quota can only be transfered if the specified CPU session is * Quota can only be transfered if the specified CPU session is
@ -274,29 +281,23 @@ struct Genode::Cpu_session : Session
size_t amount) = 0; size_t amount) = 0;
/** /**
* Return current quota limit * Return quota configuration of the session
*/ */
virtual size_t quota() = 0; virtual Quota quota() = 0;
/** /**
* Return amount of used quota * Scale up 'value' from its space with 'limit' to the 'QUOTA_LIMIT' space
*/ */
virtual size_t used() = 0; template<typename T = size_t>
static size_t quota_lim_upscale(size_t const value, size_t const limit) {
return ((T)value << Cpu_session::QUOTA_LIMIT_LOG2) / limit; }
/** /**
* Return amount of available quota * Scale down 'value' from the 'QUOTA_LIMIT' space to a space with 'limit'
*/ */
size_t avail() template<typename T = size_t>
{ static size_t quota_lim_downscale(size_t const value, size_t const limit) {
size_t q = quota(), u = used(); return ((T)value * limit) >> Cpu_session::QUOTA_LIMIT_LOG2; }
return q > u ? q - u : 0;
}
/**
* Transform percentage of CPU utilization into CPU quota
*/
static size_t pc_to_quota(size_t const pc) {
return (pc << QUOTA_LIMIT_LOG2) / 100; }
/********************* /*********************
** RPC declaration ** ** RPC declaration **
@ -329,8 +330,7 @@ struct Genode::Cpu_session : Session
GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability); GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability);
GENODE_RPC(Rpc_ref_account, int, ref_account, Cpu_session_capability); GENODE_RPC(Rpc_ref_account, int, ref_account, Cpu_session_capability);
GENODE_RPC(Rpc_transfer_quota, int, transfer_quota, Cpu_session_capability, size_t); GENODE_RPC(Rpc_transfer_quota, int, transfer_quota, Cpu_session_capability, size_t);
GENODE_RPC(Rpc_quota, size_t, quota); GENODE_RPC(Rpc_quota, Quota, quota);
GENODE_RPC(Rpc_used, size_t, used);
/* /*
* 'GENODE_RPC_INTERFACE' declaration done manually * 'GENODE_RPC_INTERFACE' declaration done manually
@ -361,9 +361,14 @@ struct Genode::Cpu_session : Session
Meta::Type_tuple<Rpc_ref_account, Meta::Type_tuple<Rpc_ref_account,
Meta::Type_tuple<Rpc_transfer_quota, Meta::Type_tuple<Rpc_transfer_quota,
Meta::Type_tuple<Rpc_quota, Meta::Type_tuple<Rpc_quota,
Meta::Type_tuple<Rpc_used,
Meta::Empty> Meta::Empty>
> > > > > > > > > > > > > > > > > > > > > Rpc_functions; > > > > > > > > > > > > > > > > > > > > Rpc_functions;
};
struct Genode::Cpu_session::Quota
{
size_t super_period_us;
size_t us;
}; };
#endif /* _INCLUDE__CPU_SESSION__CPU_SESSION_H_ */ #endif /* _INCLUDE__CPU_SESSION__CPU_SESSION_H_ */

View File

@ -198,7 +198,8 @@ Process::Process(Dataspace_capability elf_ds_cap,
/* create thread0 */ /* create thread0 */
try { try {
_thread0_cap = _cpu_session_client.create_thread(0, name); enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
_thread0_cap = _cpu_session_client.create_thread(WEIGHT, name);
} catch (Cpu_session::Thread_creation_failed) { } catch (Cpu_session::Thread_creation_failed) {
PERR("Creation of thread0 failed"); PERR("Creation of thread0 failed");
throw THREAD_FAIL; throw THREAD_FAIL;

View File

@ -102,7 +102,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
char const *name, bool start_on_construction, char const *name, bool start_on_construction,
Affinity::Location location) Affinity::Location location)
: :
Thread_base(0, name, stack_size), Thread_base(Cpu_session::DEFAULT_WEIGHT, name, stack_size),
_cap(Untyped_capability()), _cap(Untyped_capability()),
_curr_obj(0), _cap_valid(Lock::LOCKED), _delay_start(Lock::LOCKED), _curr_obj(0), _cap_valid(Lock::LOCKED), _delay_start(Lock::LOCKED),
_delay_exit(Lock::LOCKED), _delay_exit(Lock::LOCKED),

View File

@ -54,7 +54,9 @@ void Thread_base::start()
/* create thread at core */ /* create thread at core */
char buf[48]; char buf[48];
name(buf, sizeof(buf)); name(buf, sizeof(buf));
_thread_cap = _cpu_session->create_thread(0, buf, (addr_t)&_context->utcb); enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
addr_t const utcb = (addr_t)&_context->utcb;
_thread_cap = _cpu_session->create_thread(WEIGHT, buf, utcb);
if (!_thread_cap.valid()) if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed(); throw Cpu_session::Thread_creation_failed();

View File

@ -33,14 +33,10 @@ void Cpu_thread_component::update_exception_sigh()
}; };
Thread_capability Cpu_session_component::create_thread(size_t quota, Thread_capability Cpu_session_component::create_thread(size_t weight,
Name const &name, Name const &name,
addr_t utcb) addr_t utcb)
{ {
/* check for sufficient quota */
quota = _local_to_global(quota);
if (quota > avail()) { _insuff_for_consume(quota); }
unsigned trace_control_index = 0; unsigned trace_control_index = 0;
if (!_trace_control_area.alloc(trace_control_index)) if (!_trace_control_area.alloc(trace_control_index))
throw Out_of_metadata(); throw Out_of_metadata();
@ -51,16 +47,27 @@ Thread_capability Cpu_session_component::create_thread(size_t quota,
Trace::Thread_name thread_name(name.string()); Trace::Thread_name thread_name(name.string());
Cpu_thread_component *thread = 0; Cpu_thread_component *thread = 0;
if (weight == 0) {
PWRN("Thread %s: Bad weight 0, using %i instead.",
name.string(), DEFAULT_WEIGHT);
weight = DEFAULT_WEIGHT;
}
if (weight > QUOTA_LIMIT) {
PWRN("Thread %s: Oversized weight %zu, using %i instead.",
name.string(), weight, QUOTA_LIMIT);
weight = QUOTA_LIMIT;
}
Lock::Guard thread_list_lock_guard(_thread_list_lock);
_incr_weight(weight);
try { try {
Lock::Guard slab_lock_guard(_thread_alloc_lock); Lock::Guard slab_lock_guard(_thread_alloc_lock);
thread = new(&_thread_alloc) thread = new(&_thread_alloc)
Cpu_thread_component( Cpu_thread_component(
quota, _label, thread_name, _priority, utcb, weight, _weight_to_quota(weight), _label, thread_name,
_default_exception_handler, trace_control_index, _priority, utcb, _default_exception_handler,
*trace_control); trace_control_index, *trace_control);
/* account quota */
_used += quota;
/* set default affinity defined by CPU session */ /* set default affinity defined by CPU session */
thread->platform_thread()->affinity(_location); thread->platform_thread()->affinity(_location);
@ -68,7 +75,6 @@ Thread_capability Cpu_session_component::create_thread(size_t quota,
throw Out_of_metadata(); throw Out_of_metadata();
} }
Lock::Guard thread_list_lock_guard(_thread_list_lock);
_thread_list.insert(thread); _thread_list.insert(thread);
_trace_sources.insert(thread->trace_source()); _trace_sources.insert(thread->trace_source());
@ -86,7 +92,7 @@ void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread_component *th
unsigned const trace_control_index = thread->trace_control_index(); unsigned const trace_control_index = thread->trace_control_index();
_used -= thread->quota(); _decr_weight(thread->weight());
Lock::Guard lock_guard(_thread_alloc_lock); Lock::Guard lock_guard(_thread_alloc_lock);
destroy(&_thread_alloc, thread); destroy(&_thread_alloc, thread);
@ -290,39 +296,72 @@ static size_t remaining_session_ram_quota(char const *args)
} }
int Cpu_session_component::transfer_quota(Cpu_session_capability c, size_t q) void Cpu_session_component::_transfer_quota(Cpu_session_component * const dst,
size_t const quota)
{ {
/* lookup targeted CPU-session */ if (!quota) { return; }
Object_pool<Cpu_session_component>::Guard s(_session_ep->lookup_and_lock(c)); _decr_quota(quota);
if (!s) { return -1; } dst->_incr_quota(quota);
/* translate quota argument and check limits */
q = _local_to_global(q);
if (q > avail()) { return _insuff_for_transfer(q); }
/* transfer quota to targeted CPU-session */
if (s->_ref == this) { return _transfer_forth(s, q); }
if (s == _ref) { return _transfer_back(q); }
return -2;
} }
int Cpu_session_component::ref_account(Cpu_session_capability c) int Cpu_session_component::transfer_quota(Cpu_session_capability dst_cap,
size_t amount)
{
/* lookup targeted CPU session */
Object_pool<Cpu_session_component>::Guard
dst(_session_ep->lookup_and_lock(dst_cap));
if (!dst) {
PWRN("Transfer CPU quota, %s, targeted session not found",
_label.string());
return -1;
}
/* check reference relationship */
if (dst->_ref != this && dst != _ref) {
PWRN("Transfer CPU quota, %s -> %s, no reference relation",
_label.string(), dst->_label.string());
return -2;
}
/* check quota availability */
size_t const quota = quota_lim_downscale(_quota, amount);
if (quota > _quota) {
PWRN("Transfer CPU quota, %s -> %s, insufficient quota %zu, need %zu",
_label.string(), dst->_label.string(), _quota, quota);
return -3;
}
/* transfer quota */
_transfer_quota(dst, quota);
return 0;
}
int Cpu_session_component::ref_account(Cpu_session_capability ref_cap)
{ {
/* /*
* Ensure that the ref account is set only once * Ensure that the ref account is set only once
* *
* FIXME Add check for cycles along the tree of reference accounts * FIXME Add check for cycles along the tree of reference accounts
*/ */
if (_ref) { return -2; } if (_ref) {
PWRN("Set ref account, %s, set already",
/* lookup targeted CPU-session */ _label.string());
Object_pool<Cpu_session_component>::Guard s(_session_ep->lookup_and_lock(c)); return -2; }
if (!s) { return -1; }
if (s == this) { return -3; }
/* lookup and check targeted CPU-session */
Object_pool<Cpu_session_component>::Guard
ref(_session_ep->lookup_and_lock(ref_cap));
if (!ref) {
PWRN("Set ref account, %s, targeted session not found",
_label.string());
return -1;
}
if (ref == this) {
PWRN("Set ref account, %s, self reference not allowed",
_label.string());
return -3;
}
/* establish ref-account relation from targeted CPU-session to us */ /* establish ref-account relation from targeted CPU-session to us */
_ref = s; _ref = ref;
_ref->_insert_ref_member(this); _ref->_insert_ref_member(this);
return 0; return 0;
} }
@ -335,7 +374,7 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint *session_ep,
Trace::Source_registry &trace_sources, Trace::Source_registry &trace_sources,
char const *args, char const *args,
Affinity const &affinity, Affinity const &affinity,
size_t quota) size_t const quota)
: :
_session_ep(session_ep), _session_ep(session_ep),
_thread_ep(thread_ep), _pager_ep(pager_ep), _thread_ep(thread_ep), _pager_ep(pager_ep),
@ -345,7 +384,7 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint *session_ep,
/* map affinity to a location within the physical affinity space */ /* map affinity to a location within the physical affinity space */
_location(affinity.scale_to(platform()->affinity_space())), _location(affinity.scale_to(platform()->affinity_space())),
_trace_sources(trace_sources), _ref(0), _used(0), _quota(quota) _trace_sources(trace_sources), _quota(quota), _ref(0)
{ {
/* remember session label */ /* remember session label */
char buf[Session_label::size()]; char buf[Session_label::size()];
@ -375,7 +414,7 @@ void Cpu_session_component::_deinit_ref_account()
if (!_ref) { return; } if (!_ref) { return; }
/* give back our remaining quota to our ref account */ /* give back our remaining quota to our ref account */
_transfer_back(_quota); _transfer_quota(_ref, _quota);
/* remove ref-account relation between us and our ref-account */ /* remove ref-account relation between us and our ref-account */
Cpu_session_component * const orig_ref = _ref; Cpu_session_component * const orig_ref = _ref;
@ -405,30 +444,53 @@ void Cpu_session_component::_deinit_threads()
} }
int Cpu_session_component::_insuff_for_transfer(size_t const q) void Cpu_session_component::
_update_thread_quota(Cpu_thread_component * const thread) const
{ {
if (verbose) { thread->platform_thread()->quota(_weight_to_quota(thread->weight()));
PWRN("Insufficient CPU quota for transfer: %s", _label.string());
PWRN(" avail %zu", _avail());
PWRN(" needed %zu", q);
}
return -3;
} }
void Cpu_session_component::_insuff_for_consume(size_t const q) void Cpu_session_component::_incr_weight(size_t const weight)
{ {
if (verbose) { _weight += weight;
PWRN("Insufficient CPU quota for consumption: %s", _label.string()); if (_quota) { _update_each_thread_quota(); }
PWRN(" avail %zu", _avail());
PWRN(" needed %zu", q);
}
throw Quota_exceeded();
} }
size_t Cpu_session_component::used() { return _global_to_local(_used); }
size_t Cpu_session_component::quota() { return _global_to_local(_quota); } void Cpu_session_component::_decr_weight(size_t const weight)
{
_weight -= weight;
if (_quota) { _update_each_thread_quota(); }
}
void Cpu_session_component::_decr_quota(size_t const quota)
{
Lock::Guard lock_guard(_thread_list_lock);
_quota -= quota;
_update_each_thread_quota();
}
void Cpu_session_component::_incr_quota(size_t const quota)
{
Lock::Guard lock_guard(_thread_list_lock);
_quota += quota;
_update_each_thread_quota();
}
void Cpu_session_component::_update_each_thread_quota()
{
Cpu_thread_component * thread = _thread_list.first();
for (; thread; thread = thread->next()) { _update_thread_quota(thread); }
}
size_t
Cpu_session_component::_weight_to_quota(size_t const weight) const {
return (weight * _quota) / _weight; }
/**************************** /****************************

View File

@ -53,7 +53,7 @@ namespace Genode {
private: private:
size_t const _quota; size_t const _weight;
Thread_name const _name; Thread_name const _name;
Platform_thread _platform_thread; Platform_thread _platform_thread;
bool _bound; /* pd binding flag */ bool _bound; /* pd binding flag */
@ -63,14 +63,27 @@ namespace Genode {
public: public:
Cpu_thread_component(size_t quota, Session_label const &label, /**
* Constructor
*
* \param weight weighting regarding the CPU session quota
* \param quota initial quota counter-value of the weight
* \param labal label of the threads session
* \param name name for the thread
* \param priority scheduling priority
* \param utcb user-local UTCB base
* \param sigh initial exception handler
*/
Cpu_thread_component(size_t const weight,
size_t const quota,
Session_label const &label,
Thread_name const &name, Thread_name const &name,
unsigned priority, addr_t utcb, unsigned priority, addr_t utcb,
Signal_context_capability sigh, Signal_context_capability sigh,
unsigned trace_control_index, unsigned trace_control_index,
Trace::Control &trace_control) Trace::Control &trace_control)
: :
_quota(quota), _name(name), _weight(weight), _name(name),
_platform_thread(quota, name.string(), priority, utcb), _platform_thread(quota, name.string(), priority, utcb),
_bound(false), _sigh(sigh), _bound(false), _sigh(sigh),
_trace_control_index(trace_control_index), _trace_control_index(trace_control_index),
@ -88,7 +101,7 @@ namespace Genode {
bool bound() const { return _bound; } bool bound() const { return _bound; }
void bound(bool b) { _bound = b; } void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; } Trace::Source *trace_source() { return &_trace_source; }
size_t quota() const { return _quota; } size_t weight() const { return _weight; }
void sigh(Signal_context_capability sigh) void sigh(Signal_context_capability sigh)
{ {
@ -138,9 +151,9 @@ namespace Genode {
* Members for quota accounting * Members for quota accounting
*/ */
Cpu_session_component * _ref; size_t _weight;
size_t _used;
size_t _quota; size_t _quota;
Cpu_session_component * _ref;
List<Cpu_session_component> _ref_members; List<Cpu_session_component> _ref_members;
Lock _ref_members_lock; Lock _ref_members_lock;
@ -148,32 +161,22 @@ namespace Genode {
* Utilities for quota accounting * Utilities for quota accounting
*/ */
size_t _avail() { return _quota - _used; } void _incr_weight(size_t const weight);
size_t _local_to_global(size_t const q) const { void _decr_weight(size_t const weight);
return (q * _quota) >> Cpu_session::QUOTA_LIMIT_LOG2; }
size_t _global_to_local(size_t const q) const { size_t _weight_to_quota(size_t const weight) const;
if (!_quota) { return 0; }
return (q << Cpu_session::QUOTA_LIMIT_LOG2) / _quota; }
int _insuff_for_transfer(size_t const q); void _decr_quota(size_t const quota);
void _insuff_for_consume(size_t const q); void _incr_quota(size_t const quota);
int _transfer_back(size_t const q) void _update_thread_quota(Cpu_thread_component *) const;
{
_quota -= q;
_ref->_used -= q;
return 0;
}
int _transfer_forth(Cpu_session_component * const s, size_t const q) void _update_each_thread_quota();
{
s->_quota += q; void _transfer_quota(Cpu_session_component * const dst,
_used += q; size_t const quota);
return 0;
}
void _insert_ref_member(Cpu_session_component * const s) void _insert_ref_member(Cpu_session_component * const s)
{ {
@ -261,9 +264,8 @@ namespace Genode {
Dataspace_capability trace_buffer(Thread_capability); Dataspace_capability trace_buffer(Thread_capability);
Dataspace_capability trace_policy(Thread_capability); Dataspace_capability trace_policy(Thread_capability);
int ref_account(Cpu_session_capability c); int ref_account(Cpu_session_capability c);
int transfer_quota(Cpu_session_capability c, size_t q); int transfer_quota(Cpu_session_capability, size_t);
size_t used(); Quota quota() override;
size_t quota();
}; };
} }

View File

@ -263,14 +263,13 @@ int main()
Ram_session_client(init_ram_session_cap).ref_account(env()->ram_session_cap()); Ram_session_client(init_ram_session_cap).ref_account(env()->ram_session_cap());
/* create CPU session for init and transfer all of the CPU quota to it */ /* create CPU session for init and transfer all of the CPU quota to it */
constexpr size_t cpu_quota = Cpu_session::QUOTA_LIMIT;
static Cpu_session_component static Cpu_session_component
cpu(e, e, rm_root.pager_ep(), &sliced_heap, trace_sources, cpu(e, e, rm_root.pager_ep(), &sliced_heap, trace_sources,
"label=\"core\"", Affinity(), cpu_quota); "label=\"core\"", Affinity(), Cpu_session::QUOTA_LIMIT);
Cpu_session_capability cpu_cap = core_env()->entrypoint()->manage(&cpu); Cpu_session_capability cpu_cap = core_env()->entrypoint()->manage(&cpu);
Cpu_connection init_cpu("init"); Cpu_connection init_cpu("init");
init_cpu.ref_account(cpu_cap); init_cpu.ref_account(cpu_cap);
cpu.transfer_quota(init_cpu, cpu_quota); cpu.transfer_quota(init_cpu, Cpu_session::quota_lim_upscale(100, 100));
Rm_connection init_rm; Rm_connection init_rm;

View File

@ -38,10 +38,12 @@ extern "C" {
void *(*_start_routine) (void *); void *(*_start_routine) (void *);
void *_arg; void *_arg;
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
pthread(pthread_attr_t attr, void *(*start_routine) (void *), pthread(pthread_attr_t attr, void *(*start_routine) (void *),
void *arg, size_t stack_size, char const * name, void *arg, size_t stack_size, char const * name,
Genode::Cpu_session * cpu) Genode::Cpu_session * cpu)
: Thread_base(0, name, stack_size, Type::NORMAL, cpu), : Thread_base(WEIGHT, name, stack_size, Type::NORMAL, cpu),
_attr(attr), _attr(attr),
_start_routine(start_routine), _start_routine(start_routine),
_arg(arg) _arg(arg)

View File

@ -42,6 +42,12 @@ namespace Init {
extern bool config_verbose; extern bool config_verbose;
static void warn_insuff_quota(Genode::size_t const avail)
{
if (!config_verbose) { return; }
Genode::printf("Warning: Specified quota exceeds available quota.\n");
Genode::printf(" Proceeding with a quota of %zu.\n", avail);
}
inline long read_priority(Genode::Xml_node start_node) inline long read_priority(Genode::Xml_node start_node)
{ {
@ -103,13 +109,6 @@ namespace Init {
} }
/**
* Return amount of CPU time that is currently unused
*/
static inline Genode::size_t avail_slack_cpu_quota() {
return Genode::env()->cpu_session()->avail(); }
/** /**
* Return true if service XML node matches the specified service name * Return true if service XML node matches the specified service name
*/ */
@ -395,21 +394,12 @@ class Init::Child : Genode::Child_policy
struct Read_quota struct Read_quota
{ {
void warn_unsuff_quota(Genode::size_t const avail)
{
using namespace Genode;
if (!config_verbose) { return; }
Genode::printf("Warning: Specified quota exceeds available quota.\n");
Genode::printf(" Proceeding with a quota of %zu.\n", avail);
}
Read_quota(Genode::Xml_node start_node, Read_quota(Genode::Xml_node start_node,
Genode::size_t & ram_quota, Genode::size_t & ram_quota,
Genode::size_t & cpu_quota, Genode::size_t & cpu_quota_pc,
bool & constrain_phys) bool & constrain_phys)
{ {
Genode::Number_of_bytes ram_bytes = 0; Genode::Number_of_bytes ram_bytes = 0;
Genode::size_t cpu_percent = 0;
try { try {
Genode::Xml_node rsc = start_node.sub_node("resource"); Genode::Xml_node rsc = start_node.sub_node("resource");
@ -419,12 +409,11 @@ class Init::Child : Genode::Child_policy
rsc.attribute("quantum").value(&ram_bytes); rsc.attribute("quantum").value(&ram_bytes);
constrain_phys = rsc.attribute("constrain_phys").has_value("yes"); constrain_phys = rsc.attribute("constrain_phys").has_value("yes");
} else if (rsc.attribute("name").has_value("CPU")) { } else if (rsc.attribute("name").has_value("CPU")) {
rsc.attribute("quantum").value(&cpu_percent); } rsc.attribute("quantum").value(&cpu_quota_pc); }
} catch (...) { } } catch (...) { }
} }
} catch (...) { } } catch (...) { }
ram_quota = ram_bytes; ram_quota = ram_bytes;
cpu_quota = Genode::Cpu_session::pc_to_quota(cpu_percent);
/* /*
* If the configured RAM quota exceeds our own quota, we donate * If the configured RAM quota exceeds our own quota, we donate
@ -435,13 +424,7 @@ class Init::Child : Genode::Child_policy
Genode::size_t const ram_avail = avail_slack_ram_quota(); Genode::size_t const ram_avail = avail_slack_ram_quota();
if (ram_quota > ram_avail) { if (ram_quota > ram_avail) {
ram_quota = ram_avail; ram_quota = ram_avail;
warn_unsuff_quota(ram_avail); warn_insuff_quota(ram_avail);
}
Genode::size_t const cpu_avail = avail_slack_cpu_quota();
if (cpu_quota > cpu_avail) {
cpu_quota = cpu_avail;
warn_unsuff_quota(cpu_avail);
} }
} }
}; };
@ -455,17 +438,19 @@ class Init::Child : Genode::Child_policy
long priority; long priority;
Genode::Affinity affinity; Genode::Affinity affinity;
Genode::size_t ram_quota; Genode::size_t ram_quota;
Genode::size_t cpu_quota; Genode::size_t cpu_quota_pc;
bool constrain_phys; bool constrain_phys;
Genode::Ram_connection ram; Genode::Ram_connection ram;
Genode::Cpu_connection cpu; Genode::Cpu_connection cpu;
Genode::Rm_connection rm; Genode::Rm_connection rm;
inline void transfer_cpu_quota();
Resources(Genode::Xml_node start_node, const char *label, Resources(Genode::Xml_node start_node, const char *label,
long prio_levels_log2, long prio_levels_log2,
Genode::Affinity::Space const &affinity_space) Genode::Affinity::Space const &affinity_space)
: :
Read_quota(start_node, ram_quota, cpu_quota, constrain_phys), Read_quota(start_node, ram_quota, cpu_quota_pc, constrain_phys),
prio_levels_log2(prio_levels_log2), prio_levels_log2(prio_levels_log2),
priority(read_priority(start_node)), priority(read_priority(start_node)),
affinity(affinity_space, affinity(affinity_space,
@ -487,8 +472,7 @@ class Init::Child : Genode::Child_policy
ram.ref_account(Genode::env()->ram_session_cap()); ram.ref_account(Genode::env()->ram_session_cap());
Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota); Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota);
cpu.ref_account(Genode::env()->cpu_session_cap()); transfer_cpu_quota();
Genode::env()->cpu_session()->transfer_quota(cpu.cap(), cpu_quota);
} }
} _resources; } _resources;
@ -801,4 +785,24 @@ class Init::Child : Genode::Child_policy
Genode::Native_pd_args const *pd_args() const { return &_pd_args; } Genode::Native_pd_args const *pd_args() const { return &_pd_args; }
}; };
void Init::Child::Resources::transfer_cpu_quota()
{
using Genode::Cpu_session;
using Genode::size_t;
static size_t avail = Cpu_session::quota_lim_upscale( 100, 100);
size_t const need = Cpu_session::quota_lim_upscale(cpu_quota_pc, 100);
size_t need_adj;
if (need > avail) {
warn_insuff_quota(Cpu_session::quota_lim_downscale(avail, 100));
need_adj = Cpu_session::quota_lim_upscale(100, 100);
avail = 0;
} else {
need_adj = Cpu_session::quota_lim_upscale(need, avail);
avail -= need;
}
cpu.ref_account(Genode::env()->cpu_session_cap());
Genode::env()->cpu_session()->transfer_quota(cpu.cap(), need_adj);
}
#endif /* _INCLUDE__INIT__CHILD_H_ */ #endif /* _INCLUDE__INIT__CHILD_H_ */

View File

@ -41,6 +41,8 @@ class Genode::Irq_activation : Thread_base
{ {
private: private:
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
int _number; int _number;
Irq_connection _connection; Irq_connection _connection;
Irq_handler &_handler; Irq_handler &_handler;
@ -72,7 +74,7 @@ class Genode::Irq_activation : Thread_base
*/ */
Irq_activation(int irq_number, Irq_handler &handler, size_t stack_size) Irq_activation(int irq_number, Irq_handler &handler, size_t stack_size)
: :
Thread_base(0, _create_thread_name(irq_number), stack_size), Thread_base(WEIGHT, _create_thread_name(irq_number), stack_size),
_number(irq_number), _connection(irq_number), _handler(handler), _number(irq_number), _connection(irq_number), _handler(handler),
_dispatcher(_sig_rec, *this, &Irq_activation::_handle) _dispatcher(_sig_rec, *this, &Irq_activation::_handle)
{ {

244
repos/os/run/cpu_quota.run Normal file
View File

@ -0,0 +1,244 @@
#
# Check platform
#
# HW is the only kernel that provides appliance of quota to the scheduling.
# On X86, the timer driver uses the PIT with a timeout of max. 54 ms. Thus,
# the driver needs to restart the timer permanently which is a hard job with 6
# high-priority counter-threads in the background. As a consequence, timeouts
# take much longer than requested and the test fails. However, as the PIT
# tends to be replaced by a better timing source, we simply skip X86 for now.
#
#
assert_spec hw
assert_spec arm
#
# 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="IO_PORT"/>
<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="test-sync">
<resource name="RAM" quantum="10M"/>
<provides><service name="Sync"/></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="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
<service name="Sync"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<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="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
<service name="Sync"/>
</parent-provides>
<default-route>
<any-service><parent/></any-service>
</default-route>
<start name="test_midl">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="25"/>
</start>
<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 test-sync"
#
# Execution
#
append qemu_args "-nographic -m 64"
run_genode_until ".*done.*\n.*done.*\n.*done.*\n" 100
#
# Conclusion
#
proc check_counter { name opt cnt total_cnt } {
set err 1
set is [expr double($cnt) / $total_cnt ]
set is_pc [expr double(round($is * 100000)) / 1000]
set opt_pc [expr double(round($opt * 100000)) / 1000]
if {[expr $is > $opt + $err || $is < $opt - $err]} {
puts stderr "Error: $name received $is_pc % of the CPU time."
puts stderr " Should receive $opt_pc %."
exit -1
}
puts "$name: $is_pc % (optimal $opt_pc %)"
}
proc check_quota { name opt_sp quota_sp opt quota } {
if {[expr $quota != $opt]} {
puts stderr "Error: $name has CPU quota of $quota us."
puts stderr " Should have $opt us."
exit -1
}
if {[expr $quota_sp != $opt_sp]} {
puts stderr "Error: $name has CPU quota super-period of $quota_sp us."
puts stderr " Should have $opt_sp us."
exit -1
}
}
regexp {[0-9]+} [regexp -inline {slow. quota [0-9]+} $output] slow_quota
regexp {[0-9]+} [regexp -inline {midl. quota [0-9]+} $output] midl_quota
regexp {[0-9]+} [regexp -inline {fast. quota [0-9]+} $output] fast_quota
regexp {[0-9]+} [regexp -inline {slow. quota super period [0-9]+} $output] slow_quota_sp
regexp {[0-9]+} [regexp -inline {midl. quota super period [0-9]+} $output] midl_quota_sp
regexp {[0-9]+} [regexp -inline {fast. quota super period [0-9]+} $output] fast_quota_sp
#
# We have to consider the rounding errors as the two translations from init to
# core and then from core to the user are distinct.
#
# Slow quota (1000000 * (0x8000 * 5 / 100)) / 0x8000 = 49987
# Slow quota (1000000 * (0x8000 * 20 / 100)) / 0x8000 = 199981
# Slow quota (1000000 * (0x8000 * 60 / 100)) / 0x8000 = 599975
#
check_quota "Slow test" 1000000 $slow_quota_sp 49987 $slow_quota
check_quota "Middle test" 1000000 $midl_quota_sp 199981 $midl_quota
check_quota "Fast test" 1000000 $fast_quota_sp 599975 $fast_quota
regexp {[0-9]+} [regexp -inline {slow. counter A [0-9]+} $output] slow_a_cnt
regexp {[0-9]+} [regexp -inline {midl. counter A [0-9]+} $output] midl_a_cnt
regexp {[0-9]+} [regexp -inline {fast. counter A [0-9]+} $output] fast_a_cnt
regexp {[0-9]+} [regexp -inline {slow. counter B [0-9]+} $output] slow_b_cnt
regexp {[0-9]+} [regexp -inline {midl. counter B [0-9]+} $output] midl_b_cnt
regexp {[0-9]+} [regexp -inline {fast. counter B [0-9]+} $output] fast_b_cnt
set total_cnt [expr $fast_a_cnt + $midl_a_cnt + $slow_a_cnt + $fast_b_cnt + $midl_b_cnt + $slow_b_cnt]
#
# Slow 5.0 % claim + 5.0 % fill = 10 %
# Stage 1
# A 0.5 % claim + 2.5 % fill = 3 %
# B 4.5 % claim + 2.5 % fill = 7 %
# Stage 2
# A 5.0 % claim + 5.0 % fill = 10 %
# Total
# A 3/4 * 3 + 1/4 * 10 = 4.75 %
# A 3/4 * 7 + 1/4 * 0 = 5.25 %
#
check_counter "Slow counter A" 0.0475 $slow_a_cnt $total_cnt
check_counter "Slow counter B" 0.0525 $slow_b_cnt $total_cnt
#
# Middle 20 % claim + 5.0 % fill = 25.0 %
# Stage 1
# A 2 % claim + 2.5 % fill = 4.5 %
# B 18 % claim + 2.5 % fill = 20.5 %
# Stage 2
# A 20 % claim + 5.0 % fill = 25.0 %
# Total
# A 3/4 * 4.5 + 1/4 * 25 = 9.625 %
# A 3/4 * 20.5 + 1/4 * 0 = 15.375 %
#
check_counter "Middle counter A" 0.09625 $midl_a_cnt $total_cnt
check_counter "Middle counter B" 0.15375 $midl_b_cnt $total_cnt
#
# Fast 60 % claim + 5.0 % fill = 65.0 %
# Stage 1
# A 6 % claim + 2.5 % fill = 8.5 %
# B 54 % claim + 2.5 % fill = 56.5 %
# Stage 2
# A 60 % claim + 5.0 % fill = 65.0 %
# Total
# A 3/4 * 8.5 + 1/4 * 65 = 22.625 %
# A 3/4 * 56.5 + 1/4 * 0 = 42.375 %
#
check_counter "Fast counter A" 0.22625 $fast_a_cnt $total_cnt
check_counter "Fast counter B" 0.42375 $fast_b_cnt $total_cnt
puts "Test succeeded"

View File

@ -35,6 +35,8 @@ namespace L4lx {
{ {
private: private:
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
Genode::Lock _lock; Genode::Lock _lock;
L4_CV void (*_func)(void *data); L4_CV void (*_func)(void *data);
unsigned long _data; unsigned long _data;
@ -50,7 +52,7 @@ namespace L4lx {
Genode::size_t stack_size, Genode::size_t stack_size,
Genode::addr_t vcpu_state, Genode::addr_t vcpu_state,
unsigned cpu_nr) unsigned cpu_nr)
: Genode::Thread_base(0, str, stack_size), : Genode::Thread_base(WEIGHT, str, stack_size),
_lock(Genode::Cancelable_lock::LOCKED), _lock(Genode::Cancelable_lock::LOCKED),
_func(func), _func(func),
_data(data ? *data : 0), _data(data ? *data : 0),

View File

@ -31,6 +31,8 @@ class Vmm::Vcpu_dispatcher : public T
{ {
private: private:
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
Cap_connection &_cap; Cap_connection &_cap;
/** /**
@ -61,7 +63,7 @@ class Vmm::Vcpu_dispatcher : public T
Cpu_session * cpu_session, Cpu_session * cpu_session,
Genode::Affinity::Location location) Genode::Affinity::Location location)
: :
T(0, "vCPU dispatcher", stack_size), T(WEIGHT, "vCPU dispatcher", stack_size),
_cap(cap) _cap(cap)
{ {
using namespace Genode; using namespace Genode;

View File

@ -62,8 +62,10 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
{ {
using namespace Genode; using namespace Genode;
Thread_capability vcpu_vm = _cpu_session->create_thread(0, "vCPU"); enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
Thread_capability vcpu_vm =
_cpu_session->create_thread(WEIGHT, "vCPU");
/* assign thread to protection domain */ /* assign thread to protection domain */
_pd_session.bind_thread(vcpu_vm); _pd_session.bind_thread(vcpu_vm);
@ -104,12 +106,14 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread_base class Vmm::Vcpu_same_pd : public Vmm::Vcpu_thread, Genode::Thread_base
{ {
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
public: public:
Vcpu_same_pd(size_t stack_size, Cpu_session * cpu_session, Vcpu_same_pd(size_t stack_size, Cpu_session * cpu_session,
Genode::Affinity::Location location) Genode::Affinity::Location location)
: :
Thread_base(0, "vCPU", stack_size, Type::NORMAL, cpu_session) Thread_base(WEIGHT, "vCPU", stack_size, Type::NORMAL, cpu_session)
{ {
/* release pre-allocated selectors of Thread */ /* release pre-allocated selectors of Thread */
Genode::cap_map()->remove(tid().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2); Genode::cap_map()->remove(tid().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2);

View File

@ -63,10 +63,12 @@ Thread_capability Cpu_session_component::thread_cap(unsigned long lwpid)
} }
Thread_capability Cpu_session_component::create_thread(size_t, Cpu_session::Name const &name, addr_t utcb) Thread_capability
Cpu_session_component::create_thread(size_t weight, Name const &name,
addr_t utcb)
{ {
Thread_capability thread_cap = Thread_capability thread_cap =
_parent_cpu_session.create_thread(0, name.string(), utcb); _parent_cpu_session.create_thread(weight, name.string(), utcb);
if (thread_cap.valid()) { if (thread_cap.valid()) {
Thread_info *thread_info = new (env()->heap()) Thread_info(thread_cap, new_lwpid++); Thread_info *thread_info = new (env()->heap()) Thread_info(thread_cap, new_lwpid++);
@ -239,10 +241,8 @@ Cpu_session_component::~Cpu_session_component()
{ {
} }
size_t Cpu_session_component::quota() { return 0; }
size_t Cpu_session_component::used() { return 0; }
int Cpu_session_component::ref_account(Cpu_session_capability) { return -1; } int Cpu_session_component::ref_account(Cpu_session_capability) { return -1; }
int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; } int Cpu_session_component::transfer_quota(Cpu_session_capability, size_t) { return -1; }
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }

View File

@ -78,8 +78,7 @@ class Cpu_session_component : public Rpc_object<Cpu_session>
Dataspace_capability trace_policy(Thread_capability); Dataspace_capability trace_policy(Thread_capability);
int ref_account(Cpu_session_capability c); int ref_account(Cpu_session_capability c);
int transfer_quota(Cpu_session_capability c, size_t q); int transfer_quota(Cpu_session_capability c, size_t q);
size_t used(); Quota quota() override;
size_t quota();
}; };
#endif /* _CPU_SESSION_COMPONENT_H_ */ #endif /* _CPU_SESSION_COMPONENT_H_ */

View File

@ -71,7 +71,7 @@ namespace Noux {
** Cpu_session interface ** ** Cpu_session interface **
***************************/ ***************************/
Thread_capability create_thread(size_t, Name const &name, Thread_capability create_thread(size_t weight, Name const &name,
addr_t utcb) addr_t utcb)
{ {
/* /*
@ -83,7 +83,7 @@ namespace Noux {
while (1); while (1);
return Thread_capability(); return Thread_capability();
} }
_main_thread = _cpu.create_thread(0, name, utcb); _main_thread = _cpu.create_thread(weight, name, utcb);
return _main_thread; return _main_thread;
} }
@ -147,10 +147,13 @@ namespace Noux {
Dataspace_capability trace_policy(Thread_capability thread) { Dataspace_capability trace_policy(Thread_capability thread) {
return _cpu.trace_policy(thread); } return _cpu.trace_policy(thread); }
size_t quota() { return 0; } Quota quota() override { return _cpu.quota(); }
size_t used() { return 0; }
int ref_account(Cpu_session_capability) { return -1; } int ref_account(Cpu_session_capability c) override {
int transfer_quota(Cpu_session_capability, size_t) { return -1; } return _cpu.ref_account(c); }
int transfer_quota(Cpu_session_capability c, size_t q) override {
return _cpu.transfer_quota(c, q); }
}; };
} }

View File

@ -50,3 +50,4 @@ vbox_auto_win8
tz_vmm tz_vmm
vmm vmm
bomb bomb
cpu_quota