diff --git a/base/run/affinity.run b/base/run/affinity.run
index 9aef1af8e..2a550a80a 100644
--- a/base/run/affinity.run
+++ b/base/run/affinity.run
@@ -1,3 +1,15 @@
+#
+# \brief Test to start threads on all available CPUs
+# \author Norman Feske
+# \author Alexander Boettcher
+#
+
+if {![have_spec nova] && ![have_spec foc]} {
+ puts "Platform is unsupported."
+ exit 0
+}
+
+
build "core init test/affinity"
create_boot_directory
@@ -20,6 +32,33 @@ install_config {
build_boot_image "core init test-affinity"
-append qemu_args " -nographic -m 64 -smp 2,cores=2 "
+if {[is_qemu_available]} {
+ set want_cpus 4
+ set rounds "05"
+ append qemu_args "-nographic -m 64 -smp $want_cpus,cores=$want_cpus "
+} else {
+ set rounds "10"
+ if {[have_spec x86]} { set rounds "40" }
+}
-run_genode_until forever
+run_genode_until "Round $rounds:.*\n" 90
+
+set cpus [regexp -inline {Detected [0-9]+ CPU[ s].*\n} $output]
+set cpus [regexp -inline {[0-9]+} $cpus]
+
+if {[is_qemu_available]} {
+ if {$want_cpus != $cpus} {
+ puts "CPU count is not as expected: $want_cpus != $cpus"
+ exit 1;
+ }
+}
+
+set good_string {[init -> test-affinity] Round XX:}
+for {set i 0} {$i < $cpus} {incr i} {
+ append good_string " A"
+}
+
+grep_output {\[init -\> test-affinity\] Round}
+unify_output {[0-9]+} "XX"
+
+compare_output_to $good_string
diff --git a/base/src/test/affinity/main.cc b/base/src/test/affinity/main.cc
index d5bbc59b2..1038c4499 100644
--- a/base/src/test/affinity/main.cc
+++ b/base/src/test/affinity/main.cc
@@ -18,35 +18,38 @@
#include
-enum { STACK_SIZE = sizeof(long)*1024 };
+enum { STACK_SIZE = sizeof(long)*1024, COUNT_VALUE = 10 * 1024 * 1024 };
+
struct Spinning_thread : Genode::Thread
{
- int const cpu_number;
+ unsigned const _cpu_number;
- unsigned long volatile cnt;
+ Genode::uint64_t volatile cnt;
Genode::Lock barrier;
void entry()
{
- PINF("thread started on CPU %d, spinning...", cpu_number);
-
barrier.unlock();
+ PINF("thread started on CPU %u, spinning...", _cpu_number);
+
+ unsigned round = 0;
+
for (;;) {
cnt++;
/* show a life sign every now and then... */
- if (cnt > 100*1024*1024) {
- PINF("thread on CPU %d keeps counting...\n", cpu_number);
- cnt = 0;
+ if (cnt % COUNT_VALUE == 0) {
+ PINF("thread on CPU %u keeps counting - round %u...\n",
+ _cpu_number, round++);
}
}
}
Spinning_thread(unsigned cpu_number, char const *name)
:
- Genode::Thread(name), cpu_number(cpu_number), cnt(0),
+ Genode::Thread(name), _cpu_number(cpu_number), cnt(0ULL),
barrier(Genode::Lock::LOCKED)
{
Genode::env()->cpu_session()->affinity(Thread_base::cap(), cpu_number);
@@ -60,15 +63,62 @@ int main(int argc, char **argv)
using namespace Genode;
printf("--- test-affinity started ---\n");
- static Spinning_thread thread_0(0, "thread_0");
- static Spinning_thread thread_1(1, "thread_1");
- /* wait until both threads are up and running */
- thread_0.barrier.lock();
- thread_1.barrier.lock();
+ unsigned cpus = env()->cpu_session()->num_cpus();
+ printf("Detected %u CPU%c.\n", cpus, cpus > 1 ? 's' : ' ');
+
+ /* get some memory for the thread objects */
+ Spinning_thread ** threads = new (env()->heap()) Spinning_thread*[cpus];
+ uint64_t * thread_cnt = new (env()->heap()) uint64_t[cpus];
+
+ /* construct the thread objects */
+ for (unsigned i = 0; i < cpus; i++)
+ threads[i] = new (env()->heap()) Spinning_thread(i, "thread");
+
+ /* wait until all threads are up and running */
+ for (unsigned i = 0; i < cpus; i++)
+ threads[i]->barrier.lock();
printf("Threads started on a different CPU each.\n");
- printf("You may inspect them using the kernel debugger\n");
+ printf("You may inspect them using the kernel debugger - if you have one.\n");
+ printf("Main thread monitors client threads and prints the status of them.\n");
+ printf("Legend : D - DEAD, A - ALIVE\n");
+ volatile uint64_t cnt = 0;
+ unsigned round = 0;
+
+ char const text_cpu[] = " CPU: ";
+ char const text_round[] = "Round %2u: ";
+ char * output_buffer = new (env()->heap()) char [sizeof(text_cpu) + 3 * cpus];
+
+ for (;;) {
+ cnt++;
+
+ /* try to get a life sign by the main thread from the remote threads */
+ if (cnt % COUNT_VALUE == 0) {
+ char * output = output_buffer;
+ snprintf(output, sizeof(text_cpu), text_cpu);
+ output += sizeof(text_cpu) - 1;
+ for (unsigned i = 0; i < cpus; i++) {
+ snprintf(output, 4, "%2u ", i);
+ output += 3;
+ }
+ printf("%s\n", output_buffer);
+
+ output = output_buffer;
+ snprintf(output, sizeof(text_round), text_round, round);
+ output += sizeof(text_round) - 2;
+
+ for (unsigned i = 0; i < cpus; i++) {
+ snprintf(output, 4, "%s ",
+ thread_cnt[i] == threads[i]->cnt ? " D" : " A");
+ output += 3;
+ thread_cnt[i] = threads[i]->cnt;
+ }
+ printf("%s\n", output_buffer);
+
+ round ++;
+ }
+ }
sleep_forever();
}
diff --git a/tool/autopilot.list b/tool/autopilot.list
index ac5463f82..b0e0b38ca 100644
--- a/tool/autopilot.list
+++ b/tool/autopilot.list
@@ -25,3 +25,4 @@ l4linux_netperf
l4linux_netperf_usb30
l4linux_netperf_bridge
noux_tool_chain_auto
+affinity