mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
thread API & CPU session: accounting of CPU quota
In the init configuration one can configure the donation of CPU time via 'resource' tags that have the attribute 'name' set to "CPU" and the attribute 'quantum' set to the percentage of CPU quota that init shall donate. The pattern is the same as when donating RAM quota. ! <start name="test"> ! <resource name="CPU" quantum="75"/> ! </start> This would cause init to try donating 75% of its CPU quota to the child "test". Init and core do not preserve CPU quota for their own requirements by default as it is done with RAM quota. The CPU quota that a process owns can be applied through the thread constructor. The constructor has been enhanced by an argument that indicates the percentage of the programs CPU quota that shall be granted to the new thread. So 'Thread(33, "test")' would cause the backing CPU session to try to grant 33% of the programs CPU quota to the thread "test". By now, the CPU quota of a thread can't be altered after construction. Constructing a thread with CPU quota 0 doesn't mean the thread gets never scheduled but that the thread has no guaranty to receive CPU time. Such threads have to live with excess CPU time. Threads that already existed in the official repositories of Genode were adapted in the way that they receive a quota of 0. This commit also provides a run test 'cpu_quota' in base-hw (the only kernel that applies the CPU-quota scheme currently). The test basically runs three threads with different physical CPU quota. The threads simply count for 30 seconds each and the test then checks wether the counter values relate to the CPU-quota distribution. fix #1275
This commit is contained in:
committed by
Christian Helmuth
parent
f60e2af21f
commit
8f9355b360
@@ -136,7 +136,7 @@ namespace Genode {
|
||||
public:
|
||||
|
||||
Pager_activation_base(const char *name, size_t stack_size) :
|
||||
Thread_base(name, stack_size),
|
||||
Thread_base(0, name, stack_size),
|
||||
_cap(Native_capability()), _ep(0), _cap_valid(Lock::LOCKED) { }
|
||||
|
||||
/**
|
||||
|
||||
@@ -326,15 +326,17 @@ namespace Genode {
|
||||
/**
|
||||
* Hook for platform-specific constructor supplements
|
||||
*
|
||||
* \param main_thread whether this is the main thread
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param type enables selection of special initialization
|
||||
*/
|
||||
void _init_platform_thread(Type type);
|
||||
void _init_platform_thread(size_t quota, Type type);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name for debugging
|
||||
* \param stack_size stack size
|
||||
* \param type enables selection of special construction
|
||||
@@ -354,12 +356,13 @@ namespace Genode {
|
||||
* at least set Context::ds_cap in a way that it references
|
||||
* the dataspace of the already attached stack.
|
||||
*/
|
||||
Thread_base(const char *name, size_t stack_size,
|
||||
Thread_base(size_t quota, const char *name, size_t stack_size,
|
||||
Type type = NORMAL);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name for debugging
|
||||
* \param stack_size stack size
|
||||
* \param type enables selection of special construction
|
||||
@@ -369,8 +372,8 @@ namespace Genode {
|
||||
* \throw Stack_alloc_failed
|
||||
* \throw Context_alloc_failed
|
||||
*/
|
||||
Thread_base(const char *name, size_t stack_size, Type type,
|
||||
Cpu_session *);
|
||||
Thread_base(size_t quota, const char *name, size_t stack_size,
|
||||
Type type, Cpu_session *);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
@@ -513,20 +516,36 @@ namespace Genode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param name thread name (for debugging)
|
||||
* \param type enables selection of special construction
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name (for debugging)
|
||||
* \param type enables selection of special construction
|
||||
*/
|
||||
explicit Thread(const char *name, Type type = NORMAL)
|
||||
: Thread_base(name, STACK_SIZE, type) { }
|
||||
explicit Thread(size_t quota, const char *name, Type type = NORMAL)
|
||||
: Thread_base(quota, name, STACK_SIZE, type) { }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name thread name (for debugging)
|
||||
* \param cpu_session thread created via specific cpu session
|
||||
*/
|
||||
explicit Thread(size_t quota, const char *name, Cpu_session * cpu_session)
|
||||
: Thread_base(quota, name, STACK_SIZE, Type::NORMAL, cpu_session)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Shortcut for 'Thread(0, name, type)'
|
||||
*/
|
||||
explicit Thread(const char *name, Type type = NORMAL)
|
||||
: Thread_base(0, name, STACK_SIZE, type) { }
|
||||
|
||||
/**
|
||||
* Shortcut for 'Thread(0, name, cpu_session)'
|
||||
*/
|
||||
explicit Thread(const char *name, Cpu_session * cpu_session)
|
||||
: Thread_base(name, STACK_SIZE, Type::NORMAL, cpu_session) { }
|
||||
: Thread_base(0, name, STACK_SIZE, Type::NORMAL, cpu_session)
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
#define _INCLUDE__CPU_SESSION__CAPABILITY_H_
|
||||
|
||||
#include <base/capability.h>
|
||||
#include <cpu_session/cpu_session.h>
|
||||
|
||||
namespace Genode { typedef Capability<Cpu_session> Cpu_session_capability; }
|
||||
namespace Genode
|
||||
{
|
||||
class Cpu_session;
|
||||
typedef Capability<Cpu_session> Cpu_session_capability;
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__CPU_SESSION__CAPABILITY_H_ */
|
||||
|
||||
@@ -24,8 +24,9 @@ namespace Genode {
|
||||
explicit Cpu_session_client(Cpu_session_capability session)
|
||||
: Rpc_client<Cpu_session>(session) { }
|
||||
|
||||
Thread_capability create_thread(Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(name, utcb); }
|
||||
Thread_capability
|
||||
create_thread(size_t quota, Name const &name, addr_t utcb = 0) {
|
||||
return call<Rpc_create_thread>(quota, name, utcb); }
|
||||
|
||||
Ram_dataspace_capability utcb(Thread_capability thread) {
|
||||
return call<Rpc_utcb>(thread); }
|
||||
@@ -77,6 +78,16 @@ namespace Genode {
|
||||
|
||||
Dataspace_capability trace_policy(Thread_capability thread) {
|
||||
return call<Rpc_trace_policy>(thread); }
|
||||
|
||||
int ref_account(Cpu_session_capability session) {
|
||||
return call<Rpc_ref_account>(session); }
|
||||
|
||||
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>(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_
|
||||
#define _INCLUDE__CPU_SESSION__CPU_SESSION_H_
|
||||
|
||||
#include <cpu_session/capability.h>
|
||||
#include <base/stdint.h>
|
||||
#include <base/exception.h>
|
||||
#include <base/thread_state.h>
|
||||
@@ -50,12 +51,15 @@ namespace Genode {
|
||||
|
||||
class Thread_creation_failed : public Exception { };
|
||||
class State_access_failed : public Exception { };
|
||||
class Quota_exceeded : public Thread_creation_failed { };
|
||||
class Out_of_metadata : public Exception { };
|
||||
|
||||
static const char *service_name() { return "CPU"; }
|
||||
|
||||
enum { THREAD_NAME_LEN = 48 };
|
||||
enum { PRIORITY_LIMIT = 1 << 16 };
|
||||
enum { QUOTA_LIMIT_LOG2 = 15 };
|
||||
enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 };
|
||||
enum { DEFAULT_PRIORITY = 0 };
|
||||
|
||||
typedef Rpc_in_buffer<THREAD_NAME_LEN> Name;
|
||||
@@ -65,13 +69,16 @@ namespace Genode {
|
||||
/**
|
||||
* Create a new thread
|
||||
*
|
||||
* \param name name for the thread
|
||||
* \param utcb Base of the UTCB that will be used by the thread
|
||||
* \return capability representing the new thread
|
||||
* \throw Thread_creation_failed
|
||||
* \throw Out_of_metadata
|
||||
* \param quota CPU quota that shall be granted to the thread
|
||||
* \param name name for the thread
|
||||
* \param utcb Base of the UTCB that will be used by the thread
|
||||
* \return capability representing the new thread
|
||||
* \throw Thread_creation_failed
|
||||
* \throw Out_of_metadata
|
||||
* \throw Quota_exceeded
|
||||
*/
|
||||
virtual Thread_capability create_thread(Name const &name,
|
||||
virtual Thread_capability create_thread(size_t quota,
|
||||
Name const &name,
|
||||
addr_t utcb = 0) = 0;
|
||||
|
||||
/**
|
||||
@@ -254,6 +261,56 @@ namespace Genode {
|
||||
*/
|
||||
virtual Dataspace_capability trace_policy(Thread_capability thread) = 0;
|
||||
|
||||
/**
|
||||
* Define reference account for the CPU session
|
||||
*
|
||||
* \param cpu_session reference account
|
||||
*
|
||||
* \return 0 on success
|
||||
*
|
||||
* Each CPU session requires another CPU session as reference
|
||||
* account to transfer quota to and from. The reference account can
|
||||
* be defined only once.
|
||||
*/
|
||||
virtual int ref_account(Cpu_session_capability cpu_session) = 0;
|
||||
|
||||
/**
|
||||
* Transfer quota to another CPU session
|
||||
*
|
||||
* \param cpu_session receiver of quota donation
|
||||
* \param amount amount of quota to donate
|
||||
* \return 0 on success
|
||||
*
|
||||
* Quota can only be transfered if the specified CPU session is
|
||||
* either the reference account for this session or vice versa.
|
||||
*/
|
||||
virtual int transfer_quota(Cpu_session_capability cpu_session,
|
||||
size_t amount) = 0;
|
||||
|
||||
/**
|
||||
* Return current quota limit
|
||||
*/
|
||||
virtual size_t quota() = 0;
|
||||
|
||||
/**
|
||||
* Return amount of used quota
|
||||
*/
|
||||
virtual size_t used() = 0;
|
||||
|
||||
/**
|
||||
* Return amount of available quota
|
||||
*/
|
||||
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; }
|
||||
|
||||
/*********************
|
||||
** RPC declaration **
|
||||
@@ -261,7 +318,7 @@ namespace Genode {
|
||||
|
||||
GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread,
|
||||
GENODE_TYPE_LIST(Thread_creation_failed, Out_of_metadata),
|
||||
Name const &, addr_t);
|
||||
size_t, Name const &, addr_t);
|
||||
GENODE_RPC(Rpc_utcb, Ram_dataspace_capability, utcb, Thread_capability);
|
||||
GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability);
|
||||
GENODE_RPC(Rpc_set_pager, int, set_pager, Thread_capability, Pager_capability);
|
||||
@@ -284,6 +341,10 @@ namespace Genode {
|
||||
GENODE_RPC(Rpc_trace_control_index, unsigned, trace_control_index, Thread_capability);
|
||||
GENODE_RPC(Rpc_trace_buffer, Dataspace_capability, trace_buffer, Thread_capability);
|
||||
GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability);
|
||||
GENODE_RPC(Rpc_ref_account, int, ref_account, Cpu_session_capability);
|
||||
GENODE_RPC(Rpc_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_INTERFACE' declaration done manually
|
||||
@@ -311,8 +372,12 @@ namespace Genode {
|
||||
Meta::Type_tuple<Rpc_trace_control_index,
|
||||
Meta::Type_tuple<Rpc_trace_buffer,
|
||||
Meta::Type_tuple<Rpc_trace_policy,
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user