diff --git a/repos/os/src/app/cpu_burner/main.cc b/repos/os/src/app/cpu_burner/main.cc index 19f4036cab..c0e52891a2 100644 --- a/repos/os/src/app/cpu_burner/main.cc +++ b/repos/os/src/app/cpu_burner/main.cc @@ -13,57 +13,112 @@ /* Genode includes */ #include +#include #include #include using namespace Genode; +struct Cpu_burn : Thread +{ + List_element _list_element { this }; + Env &_env; + Blockade _block { }; + bool volatile _stop { false }; + + Cpu_burn(Genode::Env &env, Location const &location) + : + Genode::Thread(env, Name("burn_", location.xpos(), "x", location.ypos()), + 4 * 4096, location, Weight(), env.cpu()), + _env(env) + { } + + void entry() override + { + while (true) { + _block.block(); + + while (!_stop) { } + + _stop = false; + } + } +}; + +typedef List > Thread_list; + struct Cpu_burner { - Genode::Env &_env; + Genode::Env &_env; + Genode::Heap _heap { _env.ram(), _env.rm() }; + Timer::Connection _timer { _env }; + Thread_list _threads { }; - Timer::Connection _timer { _env }; - - unsigned long _percent = 100; + uint64_t _start_ms { 0 }; + unsigned short _percent { 100 }; + bool _burning { false }; Genode::Attached_rom_dataspace _config { _env, "config" }; void _handle_config() { _config.update(); + + if (!_config.valid()) + return; + _percent = _config.xml().attribute_value("percent", 100L); + if (_percent > 100) + _percent = 100; } Genode::Signal_handler _config_handler { _env.ep(), *this, &Cpu_burner::_handle_config }; - unsigned _burn_per_iteration = 10; - void _handle_period() { - uint64_t const start_ms = _timer.elapsed_ms(); + uint64_t next_timer_ms = 1000; + bool stop_burner = false; + bool start_burner = false; - unsigned iterations = 0; - for (;; iterations++) { + if (_burning) { + uint64_t const curr_ms = _timer.elapsed_ms(); + uint64_t const passed_ms = curr_ms - _start_ms; - uint64_t const curr_ms = _timer.elapsed_ms(); - uint64_t passed_ms = curr_ms - start_ms; + if (_percent < 100) { + stop_burner = (passed_ms >= 10*_percent); + if (stop_burner) + next_timer_ms = (100 - _percent) * 10; + else + next_timer_ms = 10*_percent - passed_ms; + } + } else + start_burner = true; - if (passed_ms >= 10*_percent) - break; + if (stop_burner) { + for (auto t = _threads.first(); t; t = t->next()) { + auto thread = t->object(); + if (!thread) + continue; - /* burn some time */ - for (unsigned volatile i = 0; i < _burn_per_iteration; i++) - for (unsigned volatile j = 0; j < 1000*1000; j++) - (void) (i*j); + thread->_stop = true; + } + _burning = false; } - /* adjust busy loop duration */ - if (iterations > 10) - _burn_per_iteration *= 2; + if (start_burner) { + for (auto t = _threads.first(); t; t = t->next()) { + auto thread = t->object(); + if (!thread) + continue; - if (iterations < 5) - _burn_per_iteration /= 2; + thread->_block.wakeup(); + } + _burning = true; + _start_ms = _timer.elapsed_ms(); + } + + _timer.trigger_once(next_timer_ms*1000); } Genode::Signal_handler _period_handler { @@ -75,7 +130,17 @@ struct Cpu_burner _handle_config(); _timer.sigh(_period_handler); - _timer.trigger_periodic(1000*1000); + _timer.trigger_once(1000*1000); + + Affinity::Space space = env.cpu().affinity_space(); + + for (unsigned i = 0; i < space.total(); i++) { + Affinity::Location location = env.cpu().affinity_space().location_of_index(i); + Cpu_burn *t = new (_heap) Cpu_burn(env, location); + t->start(); + + _threads.insert(&t->_list_element); + } } };