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 #1464devel
parent
955977b516
commit
c9272937e7
@ -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"
|
||||
}
|
@ -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_ */
|
@ -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_ */
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* \brief Provide sync signals for cross-component synchronization
|
||||
* \author Martin Stein
|
||||
* \date 2015-04-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/server.h>
|
||||
#include <root/component.h>
|
||||
|
||||
/* local includes */
|
||||
#include <sync_session/connection.h>
|
||||
|
||||
namespace Sync
|
||||
{
|
||||
enum { NR_OF_SIGNALS = 1 };
|
||||
|
||||
using Server::Entrypoint;
|
||||
using Genode::Rpc_object;
|
||||
using Genode::env;
|
||||
using Genode::Root_component;
|
||||
using Genode::Allocator;
|
||||
using Genode::Signal_transmitter;
|
||||
|
||||
class Signal;
|
||||
class Session_component;
|
||||
class Root;
|
||||
struct Main;
|
||||
}
|
||||
|
||||
class Sync::Signal
|
||||
{
|
||||
friend class Root;
|
||||
|
||||
private:
|
||||
|
||||
enum { NR_OF_TRANSMITTERS = 9 };
|
||||
|
||||
Signal_transmitter _transmitters[NR_OF_TRANSMITTERS];
|
||||
unsigned _submitted;
|
||||
unsigned _threshold;
|
||||
|
||||
void _check()
|
||||
{
|
||||
if (_submitted < _threshold) { return; }
|
||||
for (unsigned i = 0; i < _submitted; i++) {
|
||||
_transmitters[i].submit(); }
|
||||
_submitted = 0;
|
||||
}
|
||||
|
||||
void _reset()
|
||||
{
|
||||
_submitted = 0;
|
||||
_threshold = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void threshold(unsigned const threshold)
|
||||
{
|
||||
_threshold = threshold;
|
||||
_check();
|
||||
}
|
||||
|
||||
void submit(Signal_context_capability & sigc)
|
||||
{
|
||||
_transmitters[_submitted] = Signal_transmitter(sigc);
|
||||
_submitted++;
|
||||
_check();
|
||||
}
|
||||
};
|
||||
|
||||
class Sync::Session_component : public Rpc_object<Session>
|
||||
{
|
||||
private:
|
||||
|
||||
Signal * const _signals;
|
||||
|
||||
public:
|
||||
|
||||
Session_component(Signal * const signals) : _signals(signals) { }
|
||||
|
||||
void threshold(unsigned id, unsigned threshold) override
|
||||
{
|
||||
if (id >= NR_OF_SIGNALS) { return; }
|
||||
_signals[id].threshold(threshold);
|
||||
}
|
||||
|
||||
void
|
||||
submit(unsigned const id, Signal_context_capability sigc) override
|
||||
{
|
||||
if (id >= NR_OF_SIGNALS) { return; }
|
||||
_signals[id].submit(sigc);
|
||||
}
|
||||
};
|
||||
|
||||
class Sync::Root : public Root_component<Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Signal _signals[NR_OF_SIGNALS];
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
try { return new (md_alloc()) Session_component(_signals); }
|
||||
catch (...) { throw Root::Exception(); }
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Entrypoint & ep, Allocator & md_alloc)
|
||||
: Root_component<Session_component>(&ep.rpc_ep(), &md_alloc)
|
||||
{
|
||||
for (unsigned i = 0; i < NR_OF_SIGNALS; i++) {
|
||||
_signals[i]._reset(); }
|
||||
}
|
||||
};
|
||||
|
||||
struct Sync::Main
|
||||
{
|
||||
Server::Entrypoint & ep;
|
||||
|
||||
Root root;
|
||||
|
||||
Main(Server::Entrypoint & ep) : ep(ep), root(ep, *env()->heap()) {
|
||||
env()->parent()->announce(ep.manage(root)); }
|
||||
};
|
||||
|
||||
|
||||
/************
|
||||
** Server **
|
||||
************/
|
||||
|
||||
namespace Server
|
||||
{
|
||||
using namespace Sync;
|
||||
|
||||
char const *name() { return "sync_ep"; }
|
||||
|
||||
size_t stack_size() { return 2 * 1024 * sizeof(long); }
|
||||
|
||||
void construct(Entrypoint & ep) { static Main main(ep); }
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#
|
||||
# \brief Provide cross-component synchronization
|
||||
# \author Martin Stein
|
||||
# \date 2014-10-13
|
||||
#
|
||||
|
||||
# Set program name
|
||||
TARGET = test-sync
|
||||
|
||||
# Add C++ sources
|
||||
SRC_CC = main.cc
|
||||
|
||||
# Add include paths
|
||||
INC_DIR += $(PRG_DIR)/../include
|
||||
|
||||
# Add libraries
|
||||
LIBS = base server
|