From 33a64f79dc6c7010d7dc50cc3d5c38a09487ba46 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 23 Apr 2021 11:45:35 +0200 Subject: [PATCH] libc: place pthreads round-robin if the number of threads started exceed configured placement configuration Issue #3967 --- repos/libports/src/lib/libc/internal/init.h | 3 +- repos/libports/src/lib/libc/kernel.cc | 2 +- repos/libports/src/lib/libc/pthread_create.cc | 127 +++++++++++++----- 3 files changed, 93 insertions(+), 39 deletions(-) diff --git a/repos/libports/src/lib/libc/internal/init.h b/repos/libports/src/lib/libc/internal/init.h index 4c36e43ce3..eaf0ffbcd3 100644 --- a/repos/libports/src/lib/libc/internal/init.h +++ b/repos/libports/src/lib/libc/internal/init.h @@ -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 diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc index 50fa93bac1..ff5db0bed8 100644 --- a/repos/libports/src/lib/libc/kernel.cc +++ b/repos/libports/src/lib/libc/kernel.cc @@ -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); diff --git a/repos/libports/src/lib/libc/pthread_create.cc b/repos/libports/src/lib/libc/pthread_create.cc index afd0270653..aa442a113a 100644 --- a/repos/libports/src/lib/libc/pthread_create.cc +++ b/repos/libports/src/lib/libc/pthread_create.cc @@ -29,56 +29,111 @@ #include -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 > _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 (_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,