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