libc: place pthreads round-robin

if the number of threads started exceed configured placement configuration

Issue #3967
This commit is contained in:
Alexander Boettcher 2021-04-23 11:45:35 +02:00 committed by Norman Feske
parent 7de62734e5
commit 33a64f79dc
3 changed files with 93 additions and 39 deletions

View File

@ -113,7 +113,8 @@ namespace Libc {
* Pthread/semaphore support
*/
void init_pthread_support(Monitor &, Timer_accessor &);
void init_pthread_support(Genode::Cpu_session &, Xml_node);
void init_pthread_support(Genode::Cpu_session &, Xml_node const &,
Genode::Allocator &);
void init_semaphore_support(Timer_accessor &);
struct Config_accessor : Interface

View File

@ -461,7 +461,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap)
init_semaphore_support(_timer_accessor);
init_pthread_support(*this, _timer_accessor);
init_pthread_support(env.cpu(), _pthread_config());
init_pthread_support(env.cpu(), _pthread_config(), _heap);
_env.ep().register_io_progress_handler(*this);

View File

@ -29,56 +29,111 @@
#include <internal/pthread.h>
static Genode::Cpu_session * _cpu_session { nullptr };
static unsigned _id_cpu_map[32];
static bool _verbose { false };
using namespace Genode;
void Libc::init_pthread_support(Genode::Cpu_session &cpu_session,
Genode::Xml_node node)
struct Placement_policy
{
struct Placement : Interface
{
unsigned pthread_id;
unsigned cpu;
Placement (unsigned id, unsigned cpu)
: pthread_id(id), cpu(cpu) { }
};
Registry<Registered<Placement> > _policies { };
enum class Policy { ALL, SINGLE, MANUAL };
Policy _policy { Policy::ALL };
void policy(String<32> const &policy_name)
{
if (policy_name == "single-cpu")
_policy = Policy::SINGLE;
if (policy_name == "manual")
_policy = Policy::MANUAL;
if (policy_name == "all-cpus")
_policy = Policy::ALL;
}
unsigned placement(unsigned const pthread_id) const
{
switch (_policy) {
case Policy::SINGLE:
return 0U;
case Policy::MANUAL: {
unsigned cpu = 0U;
bool found = false;
_policies.for_each([&](auto const &policy) {
if (policy.pthread_id == pthread_id) {
cpu = policy.cpu;
found = true;
}
});
/* if no entry is found, Policy::ALL is applied */
return found ? cpu : pthread_id;
}
case Policy::ALL:
default:
return pthread_id;
}
}
void add_placement(Genode::Allocator &alloc, unsigned pthread, unsigned cpu)
{
new (alloc) Registered<Placement> (_policies, pthread, cpu);
}
};
static Cpu_session *_cpu_session { nullptr };
static bool _verbose { false };
Placement_policy &placement_policy()
{
static Placement_policy policy { };
return policy;
}
void Libc::init_pthread_support(Cpu_session &cpu_session,
Xml_node const &node,
Genode::Allocator &alloc)
{
_cpu_session = &cpu_session;
_verbose = node.attribute_value("verbose", false);
String<32> placement("all-cpus");
placement = node.attribute_value("placement", placement);
String<32> const policy_name = node.attribute_value("placement",
String<32>("all-cpus"));
placement_policy().policy(policy_name);
if (placement == "single-cpu") {
return;
}
node.for_each_sub_node("thread", [&](Xml_node &policy) {
if (placement == "manual") {
node.for_each_sub_node("thread", [](Xml_node &node) {
if (node.has_attribute("id") && node.has_attribute("cpu")) {
unsigned const id = node.attribute_value("id", 0U);
unsigned const cpu = node.attribute_value("cpu", 0U);
if (policy.has_attribute("id") && policy.has_attribute("cpu")) {
unsigned const id = policy.attribute_value("id", 0U);
unsigned const cpu = policy.attribute_value("cpu", 0U);
if (id < sizeof(_id_cpu_map) / sizeof(_id_cpu_map[0])) {
_id_cpu_map[id] = cpu;
if (_verbose)
Genode::log("pthread.", id, " -> cpu ", cpu);
} else {
Genode::warning("pthread configuration ignored - "
"id=", id, " cpu=", cpu);
}
}
});
return;
}
if (_verbose)
log("pthread.", id, " -> cpu ", cpu);
/* all-cpus and unknown case */
for (unsigned i = 0; i < sizeof(_id_cpu_map) / sizeof(_id_cpu_map[0]); i++)
_id_cpu_map[i] = i;
placement_policy().add_placement(alloc, id, cpu);
}
});
}
static unsigned pthread_id()
{
static Genode::Mutex mutex;
static Mutex mutex;
static unsigned id = 0;
Genode::Mutex::Guard guard(mutex);
Mutex::Guard guard(mutex);
return id++;
}
@ -132,17 +187,15 @@ int Libc::pthread_create(pthread_t *thread, const pthread_attr_t *attr,
? (*attr)->stack_size
: Libc::Component::stack_size();
using Genode::Affinity;
unsigned const id { pthread_id() };
unsigned const cpu = (id < sizeof(_id_cpu_map) / sizeof(_id_cpu_map[0])) ? _id_cpu_map[id] : 0;
unsigned const cpu = placement_policy().placement(id);
Genode::String<32> const pthread_name { "pthread.", id };
String<32> const pthread_name { "pthread.", id };
Affinity::Space space { _cpu_session->affinity_space() };
Affinity::Location location { space.location_of_index(cpu) };
if (_verbose)
Genode::log("create ", pthread_name, " -> cpu ", cpu);
log("create ", pthread_name, " -> cpu ", cpu);
int result =
Libc::pthread_create_from_session(thread, start_routine, arg,