mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
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:
parent
955977b516
commit
c9272937e7
@ -55,7 +55,8 @@ void Thread_base::start()
|
||||
/* create thread at core */
|
||||
char buf[48];
|
||||
name(buf, sizeof(buf));
|
||||
_thread_cap = _cpu_session->create_thread(0, buf);
|
||||
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
|
||||
_thread_cap = _cpu_session->create_thread(WEIGHT, buf);
|
||||
|
||||
/* assign thread to protection domain */
|
||||
env()->pd_session()->bind_thread(_thread_cap);
|
||||
|
@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -152,6 +152,11 @@ namespace Genode {
|
||||
***********************/
|
||||
|
||||
addr_t utcb() const { return _utcb; }
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota) { /* not supported*/ }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -150,6 +150,11 @@ namespace Genode {
|
||||
unsigned long pager_object_badge() const {
|
||||
return convert_native_thread_id_to_badge(_l4_thread_id); }
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota) { /* not supported*/ }
|
||||
|
||||
|
||||
/*******************************
|
||||
** Fiasco-specific Accessors **
|
||||
|
@ -25,8 +25,8 @@ namespace Genode {
|
||||
explicit Foc_cpu_session_client(Cpu_session_capability session)
|
||||
: Rpc_client<Foc_cpu_session>(static_cap_cast<Foc_cpu_session>(session)) { }
|
||||
|
||||
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(0, name, utcb); }
|
||||
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(weight, name, utcb); }
|
||||
|
||||
Ram_dataspace_capability utcb(Thread_capability thread) {
|
||||
return call<Rpc_utcb>(thread); }
|
||||
@ -100,9 +100,7 @@ namespace Genode {
|
||||
int transfer_quota(Cpu_session_capability session, size_t amount) {
|
||||
return call<Rpc_transfer_quota>(session, amount); }
|
||||
|
||||
size_t quota() { return call<Rpc_quota>(); }
|
||||
|
||||
size_t used() { return call<Rpc_used>(); }
|
||||
Quota quota() override { return call<Rpc_quota>(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ void Thread_base::free_secondary_stack(void* stack_addr)
|
||||
}
|
||||
|
||||
|
||||
Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
|
||||
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
|
||||
Type const type, Cpu_session *cpu_session)
|
||||
:
|
||||
_cpu_session(cpu_session),
|
||||
@ -195,13 +195,13 @@ Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
|
||||
_join_lock(Lock::LOCKED)
|
||||
{
|
||||
strncpy(_context->name, name, sizeof(_context->name));
|
||||
_init_platform_thread(0, type);
|
||||
_init_platform_thread(weight, type);
|
||||
}
|
||||
|
||||
|
||||
Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
|
||||
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
|
||||
Type type)
|
||||
: Thread_base(0, name, stack_size, type, nullptr) { }
|
||||
: Thread_base(weight, name, stack_size, type, nullptr) { }
|
||||
|
||||
|
||||
Thread_base::~Thread_base()
|
||||
|
@ -39,7 +39,7 @@ void Thread_base::_deinit_platform_thread()
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::_init_platform_thread(size_t, Type type)
|
||||
void Thread_base::_init_platform_thread(size_t weight, Type type)
|
||||
{
|
||||
/* if no cpu session is given, use it from the environment */
|
||||
if (!_cpu_session)
|
||||
@ -50,7 +50,7 @@ void Thread_base::_init_platform_thread(size_t, Type type)
|
||||
/* create thread at core */
|
||||
char buf[48];
|
||||
name(buf, sizeof(buf));
|
||||
_thread_cap = _cpu_session->create_thread(0, buf);
|
||||
_thread_cap = _cpu_session->create_thread(weight, buf);
|
||||
|
||||
/* assign thread to protection domain */
|
||||
if (!_thread_cap.valid() ||
|
||||
|
@ -107,3 +107,6 @@ void Genode::Cpu_session_component::single_step(Genode::Thread_capability thread
|
||||
|
||||
Fiasco::l4_thread_ex_regs(tid, ~0UL, ~0UL, flags);
|
||||
}
|
||||
|
||||
|
||||
Genode::Cpu_session::Quota Genode::Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -64,7 +64,9 @@ namespace Genode {
|
||||
|
||||
public:
|
||||
|
||||
Cpu_thread_component(size_t, Session_label const &label,
|
||||
Cpu_thread_component(size_t const weight,
|
||||
size_t const quota,
|
||||
Session_label const &label,
|
||||
Thread_name const &name,
|
||||
unsigned priority, addr_t utcb,
|
||||
Signal_context_capability sigh,
|
||||
@ -88,7 +90,8 @@ namespace Genode {
|
||||
bool bound() const { return _bound; }
|
||||
void bound(bool b) { _bound = b; }
|
||||
Trace::Source *trace_source() { return &_trace_source; }
|
||||
size_t quota() { return 0; }
|
||||
|
||||
size_t weight() const { return Cpu_session::DEFAULT_WEIGHT; }
|
||||
|
||||
void sigh(Signal_context_capability sigh)
|
||||
{
|
||||
@ -138,24 +141,26 @@ namespace Genode {
|
||||
session */
|
||||
Trace::Source_registry &_trace_sources;
|
||||
Trace::Control_area _trace_control_area;
|
||||
Cpu_session_component * _ref;
|
||||
size_t _used;
|
||||
|
||||
size_t _weight;
|
||||
size_t _quota;
|
||||
Cpu_session_component * _ref;
|
||||
List<Cpu_session_component> _ref_members;
|
||||
Lock _ref_members_lock;
|
||||
|
||||
size_t _global_to_local(size_t const q) const { return 0; }
|
||||
size_t _avail() { return 0; }
|
||||
void _incr_weight(size_t);
|
||||
void _decr_weight(size_t);
|
||||
size_t _weight_to_quota(size_t) const;
|
||||
void _decr_quota(size_t);
|
||||
void _incr_quota(size_t);
|
||||
void _update_thread_quota(Cpu_thread_component *) const;
|
||||
void _update_each_thread_quota();
|
||||
void _transfer_quota(Cpu_session_component *, size_t);
|
||||
void _insert_ref_member(Cpu_session_component *) { }
|
||||
void _unsync_remove_ref_member(Cpu_session_component *) { }
|
||||
void _remove_ref_member(Cpu_session_component *) { }
|
||||
void _deinit_ref_account();
|
||||
void _deinit_threads();
|
||||
size_t _local_to_global(size_t) const { return 0; }
|
||||
void _insuff_for_consume(size_t);
|
||||
int _insuff_for_transfer(size_t);
|
||||
int _transfer_back(size_t) { return -1; }
|
||||
int _transfer_forth(Cpu_session_component *, size_t) { return -1; }
|
||||
void _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
|
||||
@ -224,8 +229,7 @@ namespace Genode {
|
||||
Dataspace_capability trace_policy(Thread_capability);
|
||||
int ref_account(Cpu_session_capability c);
|
||||
int transfer_quota(Cpu_session_capability c, size_t q);
|
||||
size_t used();
|
||||
size_t quota();
|
||||
Quota quota() override;
|
||||
|
||||
|
||||
/***********************************
|
||||
|
@ -167,6 +167,11 @@ namespace Genode {
|
||||
unsigned long pager_object_badge() {
|
||||
return (unsigned long) _thread.local.dst(); }
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota) { /* not supported*/ }
|
||||
|
||||
|
||||
/*******************************
|
||||
** Fiasco-specific Accessors **
|
||||
|
@ -1,161 +0,0 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
build "core init drivers/timer test/cpu_quota"
|
||||
|
||||
#
|
||||
# Boot image
|
||||
#
|
||||
|
||||
create_boot_directory
|
||||
|
||||
install_config {
|
||||
<config prio_levels="4">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service><parent/><any-child/></any-service>
|
||||
</default-route>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
|
||||
<start name="init_1" priority="-1">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<resource name="CPU" quantum="10"/>
|
||||
<config prio_levels="2">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="Timer"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service><parent/><any-child/></any-service>
|
||||
</default-route>
|
||||
|
||||
<!-- should receive 10 % of the CPU time -->
|
||||
<start name="test_slow" priority="-1">
|
||||
<binary name="test-cpu_quota"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<resource name="CPU" quantum="50"/>
|
||||
</start>
|
||||
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="init_2" priority="-2">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="100M"/>
|
||||
<resource name="CPU" quantum="80"/>
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="RM"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="Timer"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service><parent/></any-service>
|
||||
</default-route>
|
||||
|
||||
<!-- should receive 25 % of the CPU time -->
|
||||
<start name="test_middle">
|
||||
<binary name="test-cpu_quota"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<resource name="CPU" quantum="25"/>
|
||||
</start>
|
||||
|
||||
<!-- should receive 65 % of the CPU time -->
|
||||
<start name="test_fast">
|
||||
<binary name="test-cpu_quota"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<resource name="CPU" quantum="75"/>
|
||||
</start>
|
||||
|
||||
</config>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
build_boot_image "core init timer test-cpu_quota"
|
||||
|
||||
#
|
||||
# Execution
|
||||
#
|
||||
|
||||
append qemu_args "-nographic -m 64"
|
||||
|
||||
run_genode_until "test.*\n.*test.*\n.*test.*\n" 60
|
||||
|
||||
#
|
||||
# Conclusion
|
||||
#
|
||||
|
||||
set slow_opt 0.10
|
||||
set middle_opt 0.25
|
||||
set fast_opt 0.65
|
||||
set err 0.02
|
||||
|
||||
regexp {[0-9]+} [regexp -inline {slow.*[0-9]+} $output] slow_cnt
|
||||
regexp {[0-9]+} [regexp -inline {middle.*[0-9]+} $output] middle_cnt
|
||||
regexp {[0-9]+} [regexp -inline {fast.*[0-9]+} $output] fast_cnt
|
||||
set total_cnt [expr $fast_cnt + $middle_cnt + $slow_cnt]
|
||||
|
||||
set slow_fac [expr $slow_cnt / double($total_cnt) ]
|
||||
set middle_fac [expr $middle_cnt / double($total_cnt) ]
|
||||
set fast_fac [expr $fast_cnt / double($total_cnt) ]
|
||||
|
||||
set failed 0
|
||||
if {[expr $slow_fac > $slow_opt + $err || $slow_fac < $slow_opt - $err]} {
|
||||
set is_pc [expr round($slow_fac * 10000) / 100]
|
||||
set opt_pc [expr round($slow_opt * 10000) / 100]
|
||||
puts stderr "Error: Slow counter received $is_pc% of the CPU time."
|
||||
puts stderr " Should receive $opt_pc%."
|
||||
set failed 1
|
||||
}
|
||||
if {[expr $middle_fac > $middle_opt + $err || $middle_fac < $middle_opt - $err]} {
|
||||
set is_pc [expr round($middle_fac * 10000) / 100]
|
||||
set opt_pc [expr round($middle_opt * 10000) / 100]
|
||||
puts stderr "Error: Middle counter received $is_pc% of the CPU time."
|
||||
puts stderr " Should receive $opt_pc%."
|
||||
set failed 1
|
||||
}
|
||||
if {[expr $fast_fac > $fast_opt + $err || $fast_fac < $fast_opt - $err]} {
|
||||
set is_pc [expr round($fast_fac * 10000) / 100]
|
||||
set opt_pc [expr round($fast_opt * 10000) / 100]
|
||||
puts stderr "Error: Fast counter received $is_pc% of the CPU time."
|
||||
puts stderr " Should receive $opt_pc%."
|
||||
set failed 1
|
||||
}
|
||||
if {$failed} {
|
||||
exit -1
|
||||
} else {
|
||||
puts "Test succeeded"
|
||||
}
|
@ -30,7 +30,7 @@ extern Native_thread_id _main_thread_id;
|
||||
** Thread_base **
|
||||
*****************/
|
||||
|
||||
void Thread_base::_init_platform_thread(size_t quota, Type type)
|
||||
void Thread_base::_init_platform_thread(size_t weight, Type type)
|
||||
{
|
||||
if (!_cpu_session) { _cpu_session = env()->cpu_session(); }
|
||||
if (type == NORMAL) {
|
||||
@ -38,7 +38,8 @@ void Thread_base::_init_platform_thread(size_t quota, Type type)
|
||||
/* create server object */
|
||||
char buf[48];
|
||||
name(buf, sizeof(buf));
|
||||
_thread_cap = _cpu_session->create_thread(quota, buf, (addr_t)&_context->utcb);
|
||||
addr_t const utcb = (addr_t)&_context->utcb;
|
||||
_thread_cap = _cpu_session->create_thread(weight, buf, utcb);
|
||||
return;
|
||||
}
|
||||
/* if we got reinitialized we have to get rid of the old UTCB */
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
/* core includes */
|
||||
#include <cpu_session_component.h>
|
||||
#include <kernel/configuration.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
@ -30,3 +31,10 @@ Cpu_session_component::utcb(Thread_capability thread_cap)
|
||||
return t->platform_thread()->utcb();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota()
|
||||
{
|
||||
size_t const spu = Kernel::cpu_quota_ms * 1000;
|
||||
size_t const u = quota_lim_downscale<sizet_arithm_t>(_quota, spu);
|
||||
return { spu, u };
|
||||
}
|
||||
|
@ -157,6 +157,11 @@ class Kernel::Thread
|
||||
*/
|
||||
int _read_reg(addr_t const id, addr_t & value) const;
|
||||
|
||||
/**
|
||||
* Return amount of timer tics that 'quota' is worth
|
||||
*/
|
||||
size_t _core_to_kernel_quota(size_t const quota) const;
|
||||
|
||||
/**
|
||||
* Override a thread register
|
||||
*
|
||||
|
@ -75,12 +75,6 @@ namespace Genode {
|
||||
*/
|
||||
bool _attaches_utcb_by_itself();
|
||||
|
||||
static size_t _generic_to_platform_quota(size_t const q)
|
||||
{
|
||||
assert(Kernel::cpu_quota_ms <= Cpu_session::QUOTA_LIMIT);
|
||||
return (q * Kernel::cpu_quota_ms) >> 15;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -143,6 +137,11 @@ namespace Genode {
|
||||
*/
|
||||
void cancel_blocking() { resume(); }
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota);
|
||||
|
||||
/**
|
||||
* Get raw thread state
|
||||
*/
|
||||
|
@ -29,6 +29,8 @@ namespace Genode
|
||||
* CPU driver for core
|
||||
*/
|
||||
class Arm;
|
||||
|
||||
typedef Genode::uint64_t sizet_arithm_t;
|
||||
}
|
||||
|
||||
class Genode::Arm
|
||||
|
@ -13,8 +13,8 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CPU_H_
|
||||
#define _CPU_H_
|
||||
#ifndef _SPEC__X86__CPU_SUPPORT_H_
|
||||
#define _SPEC__X86__CPU_SUPPORT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/register.h>
|
||||
@ -445,4 +445,4 @@ class Genode::Cpu
|
||||
|
||||
};
|
||||
|
||||
#endif /* _CPU_H_ */
|
||||
#endif /* _SPEC__X86__CPU_SUPPORT_H_ */
|
22
repos/base-hw/src/core/include/spec/x86_64/cpu.h
Normal file
22
repos/base-hw/src/core/include/spec/x86_64/cpu.h
Normal 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_ */
|
@ -46,6 +46,8 @@ extern void * _start_secondary_cpus;
|
||||
extern int _prog_img_beg;
|
||||
extern int _prog_img_end;
|
||||
|
||||
static_assert(sizeof(Genode::sizet_arithm_t) >= 2 * sizeof(size_t),
|
||||
"Bad result type for size_t arithmetics.");
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
/* Genode includes */
|
||||
#include <base/thread_state.h>
|
||||
#include <unmanaged_singleton.h>
|
||||
#include <cpu_session/cpu_session.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/kernel.h>
|
||||
@ -224,12 +225,21 @@ void Thread::_call_new_pd()
|
||||
void Thread::_call_delete_pd() { reinterpret_cast<Pd*>(user_arg_1())->~Pd(); }
|
||||
|
||||
|
||||
size_t Thread::_core_to_kernel_quota(size_t const quota) const
|
||||
{
|
||||
using Genode::Cpu_session;
|
||||
using Genode::sizet_arithm_t;
|
||||
size_t const tics = cpu_pool()->timer()->ms_to_tics(Kernel::cpu_quota_ms);
|
||||
return Cpu_session::quota_lim_downscale<sizet_arithm_t>(quota, tics);
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_new_thread()
|
||||
{
|
||||
/* create new thread */
|
||||
void * const p = (void *)user_arg_1();
|
||||
unsigned const priority = user_arg_2();
|
||||
unsigned const quota = cpu_pool()->timer()->ms_to_tics(user_arg_3());
|
||||
unsigned const quota = _core_to_kernel_quota(user_arg_3());
|
||||
char const * const label = (char *)user_arg_4();
|
||||
Thread * const t = new (p) Thread(priority, quota, label);
|
||||
user_arg_0(t->id());
|
||||
@ -239,8 +249,7 @@ void Thread::_call_new_thread()
|
||||
void Thread::_call_thread_quota()
|
||||
{
|
||||
Thread * const thread = (Thread *)user_arg_1();
|
||||
unsigned const quota = cpu_pool()->timer()->ms_to_tics(user_arg_2());
|
||||
thread->Cpu_job::quota(quota);
|
||||
thread->Cpu_job::quota(_core_to_kernel_quota(user_arg_2()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,6 +78,10 @@ Platform_thread::~Platform_thread()
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::quota(size_t const quota) {
|
||||
Kernel::thread_quota((Kernel::Thread *)_kernel_thread, quota); }
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(const char * const label,
|
||||
Native_utcb * utcb)
|
||||
: _pd(Kernel::core_pd()->platform_pd()),
|
||||
@ -110,7 +114,8 @@ Platform_thread::Platform_thread(const char * const label,
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t quota, const char * const label,
|
||||
Platform_thread::Platform_thread(size_t const quota,
|
||||
const char * const label,
|
||||
unsigned const virt_prio,
|
||||
addr_t const utcb)
|
||||
:
|
||||
@ -139,7 +144,6 @@ Platform_thread::Platform_thread(size_t quota, const char * const label,
|
||||
/* create kernel object */
|
||||
constexpr unsigned max_prio = Kernel::Cpu_priority::max;
|
||||
auto const phys_prio = Cpu_session::scale_priority(max_prio, virt_prio);
|
||||
quota = _generic_to_platform_quota(quota);
|
||||
_id = Kernel::new_thread(_kernel_thread, phys_prio, quota, _label);
|
||||
if (!_id) {
|
||||
PERR("failed to create kernel object");
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* \brief Sync-session capability type
|
||||
* \author Martin Stein
|
||||
* \date 2015-04-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SYNC_SESSION__CAPABILITY_H_
|
||||
#define _SYNC_SESSION__CAPABILITY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/capability.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sync_session/sync_session.h>
|
||||
|
||||
namespace Sync
|
||||
{
|
||||
using Genode::Capability;
|
||||
|
||||
typedef Capability<Session> Session_capability;
|
||||
}
|
||||
|
||||
#endif /* _SYNC_SESSION__CAPABILITY_H_ */
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* \brief Client-side Sync-session interface
|
||||
* \author Martin Stein
|
||||
* \date 2015-04-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SYNC_SESSION__CLIENT_H_
|
||||
#define _SYNC_SESSION__CLIENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/rpc_client.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sync_session/capability.h>
|
||||
|
||||
namespace Sync
|
||||
{
|
||||
using Genode::Rpc_client;
|
||||
|
||||
struct Session_client;
|
||||
}
|
||||
|
||||
|
||||
struct Sync::Session_client : Rpc_client<Session>
|
||||
{
|
||||
explicit Session_client(Session_capability session)
|
||||
: Rpc_client<Session>(session) { }
|
||||
|
||||
void threshold(unsigned id, unsigned threshold) override {
|
||||
call<Rpc_threshold>(id, threshold); }
|
||||
|
||||
void submit(unsigned id, Signal_context_capability sigc) override {
|
||||
call<Rpc_submit>(id, sigc); }
|
||||
};
|
||||
|
||||
#endif /* _SYNC_SESSION__CLIENT_H_ */
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* \brief Connection to Sync service
|
||||
* \author Martin Stein
|
||||
* \date 2015-04-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SYNC_SESSION__CONNECTION_H_
|
||||
#define _SYNC_SESSION__CONNECTION_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sync_session/client.h>
|
||||
|
||||
namespace Sync
|
||||
{
|
||||
using Genode::Parent;
|
||||
|
||||
class Connection;
|
||||
}
|
||||
|
||||
|
||||
class Sync::Connection : public Genode::Connection<Session>,
|
||||
public Session_client
|
||||
{
|
||||
public:
|
||||
|
||||
class Connection_failed : public Parent::Exception { };
|
||||
|
||||
private:
|
||||
|
||||
Session_capability _create_session()
|
||||
{
|
||||
try { return session("ram_quota=4K"); }
|
||||
catch (...) { throw Connection_failed(); }
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \throw Connection_failed
|
||||
*/
|
||||
Connection() :
|
||||
Genode::Connection<Session>(_create_session()),
|
||||
Session_client(cap())
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _SYNC_SESSION__CONNECTION_H_ */
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief Sync session interface
|
||||
* \author Martin Stein
|
||||
* \date 2015-04-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SYNC_SESSION__SYNC_SESSION_H_
|
||||
#define _SYNC_SESSION__SYNC_SESSION_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <session/session.h>
|
||||
#include <signal_session/signal_session.h>
|
||||
|
||||
namespace Sync
|
||||
{
|
||||
using Genode::Signal_context_capability;
|
||||
|
||||
struct Session;
|
||||
}
|
||||
|
||||
|
||||
struct Sync::Session : Genode::Session
|
||||
{
|
||||
static const char *service_name() { return "Sync"; }
|
||||
|
||||
virtual ~Session() { }
|
||||
|
||||
/**
|
||||
* Set the submission threshold of a synchronization signal
|
||||
*/
|
||||
virtual void threshold(unsigned id, unsigned threshold) = 0;
|
||||
|
||||
/**
|
||||
* Submit to a synchronization signal
|
||||
*/
|
||||
virtual void submit(unsigned id, Signal_context_capability sigc) = 0;
|
||||
|
||||
|
||||
/*********************
|
||||
** RPC declaration **
|
||||
*********************/
|
||||
|
||||
GENODE_RPC(Rpc_threshold, void, threshold, unsigned, unsigned);
|
||||
GENODE_RPC(Rpc_submit, void, submit, unsigned, Signal_context_capability);
|
||||
|
||||
GENODE_RPC_INTERFACE(Rpc_threshold, Rpc_submit);
|
||||
};
|
||||
|
||||
#endif /* _SYNC_SESSION__SYNC_SESSION_H_ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Diversified test of the Register and MMIO framework
|
||||
* \brief Test the distribution and application of CPU quota
|
||||
* \author Martin Stein
|
||||
* \date 2012-01-09
|
||||
*/
|
||||
@ -14,50 +14,150 @@
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <sync_session/connection.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class My_thread : public Thread<8 * 1024>
|
||||
enum { SYNC_SIG = 0 };
|
||||
|
||||
namespace Sync { class Signal; }
|
||||
|
||||
class Single_signal
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_receiver * const _sigr;
|
||||
bool volatile _stop;
|
||||
Signal_receiver _sigr;
|
||||
Signal_context _sigx;
|
||||
Signal_context_capability _sigc;
|
||||
Signal_transmitter _sigt;
|
||||
|
||||
public:
|
||||
|
||||
My_thread(Signal_receiver * const sigr)
|
||||
: Thread(Cpu_session::pc_to_quota(100), "counter"),
|
||||
_sigr(sigr), _stop(0) { }
|
||||
Single_signal() : _sigc(_sigr.manage(&_sigx)), _sigt(_sigc) { }
|
||||
|
||||
~Single_signal() { _sigr.dissolve(&_sigx); }
|
||||
|
||||
void receive() { _sigr.wait_for_signal(); }
|
||||
|
||||
void submit() { _sigt.submit(); }
|
||||
};
|
||||
|
||||
class Sync::Signal
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_receiver _sigr;
|
||||
Signal_context _sigx;
|
||||
Signal_context_capability _sigc;
|
||||
Session * const _session;
|
||||
unsigned const _id;
|
||||
|
||||
public:
|
||||
|
||||
Signal(Session * const session, unsigned const id)
|
||||
: _sigc(_sigr.manage(&_sigx)), _session(session), _id(id) { }
|
||||
|
||||
~Signal() { _sigr.dissolve(&_sigx); }
|
||||
|
||||
void threshold(unsigned const threshold) {
|
||||
_session->threshold(_id, threshold); }
|
||||
|
||||
void sync()
|
||||
{
|
||||
_session->submit(_id, _sigc);
|
||||
_sigr.wait_for_signal();
|
||||
}
|
||||
};
|
||||
|
||||
class Counter : private Thread<8 * 1024>
|
||||
{
|
||||
private:
|
||||
|
||||
char const _name;
|
||||
unsigned volatile _value;
|
||||
Sync::Signal _sync_sig;
|
||||
unsigned volatile _stage;
|
||||
Single_signal _stage_1_end;
|
||||
Single_signal _stage_2_reached;
|
||||
|
||||
inline void _stage_0_and_1(unsigned volatile & value)
|
||||
{
|
||||
_stage_1_end.receive();
|
||||
_stage = 0;
|
||||
_sync_sig.sync();
|
||||
while(_stage == 0) { value++; }
|
||||
}
|
||||
|
||||
void entry()
|
||||
{
|
||||
_sigr->wait_for_signal();
|
||||
unsigned volatile i = 0;
|
||||
while(!_stop) { i++; }
|
||||
printf("%u\n", i);
|
||||
unsigned volatile value = 0;
|
||||
while (_stage < 2) { _stage_0_and_1(value); }
|
||||
_value = value;
|
||||
_stage_2_reached.submit();
|
||||
sleep_forever();
|
||||
}
|
||||
|
||||
void stop() { _stop = 1; }
|
||||
public:
|
||||
|
||||
Counter(char const name, size_t const weight,
|
||||
Sync::Session * const sync)
|
||||
:
|
||||
Thread(weight, "counter"), _name(name), _value(0) ,
|
||||
_sync_sig(sync, SYNC_SIG), _stage(1)
|
||||
{
|
||||
Thread::start();
|
||||
}
|
||||
|
||||
void destruct()
|
||||
{
|
||||
_stage = 2;
|
||||
_stage_2_reached.receive();
|
||||
this->~Counter();
|
||||
}
|
||||
|
||||
void pause() { _stage = 1; }
|
||||
|
||||
void go() { _stage_1_end.submit(); }
|
||||
|
||||
void result() { printf("counter %c %u\n", _name, _value); }
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
/* prepare */
|
||||
Timer::Connection timer;
|
||||
Signal_receiver sigr;
|
||||
Signal_context sigx;
|
||||
Signal_context_capability sigc = sigr.manage(&sigx);
|
||||
Signal_transmitter sigt(sigc);
|
||||
My_thread thread(&sigr);
|
||||
thread.start();
|
||||
timer.msleep(3000);
|
||||
sigt.submit();
|
||||
timer.msleep(30000);
|
||||
thread.stop();
|
||||
Sync::Connection sync;
|
||||
Sync::Signal sync_sig(&sync, SYNC_SIG);
|
||||
Counter counter_a('A', Cpu_session::quota_lim_upscale(10, 100), &sync);
|
||||
Counter counter_b('B', Cpu_session::quota_lim_upscale(90, 100), &sync);
|
||||
|
||||
/* measure stage 1 */
|
||||
sync_sig.threshold(9);
|
||||
counter_a.go();
|
||||
counter_b.go();
|
||||
sync_sig.sync();
|
||||
timer.msleep(45000);
|
||||
counter_a.pause();
|
||||
counter_b.destruct();
|
||||
|
||||
/* measure stage 2 */
|
||||
sync_sig.threshold(6);
|
||||
counter_a.go();
|
||||
sync_sig.sync();
|
||||
timer.msleep(15000);
|
||||
counter_a.destruct();
|
||||
|
||||
/* print results */
|
||||
sync_sig.threshold(3);
|
||||
sync_sig.sync();
|
||||
Cpu_session::Quota quota = Genode::env()->cpu_session()->quota();
|
||||
Genode::printf("quota super period %zu\n", quota.super_period_us);
|
||||
Genode::printf("quota %zu\n", quota.us);
|
||||
counter_a.result();
|
||||
counter_b.result();
|
||||
printf("done\n");
|
||||
sleep_forever();
|
||||
}
|
||||
|
||||
|
152
repos/base-hw/src/test/cpu_quota/sync/main.cc
Normal file
152
repos/base-hw/src/test/cpu_quota/sync/main.cc
Normal 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); }
|
||||
}
|
17
repos/base-hw/src/test/cpu_quota/sync/target.mk
Normal file
17
repos/base-hw/src/test/cpu_quota/sync/target.mk
Normal 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
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# \brief Test static configuration of CPU-time distribution
|
||||
# \brief Test the distribution and application of CPU quota
|
||||
# \author Martin Stein
|
||||
# \date 2014-10-13
|
||||
#
|
||||
@ -10,5 +10,8 @@ TARGET = test-cpu_quota
|
||||
# Add C++ sources
|
||||
SRC_CC += main.cc
|
||||
|
||||
# Add include paths
|
||||
INC_DIR += $(PRG_DIR)/include
|
||||
|
||||
# Add libraries
|
||||
LIBS += base
|
||||
|
@ -24,8 +24,8 @@ namespace Genode {
|
||||
explicit Linux_cpu_session_client(Capability<Linux_cpu_session> session)
|
||||
: Rpc_client<Linux_cpu_session>(session) { }
|
||||
|
||||
Thread_capability create_thread(size_t, Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(0, name, utcb); }
|
||||
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(weight, name, utcb); }
|
||||
|
||||
Ram_dataspace_capability utcb(Thread_capability thread) {
|
||||
return call<Rpc_utcb>(thread); }
|
||||
@ -84,9 +84,7 @@ namespace Genode {
|
||||
int transfer_quota(Cpu_session_capability session, size_t amount) {
|
||||
return call<Rpc_transfer_quota>(session, amount); }
|
||||
|
||||
size_t quota() { return call<Rpc_quota>(); }
|
||||
|
||||
size_t used() { return call<Rpc_used>(); }
|
||||
Quota quota() override { return call<Rpc_quota>(); }
|
||||
|
||||
/*****************************
|
||||
* Linux-specific extension **
|
||||
|
4
repos/base-linux/src/base/env/platform_env.h
vendored
4
repos/base-linux/src/base/env/platform_env.h
vendored
@ -44,10 +44,10 @@ struct Genode::Expanding_cpu_session_client
|
||||
Expanding_cpu_session_client(Genode::Capability<Linux_cpu_session> cap)
|
||||
: Upgradeable_client<Genode::Linux_cpu_session_client>(cap) { }
|
||||
|
||||
Thread_capability create_thread(size_t, Name const &name, addr_t utcb)
|
||||
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb)
|
||||
{
|
||||
return retry<Cpu_session::Out_of_metadata>(
|
||||
[&] () { return Linux_cpu_session_client::create_thread(0, name, utcb); },
|
||||
[&] () { return Linux_cpu_session_client::create_thread(weight, name, utcb); },
|
||||
[&] () { upgrade_ram(8*1024); });
|
||||
}
|
||||
};
|
||||
|
@ -80,7 +80,8 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
|
||||
* thread. Those information will be provided to core by the constructor of
|
||||
* the 'Platform_env' of the new process.
|
||||
*/
|
||||
_thread0_cap = _cpu_session_client.create_thread(0, name);
|
||||
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
|
||||
_thread0_cap = _cpu_session_client.create_thread(WEIGHT, name);
|
||||
|
||||
Linux_pd_session_client lx_pd(static_cap_cast<Linux_pd_session>(_pd.cap()));
|
||||
|
||||
|
@ -69,7 +69,7 @@ void Thread_base::_thread_start()
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::_init_platform_thread(size_t, Type type)
|
||||
void Thread_base::_init_platform_thread(size_t weight, Type type)
|
||||
{
|
||||
/* if no cpu session is given, use it from the environment */
|
||||
if (!_cpu_session)
|
||||
@ -77,7 +77,7 @@ void Thread_base::_init_platform_thread(size_t, Type type)
|
||||
|
||||
/* for normal threads create an object at the CPU session */
|
||||
if (type == NORMAL) {
|
||||
_thread_cap = _cpu_session->create_thread(0, _context->name);
|
||||
_thread_cap = _cpu_session->create_thread(weight, _context->name);
|
||||
return;
|
||||
}
|
||||
/* adjust initial object state for main threads */
|
||||
|
@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -63,7 +63,9 @@ namespace Genode {
|
||||
|
||||
public:
|
||||
|
||||
Cpu_thread_component(size_t, Session_label const &label,
|
||||
Cpu_thread_component(size_t const weight,
|
||||
size_t const quota,
|
||||
Session_label const &label,
|
||||
Thread_name const &name,
|
||||
unsigned priority, addr_t utcb,
|
||||
Signal_context_capability sigh,
|
||||
@ -87,7 +89,8 @@ namespace Genode {
|
||||
bool bound() const { return _bound; }
|
||||
void bound(bool b) { _bound = b; }
|
||||
Trace::Source *trace_source() { return &_trace_source; }
|
||||
size_t quota() { return 0; }
|
||||
|
||||
size_t weight() const { return Cpu_session::DEFAULT_WEIGHT; }
|
||||
|
||||
void sigh(Signal_context_capability sigh)
|
||||
{
|
||||
@ -131,24 +134,26 @@ namespace Genode {
|
||||
session */
|
||||
Trace::Source_registry &_trace_sources;
|
||||
Trace::Control_area _trace_control_area;
|
||||
Cpu_session_component * _ref;
|
||||
size_t _used;
|
||||
|
||||
size_t _weight;
|
||||
size_t _quota;
|
||||
Cpu_session_component * _ref;
|
||||
List<Cpu_session_component> _ref_members;
|
||||
Lock _ref_members_lock;
|
||||
|
||||
size_t _global_to_local(size_t const q) const { return 0; }
|
||||
size_t _avail() { return 0; }
|
||||
void _incr_weight(size_t);
|
||||
void _decr_weight(size_t);
|
||||
size_t _weight_to_quota(size_t) const;
|
||||
void _decr_quota(size_t);
|
||||
void _incr_quota(size_t);
|
||||
void _update_thread_quota(Cpu_thread_component *) const;
|
||||
void _update_each_thread_quota();
|
||||
void _transfer_quota(Cpu_session_component *, size_t);
|
||||
void _insert_ref_member(Cpu_session_component *) { }
|
||||
void _unsync_remove_ref_member(Cpu_session_component *) { }
|
||||
void _remove_ref_member(Cpu_session_component *) { }
|
||||
void _deinit_ref_account();
|
||||
void _deinit_threads();
|
||||
size_t _local_to_global(size_t) const { return 0; }
|
||||
void _insuff_for_consume(size_t);
|
||||
int _insuff_for_transfer(size_t);
|
||||
int _transfer_back(size_t) { return -1; }
|
||||
int _transfer_forth(Cpu_session_component *, size_t) { return -1; }
|
||||
void _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
|
||||
@ -214,8 +219,7 @@ namespace Genode {
|
||||
Dataspace_capability trace_policy(Thread_capability);
|
||||
int ref_account(Cpu_session_capability c);
|
||||
int transfer_quota(Cpu_session_capability c, size_t q);
|
||||
size_t used();
|
||||
size_t quota();
|
||||
Quota quota() override;
|
||||
|
||||
|
||||
/*******************************
|
||||
|
@ -153,6 +153,11 @@ namespace Genode {
|
||||
{
|
||||
_registry()->submit_exception(pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota) { /* not supported*/ }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ void Thread_base::join()
|
||||
}
|
||||
|
||||
|
||||
Thread_base::Thread_base(size_t, const char *name, size_t stack_size,
|
||||
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
|
||||
Type type, Cpu_session * cpu_sess)
|
||||
: _cpu_session(cpu_sess)
|
||||
{
|
||||
@ -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);
|
||||
|
||||
_thread_cap = cpu->create_thread(0, name);
|
||||
_thread_cap = cpu->create_thread(weight, name);
|
||||
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(0, name, stack_size, type, env()->cpu_session()) { }
|
||||
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
|
||||
Type type)
|
||||
: Thread_base(weight, name, stack_size, type, env()->cpu_session()) { }
|
||||
|
||||
void Thread_base::cancel_blocking()
|
||||
{
|
||||
|
@ -28,8 +28,8 @@ namespace Genode {
|
||||
explicit Cpu_session_client(Cpu_session_capability 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) {
|
||||
return call<Rpc_create_thread>(0, name, utcb); }
|
||||
Thread_capability create_thread(size_t weight, Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(weight, name, utcb); }
|
||||
|
||||
Ram_dataspace_capability utcb(Thread_capability thread) {
|
||||
return call<Rpc_utcb>(thread); }
|
||||
@ -100,9 +100,7 @@ namespace Genode {
|
||||
int transfer_quota(Cpu_session_capability session, size_t amount) {
|
||||
return call<Rpc_transfer_quota>(session, amount); }
|
||||
|
||||
size_t quota() { return call<Rpc_quota>(); }
|
||||
|
||||
size_t used() { return call<Rpc_used>(); }
|
||||
Quota quota() override { return call<Rpc_quota>(); }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -599,7 +599,7 @@ Pager_object::~Pager_object()
|
||||
|
||||
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)
|
||||
{
|
||||
/* tell thread starting code on which CPU to let run the pager */
|
||||
|
@ -221,7 +221,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
|
||||
const char *name, bool start_on_construction,
|
||||
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),
|
||||
_delay_start(Lock::LOCKED),
|
||||
_cap_session(cap_session)
|
||||
|
@ -65,7 +65,7 @@ void Thread_base::_thread_start()
|
||||
** 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;
|
||||
|
||||
@ -101,7 +101,7 @@ void Thread_base::_init_platform_thread(size_t, Type type)
|
||||
char buf[48];
|
||||
name(buf, sizeof(buf));
|
||||
|
||||
_thread_cap = _cpu_session->create_thread(0, buf);
|
||||
_thread_cap = _cpu_session->create_thread(weight, buf);
|
||||
if (!_thread_cap.valid())
|
||||
throw Cpu_session::Thread_creation_failed();
|
||||
|
||||
|
@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -64,7 +64,9 @@ namespace Genode {
|
||||
|
||||
public:
|
||||
|
||||
Cpu_thread_component(size_t, Session_label const &label,
|
||||
Cpu_thread_component(size_t const weight,
|
||||
size_t const quota,
|
||||
Session_label const &label,
|
||||
Thread_name const &name,
|
||||
unsigned priority, addr_t utcb,
|
||||
Signal_context_capability sigh,
|
||||
@ -88,7 +90,8 @@ namespace Genode {
|
||||
bool bound() const { return _bound; }
|
||||
void bound(bool b) { _bound = b; }
|
||||
Trace::Source *trace_source() { return &_trace_source; }
|
||||
size_t quota() { return 0; }
|
||||
|
||||
size_t weight() const { return Cpu_session::DEFAULT_WEIGHT; }
|
||||
|
||||
void sigh(Signal_context_capability sigh)
|
||||
{
|
||||
@ -138,24 +141,26 @@ namespace Genode {
|
||||
session */
|
||||
Trace::Source_registry &_trace_sources;
|
||||
Trace::Control_area _trace_control_area;
|
||||
Cpu_session_component * _ref;
|
||||
size_t _used;
|
||||
|
||||
size_t _weight;
|
||||
size_t _quota;
|
||||
Cpu_session_component * _ref;
|
||||
List<Cpu_session_component> _ref_members;
|
||||
Lock _ref_members_lock;
|
||||
|
||||
size_t _global_to_local(size_t const q) const { return 0; }
|
||||
size_t _avail() { return 0; }
|
||||
void _incr_weight(size_t);
|
||||
void _decr_weight(size_t);
|
||||
size_t _weight_to_quota(size_t) const;
|
||||
void _decr_quota(size_t);
|
||||
void _incr_quota(size_t);
|
||||
void _update_thread_quota(Cpu_thread_component *) const;
|
||||
void _update_each_thread_quota();
|
||||
void _transfer_quota(Cpu_session_component *, size_t);
|
||||
void _insert_ref_member(Cpu_session_component *) { }
|
||||
void _unsync_remove_ref_member(Cpu_session_component *) { }
|
||||
void _remove_ref_member(Cpu_session_component *) { }
|
||||
void _deinit_ref_account();
|
||||
void _deinit_threads();
|
||||
size_t _local_to_global(size_t) const { return 0; }
|
||||
void _insuff_for_consume(size_t);
|
||||
int _insuff_for_transfer(size_t);
|
||||
int _transfer_back(size_t) { return -1; }
|
||||
int _transfer_forth(Cpu_session_component *, size_t) { return -1; }
|
||||
void _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
|
||||
@ -222,8 +227,7 @@ namespace Genode {
|
||||
Dataspace_capability trace_policy(Thread_capability);
|
||||
int ref_account(Cpu_session_capability c);
|
||||
int transfer_quota(Cpu_session_capability c, size_t q);
|
||||
size_t used();
|
||||
size_t quota();
|
||||
Quota quota() override;
|
||||
|
||||
|
||||
/******************************
|
||||
|
@ -164,6 +164,11 @@ namespace Genode {
|
||||
}
|
||||
|
||||
Native_capability single_step(bool on);
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota) { /* not supported*/ }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,9 @@ class Irq_thread : public Thread_base
|
||||
{
|
||||
private:
|
||||
|
||||
enum { STACK_SIZE = 1024 * sizeof(addr_t) };
|
||||
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
static void _thread_start()
|
||||
{
|
||||
Thread_base::myself()->entry();
|
||||
@ -49,7 +52,8 @@ class Irq_thread : public Thread_base
|
||||
|
||||
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
|
||||
|
@ -26,3 +26,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -147,6 +147,11 @@ namespace Genode {
|
||||
*/
|
||||
Affinity::Location affinity() { return Affinity::Location(); }
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread
|
||||
*/
|
||||
void quota(size_t) { /* not supported */ }
|
||||
|
||||
|
||||
/*****************************
|
||||
** OKL4-specific Accessors **
|
||||
|
@ -32,3 +32,5 @@ Ram_dataspace_capability Cpu_session_component::utcb(Thread_capability thread_ca
|
||||
return Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -148,6 +148,11 @@ namespace Genode {
|
||||
*/
|
||||
Affinity::Location affinity();
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const quota) { /* not supported*/ }
|
||||
|
||||
|
||||
/**********************************
|
||||
** Pistachio-specific Accessors **
|
||||
|
@ -132,6 +132,8 @@ class Genode::Pager_activation_base: public Thread_base
|
||||
{
|
||||
private:
|
||||
|
||||
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
Native_capability _cap;
|
||||
Pager_entrypoint *_ep; /* entry point to which the
|
||||
activation belongs */
|
||||
@ -142,9 +144,9 @@ class Genode::Pager_activation_base: public Thread_base
|
||||
|
||||
public:
|
||||
|
||||
Pager_activation_base(const char *name, size_t stack_size) :
|
||||
Thread_base(0, name, stack_size),
|
||||
_cap(Native_capability()), _ep(0), _cap_valid(Lock::LOCKED) { }
|
||||
Pager_activation_base(const char *name, size_t stack_size)
|
||||
: Thread_base(WEIGHT, name, stack_size), _cap(Native_capability()),
|
||||
_ep(0), _cap_valid(Lock::LOCKED) { }
|
||||
|
||||
/**
|
||||
* Set entry point, which the activation serves
|
||||
|
@ -330,10 +330,10 @@ class Genode::Thread_base
|
||||
/**
|
||||
* Hook for platform-specific constructor supplements
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param type enables selection of special initialization
|
||||
* \param weight weighting regarding the CPU session quota
|
||||
* \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:
|
||||
|
||||
@ -347,14 +347,14 @@ class Genode::Thread_base
|
||||
* at least set Context::ds_cap in a way that it references
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name for DEBUGging
|
||||
* \param weight weighting regarding the CPU session quota
|
||||
* \param name thread name (for debugging)
|
||||
* \param stack_size stack size
|
||||
*
|
||||
* \throw Stack_too_large
|
||||
@ -366,10 +366,8 @@ class Genode::Thread_base
|
||||
* internally used by the framework for storing thread-context
|
||||
* information such as the thread's name ('Context').
|
||||
*/
|
||||
Thread_base(size_t quota, const char *name, size_t stack_size)
|
||||
:
|
||||
Thread_base(quota, name, stack_size, NORMAL)
|
||||
{ }
|
||||
Thread_base(size_t weight, const char *name, size_t stack_size)
|
||||
: Thread_base(weight, name, stack_size, NORMAL) { }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -380,8 +378,8 @@ class Genode::Thread_base
|
||||
* \noapi Using multiple CPU sessions within a single component is
|
||||
* an experimental feature.
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name for debugging
|
||||
* \param weight weighting regarding the CPU session quota
|
||||
* \param name thread name (for debugging)
|
||||
* \param stack_size stack size
|
||||
* \param type enables selection of special construction
|
||||
* \param cpu_session capability to cpu session used for construction
|
||||
@ -390,7 +388,7 @@ class Genode::Thread_base
|
||||
* \throw Stack_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 *);
|
||||
|
||||
/**
|
||||
@ -536,53 +534,54 @@ class Genode::Thread : public Thread_base
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name (for debugging)
|
||||
* \param type enables selection of special construction
|
||||
* \param weight weighting regarding the CPU session quota
|
||||
* \param name thread name (for debugging)
|
||||
* \param type enables selection of special construction
|
||||
*/
|
||||
explicit Thread(size_t quota, const char *name)
|
||||
: Thread_base(quota, name, STACK_SIZE, Type::NORMAL) { }
|
||||
explicit Thread(size_t weight, const char *name)
|
||||
: Thread_base(weight, name, STACK_SIZE, Type::NORMAL) { }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name (for debugging)
|
||||
* \param type enables selection of special construction
|
||||
* \param weight weighting regarding the CPU session quota
|
||||
* \param name thread name (for debugging)
|
||||
* \param type enables selection of special construction
|
||||
*
|
||||
* \noapi
|
||||
*/
|
||||
explicit Thread(size_t quota, const char *name, Type type)
|
||||
: Thread_base(quota, name, STACK_SIZE, type) { }
|
||||
explicit Thread(size_t weight, const char *name, Type type)
|
||||
: Thread_base(weight, name, STACK_SIZE, type) { }
|
||||
|
||||
/**
|
||||
* 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 cpu_session thread created via specific cpu session
|
||||
*
|
||||
* \noapi
|
||||
*/
|
||||
explicit Thread(size_t quota, const char *name, Cpu_session * cpu_session)
|
||||
: Thread_base(quota, name, STACK_SIZE, Type::NORMAL, cpu_session)
|
||||
{ }
|
||||
explicit Thread(size_t weight, const char *name,
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -86,9 +86,7 @@ struct Genode::Cpu_session_client : Rpc_client<Cpu_session>
|
||||
int transfer_quota(Cpu_session_capability session, size_t amount) override {
|
||||
return call<Rpc_transfer_quota>(session, amount); }
|
||||
|
||||
size_t quota() override { return call<Rpc_quota>(); }
|
||||
|
||||
size_t used() override { return call<Rpc_used>(); }
|
||||
Quota quota() override { return call<Rpc_quota>(); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__CPU_SESSION__CLIENT_H_ */
|
||||
|
@ -47,9 +47,15 @@ struct Genode::Cpu_session : Session
|
||||
enum { QUOTA_LIMIT_LOG2 = 15 };
|
||||
enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 };
|
||||
enum { DEFAULT_PRIORITY = 0 };
|
||||
enum { DEFAULT_WEIGHT = 10 };
|
||||
|
||||
typedef Rpc_in_buffer<THREAD_NAME_LEN> Name;
|
||||
|
||||
/**
|
||||
* Physical quota configuration
|
||||
*/
|
||||
struct Quota;
|
||||
|
||||
virtual ~Cpu_session() { }
|
||||
|
||||
/**
|
||||
@ -264,7 +270,8 @@ struct Genode::Cpu_session : Session
|
||||
* Transfer quota to another CPU session
|
||||
*
|
||||
* \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
|
||||
*
|
||||
* Quota can only be transfered if the specified CPU session is
|
||||
@ -274,29 +281,23 @@ struct Genode::Cpu_session : Session
|
||||
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()
|
||||
{
|
||||
size_t q = quota(), u = used();
|
||||
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; }
|
||||
template<typename T = size_t>
|
||||
static size_t quota_lim_downscale(size_t const value, size_t const limit) {
|
||||
return ((T)value * limit) >> Cpu_session::QUOTA_LIMIT_LOG2; }
|
||||
|
||||
/*********************
|
||||
** 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_ref_account, int, ref_account, Cpu_session_capability);
|
||||
GENODE_RPC(Rpc_transfer_quota, int, transfer_quota, Cpu_session_capability, size_t);
|
||||
GENODE_RPC(Rpc_quota, size_t, quota);
|
||||
GENODE_RPC(Rpc_used, size_t, used);
|
||||
GENODE_RPC(Rpc_quota, Quota, quota);
|
||||
|
||||
/*
|
||||
* '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_transfer_quota,
|
||||
Meta::Type_tuple<Rpc_quota,
|
||||
Meta::Type_tuple<Rpc_used,
|
||||
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_ */
|
||||
|
@ -198,7 +198,8 @@ Process::Process(Dataspace_capability elf_ds_cap,
|
||||
|
||||
/* create thread0 */
|
||||
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) {
|
||||
PERR("Creation of thread0 failed");
|
||||
throw THREAD_FAIL;
|
||||
|
@ -102,7 +102,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
|
||||
char const *name, bool start_on_construction,
|
||||
Affinity::Location location)
|
||||
:
|
||||
Thread_base(0, name, stack_size),
|
||||
Thread_base(Cpu_session::DEFAULT_WEIGHT, name, stack_size),
|
||||
_cap(Untyped_capability()),
|
||||
_curr_obj(0), _cap_valid(Lock::LOCKED), _delay_start(Lock::LOCKED),
|
||||
_delay_exit(Lock::LOCKED),
|
||||
|
@ -54,7 +54,9 @@ void Thread_base::start()
|
||||
/* create thread at core */
|
||||
char buf[48];
|
||||
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())
|
||||
throw Cpu_session::Thread_creation_failed();
|
||||
|
||||
|
@ -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,
|
||||
addr_t utcb)
|
||||
{
|
||||
/* check for sufficient quota */
|
||||
quota = _local_to_global(quota);
|
||||
if (quota > avail()) { _insuff_for_consume(quota); }
|
||||
|
||||
unsigned trace_control_index = 0;
|
||||
if (!_trace_control_area.alloc(trace_control_index))
|
||||
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());
|
||||
|
||||
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 {
|
||||
Lock::Guard slab_lock_guard(_thread_alloc_lock);
|
||||
thread = new(&_thread_alloc)
|
||||
Cpu_thread_component(
|
||||
quota, _label, thread_name, _priority, utcb,
|
||||
_default_exception_handler, trace_control_index,
|
||||
*trace_control);
|
||||
|
||||
/* account quota */
|
||||
_used += quota;
|
||||
weight, _weight_to_quota(weight), _label, thread_name,
|
||||
_priority, utcb, _default_exception_handler,
|
||||
trace_control_index, *trace_control);
|
||||
|
||||
/* set default affinity defined by CPU session */
|
||||
thread->platform_thread()->affinity(_location);
|
||||
@ -68,7 +75,6 @@ Thread_capability Cpu_session_component::create_thread(size_t quota,
|
||||
throw Out_of_metadata();
|
||||
}
|
||||
|
||||
Lock::Guard thread_list_lock_guard(_thread_list_lock);
|
||||
_thread_list.insert(thread);
|
||||
|
||||
_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();
|
||||
|
||||
_used -= thread->quota();
|
||||
_decr_weight(thread->weight());
|
||||
|
||||
Lock::Guard lock_guard(_thread_alloc_lock);
|
||||
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 */
|
||||
Object_pool<Cpu_session_component>::Guard s(_session_ep->lookup_and_lock(c));
|
||||
if (!s) { return -1; }
|
||||
|
||||
/* 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;
|
||||
if (!quota) { return; }
|
||||
_decr_quota(quota);
|
||||
dst->_incr_quota(quota);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
*
|
||||
* FIXME Add check for cycles along the tree of reference accounts
|
||||
*/
|
||||
if (_ref) { return -2; }
|
||||
|
||||
/* lookup targeted CPU-session */
|
||||
Object_pool<Cpu_session_component>::Guard s(_session_ep->lookup_and_lock(c));
|
||||
if (!s) { return -1; }
|
||||
if (s == this) { return -3; }
|
||||
if (_ref) {
|
||||
PWRN("Set ref account, %s, set already",
|
||||
_label.string());
|
||||
return -2; }
|
||||
|
||||
/* 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 */
|
||||
_ref = s;
|
||||
_ref = ref;
|
||||
_ref->_insert_ref_member(this);
|
||||
return 0;
|
||||
}
|
||||
@ -335,7 +374,7 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint *session_ep,
|
||||
Trace::Source_registry &trace_sources,
|
||||
char const *args,
|
||||
Affinity const &affinity,
|
||||
size_t quota)
|
||||
size_t const quota)
|
||||
:
|
||||
_session_ep(session_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 */
|
||||
_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 */
|
||||
char buf[Session_label::size()];
|
||||
@ -375,7 +414,7 @@ void Cpu_session_component::_deinit_ref_account()
|
||||
if (!_ref) { return; }
|
||||
|
||||
/* 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 */
|
||||
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) {
|
||||
PWRN("Insufficient CPU quota for transfer: %s", _label.string());
|
||||
PWRN(" avail %zu", _avail());
|
||||
PWRN(" needed %zu", q);
|
||||
}
|
||||
return -3;
|
||||
thread->platform_thread()->quota(_weight_to_quota(thread->weight()));
|
||||
}
|
||||
|
||||
|
||||
void Cpu_session_component::_insuff_for_consume(size_t const q)
|
||||
void Cpu_session_component::_incr_weight(size_t const weight)
|
||||
{
|
||||
if (verbose) {
|
||||
PWRN("Insufficient CPU quota for consumption: %s", _label.string());
|
||||
PWRN(" avail %zu", _avail());
|
||||
PWRN(" needed %zu", q);
|
||||
}
|
||||
throw Quota_exceeded();
|
||||
_weight += weight;
|
||||
if (_quota) { _update_each_thread_quota(); }
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
|
||||
/****************************
|
||||
|
@ -53,7 +53,7 @@ namespace Genode {
|
||||
|
||||
private:
|
||||
|
||||
size_t const _quota;
|
||||
size_t const _weight;
|
||||
Thread_name const _name;
|
||||
Platform_thread _platform_thread;
|
||||
bool _bound; /* pd binding flag */
|
||||
@ -63,14 +63,27 @@ namespace Genode {
|
||||
|
||||
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,
|
||||
unsigned priority, addr_t utcb,
|
||||
Signal_context_capability sigh,
|
||||
unsigned trace_control_index,
|
||||
Trace::Control &trace_control)
|
||||
:
|
||||
_quota(quota), _name(name),
|
||||
_weight(weight), _name(name),
|
||||
_platform_thread(quota, name.string(), priority, utcb),
|
||||
_bound(false), _sigh(sigh),
|
||||
_trace_control_index(trace_control_index),
|
||||
@ -88,7 +101,7 @@ namespace Genode {
|
||||
bool bound() const { return _bound; }
|
||||
void bound(bool b) { _bound = b; }
|
||||
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)
|
||||
{
|
||||
@ -138,9 +151,9 @@ namespace Genode {
|
||||
* Members for quota accounting
|
||||
*/
|
||||
|
||||
Cpu_session_component * _ref;
|
||||
size_t _used;
|
||||
size_t _weight;
|
||||
size_t _quota;
|
||||
Cpu_session_component * _ref;
|
||||
List<Cpu_session_component> _ref_members;
|
||||
Lock _ref_members_lock;
|
||||
|
||||
@ -148,32 +161,22 @@ namespace Genode {
|
||||
* 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 {
|
||||
return (q * _quota) >> Cpu_session::QUOTA_LIMIT_LOG2; }
|
||||
void _decr_weight(size_t const weight);
|
||||
|
||||
size_t _global_to_local(size_t const q) const {
|
||||
if (!_quota) { return 0; }
|
||||
return (q << Cpu_session::QUOTA_LIMIT_LOG2) / _quota; }
|
||||
size_t _weight_to_quota(size_t const weight) const;
|
||||
|
||||
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)
|
||||
{
|
||||
_quota -= q;
|
||||
_ref->_used -= q;
|
||||
return 0;
|
||||
}
|
||||
void _update_thread_quota(Cpu_thread_component *) const;
|
||||
|
||||
int _transfer_forth(Cpu_session_component * const s, size_t const q)
|
||||
{
|
||||
s->_quota += q;
|
||||
_used += q;
|
||||
return 0;
|
||||
}
|
||||
void _update_each_thread_quota();
|
||||
|
||||
void _transfer_quota(Cpu_session_component * const dst,
|
||||
size_t const quota);
|
||||
|
||||
void _insert_ref_member(Cpu_session_component * const s)
|
||||
{
|
||||
@ -261,9 +264,8 @@ namespace Genode {
|
||||
Dataspace_capability trace_buffer(Thread_capability);
|
||||
Dataspace_capability trace_policy(Thread_capability);
|
||||
int ref_account(Cpu_session_capability c);
|
||||
int transfer_quota(Cpu_session_capability c, size_t q);
|
||||
size_t used();
|
||||
size_t quota();
|
||||
int transfer_quota(Cpu_session_capability, size_t);
|
||||
Quota quota() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -263,14 +263,13 @@ int main()
|
||||
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 */
|
||||
constexpr size_t cpu_quota = Cpu_session::QUOTA_LIMIT;
|
||||
static Cpu_session_component
|
||||
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_connection init_cpu("init");
|
||||
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;
|
||||
|
||||
|
@ -38,10 +38,12 @@ extern "C" {
|
||||
void *(*_start_routine) (void *);
|
||||
void *_arg;
|
||||
|
||||
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
pthread(pthread_attr_t attr, void *(*start_routine) (void *),
|
||||
void *arg, size_t stack_size, char const * name,
|
||||
Genode::Cpu_session * cpu)
|
||||
: Thread_base(0, name, stack_size, Type::NORMAL, cpu),
|
||||
: Thread_base(WEIGHT, name, stack_size, Type::NORMAL, cpu),
|
||||
_attr(attr),
|
||||
_start_routine(start_routine),
|
||||
_arg(arg)
|
||||
|
@ -42,6 +42,12 @@ namespace Init {
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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
|
||||
*/
|
||||
@ -395,21 +394,12 @@ class Init::Child : Genode::Child_policy
|
||||
|
||||
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,
|
||||
Genode::size_t & ram_quota,
|
||||
Genode::size_t & cpu_quota,
|
||||
Genode::size_t & cpu_quota_pc,
|
||||
bool & constrain_phys)
|
||||
{
|
||||
Genode::Number_of_bytes ram_bytes = 0;
|
||||
Genode::size_t cpu_percent = 0;
|
||||
|
||||
try {
|
||||
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);
|
||||
constrain_phys = rsc.attribute("constrain_phys").has_value("yes");
|
||||
} else if (rsc.attribute("name").has_value("CPU")) {
|
||||
rsc.attribute("quantum").value(&cpu_percent); }
|
||||
rsc.attribute("quantum").value(&cpu_quota_pc); }
|
||||
} catch (...) { }
|
||||
}
|
||||
} catch (...) { }
|
||||
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
|
||||
@ -435,13 +424,7 @@ class Init::Child : Genode::Child_policy
|
||||
Genode::size_t const ram_avail = avail_slack_ram_quota();
|
||||
if (ram_quota > ram_avail) {
|
||||
ram_quota = ram_avail;
|
||||
warn_unsuff_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);
|
||||
warn_insuff_quota(ram_avail);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -455,17 +438,19 @@ class Init::Child : Genode::Child_policy
|
||||
long priority;
|
||||
Genode::Affinity affinity;
|
||||
Genode::size_t ram_quota;
|
||||
Genode::size_t cpu_quota;
|
||||
Genode::size_t cpu_quota_pc;
|
||||
bool constrain_phys;
|
||||
Genode::Ram_connection ram;
|
||||
Genode::Cpu_connection cpu;
|
||||
Genode::Rm_connection rm;
|
||||
|
||||
inline void transfer_cpu_quota();
|
||||
|
||||
Resources(Genode::Xml_node start_node, const char *label,
|
||||
long prio_levels_log2,
|
||||
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),
|
||||
priority(read_priority(start_node)),
|
||||
affinity(affinity_space,
|
||||
@ -487,8 +472,7 @@ class Init::Child : Genode::Child_policy
|
||||
ram.ref_account(Genode::env()->ram_session_cap());
|
||||
Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota);
|
||||
|
||||
cpu.ref_account(Genode::env()->cpu_session_cap());
|
||||
Genode::env()->cpu_session()->transfer_quota(cpu.cap(), cpu_quota);
|
||||
transfer_cpu_quota();
|
||||
}
|
||||
} _resources;
|
||||
|
||||
@ -801,4 +785,24 @@ class Init::Child : Genode::Child_policy
|
||||
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_ */
|
||||
|
@ -41,6 +41,8 @@ class Genode::Irq_activation : Thread_base
|
||||
{
|
||||
private:
|
||||
|
||||
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
int _number;
|
||||
Irq_connection _connection;
|
||||
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)
|
||||
:
|
||||
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),
|
||||
_dispatcher(_sig_rec, *this, &Irq_activation::_handle)
|
||||
{
|
||||
|
244
repos/os/run/cpu_quota.run
Normal file
244
repos/os/run/cpu_quota.run
Normal 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"
|
@ -35,6 +35,8 @@ namespace L4lx {
|
||||
{
|
||||
private:
|
||||
|
||||
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
Genode::Lock _lock;
|
||||
L4_CV void (*_func)(void *data);
|
||||
unsigned long _data;
|
||||
@ -50,7 +52,7 @@ namespace L4lx {
|
||||
Genode::size_t stack_size,
|
||||
Genode::addr_t vcpu_state,
|
||||
unsigned cpu_nr)
|
||||
: Genode::Thread_base(0, str, stack_size),
|
||||
: Genode::Thread_base(WEIGHT, str, stack_size),
|
||||
_lock(Genode::Cancelable_lock::LOCKED),
|
||||
_func(func),
|
||||
_data(data ? *data : 0),
|
||||
|
@ -31,6 +31,8 @@ class Vmm::Vcpu_dispatcher : public T
|
||||
{
|
||||
private:
|
||||
|
||||
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
Cap_connection &_cap;
|
||||
|
||||
/**
|
||||
@ -61,7 +63,7 @@ class Vmm::Vcpu_dispatcher : public T
|
||||
Cpu_session * cpu_session,
|
||||
Genode::Affinity::Location location)
|
||||
:
|
||||
T(0, "vCPU dispatcher", stack_size),
|
||||
T(WEIGHT, "vCPU dispatcher", stack_size),
|
||||
_cap(cap)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
@ -62,8 +62,10 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
|
||||
{
|
||||
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 */
|
||||
_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
|
||||
{
|
||||
enum { WEIGHT = Genode::Cpu_session::DEFAULT_WEIGHT };
|
||||
|
||||
public:
|
||||
|
||||
Vcpu_same_pd(size_t stack_size, Cpu_session * cpu_session,
|
||||
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 */
|
||||
Genode::cap_map()->remove(tid().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2);
|
||||
|
@ -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 =
|
||||
_parent_cpu_session.create_thread(0, name.string(), utcb);
|
||||
_parent_cpu_session.create_thread(weight, name.string(), utcb);
|
||||
|
||||
if (thread_cap.valid()) {
|
||||
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::transfer_quota(Cpu_session_capability, size_t) { return -1; }
|
||||
|
||||
Cpu_session::Quota Cpu_session_component::quota() { return Quota(); }
|
||||
|
@ -78,8 +78,7 @@ class Cpu_session_component : public Rpc_object<Cpu_session>
|
||||
Dataspace_capability trace_policy(Thread_capability);
|
||||
int ref_account(Cpu_session_capability c);
|
||||
int transfer_quota(Cpu_session_capability c, size_t q);
|
||||
size_t used();
|
||||
size_t quota();
|
||||
Quota quota() override;
|
||||
};
|
||||
|
||||
#endif /* _CPU_SESSION_COMPONENT_H_ */
|
||||
|
@ -71,7 +71,7 @@ namespace Noux {
|
||||
** 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)
|
||||
{
|
||||
/*
|
||||
@ -83,7 +83,7 @@ namespace Noux {
|
||||
while (1);
|
||||
return Thread_capability();
|
||||
}
|
||||
_main_thread = _cpu.create_thread(0, name, utcb);
|
||||
_main_thread = _cpu.create_thread(weight, name, utcb);
|
||||
|
||||
return _main_thread;
|
||||
}
|
||||
@ -147,10 +147,13 @@ namespace Noux {
|
||||
Dataspace_capability trace_policy(Thread_capability thread) {
|
||||
return _cpu.trace_policy(thread); }
|
||||
|
||||
size_t quota() { return 0; }
|
||||
size_t used() { return 0; }
|
||||
int ref_account(Cpu_session_capability) { return -1; }
|
||||
int transfer_quota(Cpu_session_capability, size_t) { return -1; }
|
||||
Quota quota() override { return _cpu.quota(); }
|
||||
|
||||
int ref_account(Cpu_session_capability c) override {
|
||||
return _cpu.ref_account(c); }
|
||||
|
||||
int transfer_quota(Cpu_session_capability c, size_t q) override {
|
||||
return _cpu.transfer_quota(c, q); }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -50,3 +50,4 @@ vbox_auto_win8
|
||||
tz_vmm
|
||||
vmm
|
||||
bomb
|
||||
cpu_quota
|
||||
|
Loading…
x
Reference in New Issue
Block a user