mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 18:06:50 +00:00
base: unify mp_server and affinity test
* remove outdated cpufreq test for Arndale * execute new SMP test on hardware not in Qemu in nightly tests Ref #3041
This commit is contained in:
parent
19d7a488de
commit
36fe50ebad
@ -1,59 +0,0 @@
|
|||||||
#
|
|
||||||
# \brief Test to affinity subspacing
|
|
||||||
# \author Norman Feske
|
|
||||||
#
|
|
||||||
|
|
||||||
if {[have_spec pbxa9] || (![have_spec nova] && ![have_spec foc])} {
|
|
||||||
puts "Platform is unsupported."
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
build "core ld.lib.so init test/affinity"
|
|
||||||
|
|
||||||
create_boot_directory
|
|
||||||
|
|
||||||
install_config {
|
|
||||||
<config>
|
|
||||||
<parent-provides>
|
|
||||||
<service name="LOG"/>
|
|
||||||
<service name="CPU"/>
|
|
||||||
<service name="RM"/>
|
|
||||||
<service name="ROM"/>
|
|
||||||
<service name="PD"/>
|
|
||||||
</parent-provides>
|
|
||||||
<affinity-space width="2" />
|
|
||||||
<default-route>
|
|
||||||
<any-service> <parent/> </any-service>
|
|
||||||
</default-route>
|
|
||||||
<start name="init">
|
|
||||||
<resource name="RAM" quantum="10M"/>
|
|
||||||
<!-- assign the right half of the available CPUs -->
|
|
||||||
<affinity xpos="1" width="1" />
|
|
||||||
<config>
|
|
||||||
<parent-provides>
|
|
||||||
<service name="LOG"/>
|
|
||||||
<service name="CPU"/>
|
|
||||||
<service name="RM"/>
|
|
||||||
</parent-provides>
|
|
||||||
<default-route>
|
|
||||||
<any-service> <parent/> </any-service>
|
|
||||||
</default-route>
|
|
||||||
<!-- assign the leftmost half of CPUs to test-affinity -->
|
|
||||||
<affinity-space width="2" />
|
|
||||||
<start name="test-affinity">
|
|
||||||
<resource name="RAM" quantum="2M"/>
|
|
||||||
<affinity xpos="0" width="1" />
|
|
||||||
</start>
|
|
||||||
</config>
|
|
||||||
</start>
|
|
||||||
</config>
|
|
||||||
}
|
|
||||||
|
|
||||||
append qemu_args " -nographic -smp 8,cores=8 "
|
|
||||||
|
|
||||||
build_boot_image "core init test-affinity"
|
|
||||||
|
|
||||||
run_genode_until {.*Detected 2x1 CPUs.*} 60
|
|
||||||
|
|
||||||
puts "Test succeeded"
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
|||||||
#
|
#
|
||||||
# \brief Test to start and call RPC entrypoint on all available CPUs
|
# \brief Test to start and call RPC entrypoint on all available CPUs
|
||||||
|
# \author Stefan Kalkowski
|
||||||
# \author Norman Feske
|
# \author Norman Feske
|
||||||
# \author Alexander Boettcher
|
# \author Alexander Boettcher
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
build "core init test/mp_server"
|
build "core init test/smp"
|
||||||
|
|
||||||
create_boot_directory
|
create_boot_directory
|
||||||
|
|
||||||
@ -21,15 +22,17 @@ install_config {
|
|||||||
<any-service> <parent/> </any-service>
|
<any-service> <parent/> </any-service>
|
||||||
</default-route>
|
</default-route>
|
||||||
<default caps="100"/>
|
<default caps="100"/>
|
||||||
<start name="test-server-mp">
|
<start name="test-smp">
|
||||||
<resource name="RAM" quantum="10M"/>
|
<resource name="RAM" quantum="10M"/>
|
||||||
</start>
|
</start>
|
||||||
</config>
|
</config>
|
||||||
}
|
}
|
||||||
|
|
||||||
build_boot_image "core ld.lib.so init test-server-mp"
|
build_boot_image "core ld.lib.so init test-smp"
|
||||||
|
|
||||||
if {[have_include "power_on/qemu"]} {
|
if {[have_include "power_on/qemu"]} {
|
||||||
|
if {[get_cmd_switch --autopilot]} { exit 0 }
|
||||||
|
|
||||||
# in general we want to have at least 2 CPUs
|
# in general we want to have at least 2 CPUs
|
||||||
set want_cpus 2
|
set want_cpus 2
|
||||||
|
|
||||||
@ -46,7 +49,7 @@ if {[have_include "power_on/qemu"]} {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# run the test
|
# run the test
|
||||||
run_genode_until {\[init -\> test-server-mp\] done.*\n} 60
|
run_genode_until {\[init -\> test-smp\] --- SMP testsuite finished.*\n} 120
|
||||||
|
|
||||||
set cpus [regexp -inline {Detected [0-9x]+ CPU[s\.]} $output]
|
set cpus [regexp -inline {Detected [0-9x]+ CPU[s\.]} $output]
|
||||||
set cpus [regexp -all -inline {[0-9]+} $cpus]
|
set cpus [regexp -all -inline {[0-9]+} $cpus]
|
||||||
@ -59,48 +62,49 @@ if {[have_include "power_on/qemu"]} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# pay only attention to the output of init and its children
|
set original_output $output
|
||||||
grep_output {^\[init }
|
grep_output {\[init -\> test-smp\] RPC:}
|
||||||
|
|
||||||
# remove upgrade messages from init
|
|
||||||
unify_output {\[init \-\> test\-server\-mp\] upgrading quota donation for .* \([0-9]+ bytes\)} ""
|
|
||||||
trim_lines
|
|
||||||
|
|
||||||
unify_output {transfer cap [a-f0-9]+} "transfer cap UNIFIED"
|
unify_output {transfer cap [a-f0-9]+} "transfer cap UNIFIED"
|
||||||
unify_output {yes - idx [a-f0-9]+} "yes - idx UNIFIED"
|
unify_output {yes - idx [a-f0-9]+} "yes - idx UNIFIED"
|
||||||
unify_output {\- received cap [a-f0-9]+} "- received cap UNIFIED"
|
unify_output {\- received cap [a-f0-9]+} "- received cap UNIFIED"
|
||||||
|
|
||||||
set good_string {
|
set good_string {[init -> test-smp] RPC: --- test started ---
|
||||||
[init -> test-server-mp] --- test-mp_server started ---
|
}
|
||||||
[init -> test-server-mp] Detected }
|
|
||||||
append good_string "$cpus"
|
|
||||||
append good_string "x1 CPU"
|
|
||||||
if {$cpus > 1} { append good_string "s" }
|
|
||||||
append good_string ".\n"
|
|
||||||
|
|
||||||
for {set r 0} {$r < $cpus} {incr r} {
|
for {set r 0} {$r < $cpus} {incr r} {
|
||||||
append good_string {[init -> test-server-mp] call server on CPU }
|
append good_string {[init -> test-smp] RPC: call server on CPU }
|
||||||
append good_string "$r\n"
|
append good_string "$r\n"
|
||||||
append good_string {[init -> test-server-mp] function test_untyped: got value }
|
append good_string {[init -> test-smp] RPC: function test_untyped: got value }
|
||||||
append good_string "$r\n"
|
append good_string "$r\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
for {set r 0} {$r < $cpus} {incr r} {
|
for {set r 0} {$r < $cpus} {incr r} {
|
||||||
append good_string {[init -> test-server-mp] call server on CPU }
|
append good_string {[init -> test-smp] RPC: call server on CPU }
|
||||||
append good_string "$r - transfer cap UNIFIED\n"
|
append good_string "$r - transfer cap UNIFIED\n"
|
||||||
append good_string {[init -> test-server-mp] function test_cap: capability is valid ? yes - idx UNIFIED}
|
append good_string {[init -> test-smp] RPC: function test_cap: capability is valid ? yes - idx UNIFIED}
|
||||||
append good_string "\n"
|
append good_string "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
for {set r 0} {$r < $cpus} {incr r} {
|
for {set r 0} {$r < $cpus} {incr r} {
|
||||||
append good_string {[init -> test-server-mp] call server on CPU }
|
append good_string {[init -> test-smp] RPC: call server on CPU }
|
||||||
append good_string "$r - transfer cap UNIFIED\n"
|
append good_string "$r - transfer cap UNIFIED\n"
|
||||||
append good_string {[init -> test-server-mp] function test_cap_reply: capability is valid ? yes - idx UNIFIED}
|
append good_string {[init -> test-smp] RPC: function test_cap_reply: capability is valid ? yes - idx UNIFIED}
|
||||||
append good_string "\n"
|
append good_string "\n"
|
||||||
append good_string {[init -> test-server-mp] got from server on CPU }
|
append good_string {[init -> test-smp] RPC: got from server on CPU }
|
||||||
append good_string "$r - received cap UNIFIED\n"
|
append good_string "$r - received cap UNIFIED\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
append good_string {[init -> test-server-mp] done}
|
|
||||||
|
|
||||||
compare_output_to $good_string
|
compare_output_to $good_string
|
||||||
|
puts "RPC test: passed"
|
||||||
|
|
||||||
|
set output $original_output
|
||||||
|
grep_output {\[init -\> test-smp\] Affinity: Round}
|
||||||
|
set rounds "10"
|
||||||
|
set good_string {}
|
||||||
|
for {set r 0} {$r <= $rounds} {incr r} {
|
||||||
|
append good_string {[init -> test-smp] Affinity: Round }
|
||||||
|
append good_string [format "%02d" $r]
|
||||||
|
append good_string ":"
|
||||||
|
for {set i 0} {$i < $cpus} {incr i} {
|
||||||
|
append good_string " A"
|
||||||
|
}
|
||||||
|
append good_string "\n"
|
||||||
|
}
|
||||||
|
compare_output_to $good_string
|
||||||
|
puts "Affinity test: passed"
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Test for setting the CPU affinity of a thread
|
|
||||||
* \author Norman Feske
|
|
||||||
* \date 2013-03-21
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/log.h>
|
|
||||||
#include <base/thread.h>
|
|
||||||
#include <base/component.h>
|
|
||||||
#include <base/heap.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Genode {
|
|
||||||
|
|
||||||
static inline void print(Output &out, Affinity::Location location)
|
|
||||||
{
|
|
||||||
print(out, location.xpos(), ",", location.ypos());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum { STACK_SIZE = sizeof(long)*1024, COUNT_VALUE = 10 * 1024 * 1024 };
|
|
||||||
|
|
||||||
struct Spinning_thread : Genode::Thread
|
|
||||||
{
|
|
||||||
Genode::Affinity::Location const _location;
|
|
||||||
|
|
||||||
Genode::uint64_t volatile cnt;
|
|
||||||
|
|
||||||
Genode::Lock barrier;
|
|
||||||
|
|
||||||
void entry()
|
|
||||||
{
|
|
||||||
barrier.unlock();
|
|
||||||
|
|
||||||
Genode::log("thread started on CPU ", _location, " spinning...");
|
|
||||||
|
|
||||||
unsigned round = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
cnt++;
|
|
||||||
|
|
||||||
/* show a life sign every now and then... */
|
|
||||||
if (cnt % COUNT_VALUE == 0) {
|
|
||||||
Genode::log("thread on CPU ", _location, " keeps counting - "
|
|
||||||
"round ", round++, "...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spinning_thread(Genode::Env &env, Location location)
|
|
||||||
:
|
|
||||||
Genode::Thread(env, Name("spinning_thread"), STACK_SIZE, location,
|
|
||||||
Weight(), env.cpu()),
|
|
||||||
_location(location), cnt(0ULL), barrier(Genode::Lock::LOCKED)
|
|
||||||
{
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Main
|
|
||||||
{
|
|
||||||
Genode::Env &env;
|
|
||||||
|
|
||||||
Genode::Heap heap { env.ram(), env.rm() };
|
|
||||||
|
|
||||||
Main(Genode::Env &env);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Main::Main(Genode::Env &env) : env(env)
|
|
||||||
{
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
log("--- test-affinity started ---");
|
|
||||||
|
|
||||||
Affinity::Space cpus = env.cpu().affinity_space();
|
|
||||||
log("Detected ", cpus.width(), "x", cpus.height(), " "
|
|
||||||
"CPU", cpus.total() > 1 ? "s." : ".");
|
|
||||||
|
|
||||||
/* get some memory for the thread objects */
|
|
||||||
Spinning_thread ** threads = new (heap) Spinning_thread*[cpus.total()];
|
|
||||||
uint64_t * thread_cnt = new (heap) uint64_t[cpus.total()];
|
|
||||||
|
|
||||||
/* construct the thread objects */
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++)
|
|
||||||
threads[i] = new (heap)
|
|
||||||
Spinning_thread(env, cpus.location_of_index(i));
|
|
||||||
|
|
||||||
/* wait until all threads are up and running */
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++)
|
|
||||||
threads[i]->barrier.lock();
|
|
||||||
|
|
||||||
log("Threads started on a different CPU each.");
|
|
||||||
log("You may inspect them using the kernel debugger - if you have one.");
|
|
||||||
log("Main thread monitors client threads and prints the status of them.");
|
|
||||||
log("Legend : D - DEAD, A - ALIVE");
|
|
||||||
|
|
||||||
volatile uint64_t cnt = 0;
|
|
||||||
unsigned round = 0;
|
|
||||||
|
|
||||||
char const text_cpu[] = " CPU: ";
|
|
||||||
char const text_round[] = "Round %2u: ";
|
|
||||||
char * output_buffer = new (heap) char [sizeof(text_cpu) + 3 * cpus.total()];
|
|
||||||
|
|
||||||
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.total(); i++) {
|
|
||||||
snprintf(output, 4, "%2u ", i);
|
|
||||||
output += 3;
|
|
||||||
}
|
|
||||||
log(Cstring(output_buffer));
|
|
||||||
|
|
||||||
output = output_buffer;
|
|
||||||
snprintf(output, sizeof(text_round), text_round, round);
|
|
||||||
output += sizeof(text_round) - 2;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++) {
|
|
||||||
snprintf(output, 4, "%s ",
|
|
||||||
thread_cnt[i] == threads[i]->cnt ? " D" : " A");
|
|
||||||
output += 3;
|
|
||||||
thread_cnt[i] = threads[i]->cnt;
|
|
||||||
}
|
|
||||||
log(Cstring(output_buffer));
|
|
||||||
|
|
||||||
round ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Component::construct(Genode::Env &env) { static Main inst(env); }
|
|
@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Multiprocessor test for a server having multiple Rpc_entrypoints on
|
|
||||||
* different CPUs
|
|
||||||
* \author Alexander Boettcher
|
|
||||||
* \date 2013-07-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/component.h>
|
|
||||||
#include <base/heap.h>
|
|
||||||
#include <base/log.h>
|
|
||||||
#include <base/rpc_server.h>
|
|
||||||
#include <base/rpc_client.h>
|
|
||||||
|
|
||||||
namespace Test {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test session interface definition
|
|
||||||
*/
|
|
||||||
struct Session : Genode::Session
|
|
||||||
{
|
|
||||||
static const char *service_name() { return "MP_RPC_TEST"; }
|
|
||||||
|
|
||||||
enum { CAP_QUOTA = 2 };
|
|
||||||
|
|
||||||
GENODE_RPC(Rpc_test_untyped, void, test_untyped, unsigned);
|
|
||||||
GENODE_RPC(Rpc_test_cap, void, test_cap, Genode::Native_capability);
|
|
||||||
GENODE_RPC(Rpc_test_cap_reply, Genode::Native_capability,
|
|
||||||
test_cap_reply, Genode::Native_capability);
|
|
||||||
GENODE_RPC_INTERFACE(Rpc_test_untyped, Rpc_test_cap, Rpc_test_cap_reply);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Client : Genode::Rpc_client<Session>
|
|
||||||
{
|
|
||||||
Client(Genode::Capability<Session> cap) : Rpc_client<Session>(cap) { }
|
|
||||||
|
|
||||||
void test_untyped(unsigned value) { call<Rpc_test_untyped>(value); }
|
|
||||||
void test_cap(Genode::Native_capability cap) { call<Rpc_test_cap>(cap); }
|
|
||||||
Genode::Native_capability test_cap_reply(Genode::Native_capability cap) {
|
|
||||||
return call<Rpc_test_cap_reply>(cap); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Component : Genode::Rpc_object<Session, Component>
|
|
||||||
{
|
|
||||||
/* Test to just sent plain words (untyped items) */
|
|
||||||
void test_untyped(unsigned);
|
|
||||||
/* Test to transfer a object capability during send */
|
|
||||||
void test_cap(Genode::Native_capability);
|
|
||||||
/* Test to transfer a object capability during send+reply */
|
|
||||||
Genode::Native_capability test_cap_reply(Genode::Native_capability);
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Genode::Capability<Session> Capability;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Session implementation
|
|
||||||
*/
|
|
||||||
void Component::test_untyped(unsigned value) {
|
|
||||||
Genode::log("function ", __FUNCTION__, ": got value ", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Component::test_cap(Genode::Native_capability cap) {
|
|
||||||
Genode::log("function ", __FUNCTION__, ": capability is valid ? ",
|
|
||||||
cap.valid() ? "yes" : "no", " - idx ", cap.local_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
Genode::Native_capability Component::test_cap_reply(Genode::Native_capability cap) {
|
|
||||||
Genode::log("function ", __FUNCTION__, ": capability is valid ? ",
|
|
||||||
cap.valid() ? "yes" : "no", " - idx ", cap.local_name());
|
|
||||||
return cap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up a server running on every CPU one Rpc_entrypoint
|
|
||||||
*/
|
|
||||||
void Component::construct(Genode::Env & env)
|
|
||||||
{
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
Heap heap(env.ram(), env.rm());
|
|
||||||
|
|
||||||
log("--- test-mp_server started ---");
|
|
||||||
|
|
||||||
Affinity::Space cpus = env.cpu().affinity_space();
|
|
||||||
log("Detected ", cpus.width(), "x", cpus.height(), " CPU",
|
|
||||||
cpus.total() > 1 ? "s." : ".");
|
|
||||||
|
|
||||||
enum { STACK_SIZE = 2*1024*sizeof(long) };
|
|
||||||
|
|
||||||
Rpc_entrypoint ** eps = new (heap) Rpc_entrypoint*[cpus.total()];
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++)
|
|
||||||
eps[i] = new (heap) Rpc_entrypoint(&env.pd(), STACK_SIZE, "rpc en",
|
|
||||||
true, cpus.location_of_index(i));
|
|
||||||
|
|
||||||
/* XXX using the same object and putting it to different queues fails XXX */
|
|
||||||
Test::Component * components = new (heap) Test::Component[cpus.total()];
|
|
||||||
|
|
||||||
Test::Capability * caps = new (heap) Test::Capability[cpus.total()];
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++)
|
|
||||||
caps[i] = eps[i]->manage(&components[i]);
|
|
||||||
|
|
||||||
Test::Client ** clients = new (heap) Test::Client*[cpus.total()];
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++)
|
|
||||||
clients[i] = new (heap) Test::Client(caps[i]);
|
|
||||||
|
|
||||||
/* Test: Invoke RPC entrypoint on different CPUs */
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++) {
|
|
||||||
log("call server on CPU ", i);
|
|
||||||
clients[i]->test_untyped(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test: Transfer a capability to RPC Entrypoints on different CPUs */
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++) {
|
|
||||||
Native_capability cap = caps[0];
|
|
||||||
log("call server on CPU ", i, " - transfer cap ", cap.local_name());
|
|
||||||
clients[i]->test_cap(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test: Transfer a capability to RPC Entrypoints and back */
|
|
||||||
for (unsigned i = 0; i < cpus.total(); i++) {
|
|
||||||
Native_capability cap = caps[0];
|
|
||||||
log("call server on CPU ", i, " - transfer cap ", cap.local_name());
|
|
||||||
Native_capability rcap = clients[i]->test_cap_reply(cap);
|
|
||||||
log("got from server on CPU ", i, " - received cap ", rcap.local_name());
|
|
||||||
}
|
|
||||||
|
|
||||||
log("done");
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
TARGET = test-server-mp
|
|
||||||
SRC_CC = main.cc
|
|
||||||
LIBS = base
|
|
262
repos/base/src/test/smp/main.cc
Normal file
262
repos/base/src/test/smp/main.cc
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
* \brief Multiprocessor testsuite
|
||||||
|
* \author Alexander Boettcher
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2013-07-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013-2017 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/heap.h>
|
||||||
|
#include <base/log.h>
|
||||||
|
#include <base/rpc_server.h>
|
||||||
|
#include <base/rpc_client.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
static inline void print(Output &out, Affinity::Location location)
|
||||||
|
{
|
||||||
|
print(out, location.xpos(), ",", location.ypos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up a server running on every CPU one Rpc_entrypoint
|
||||||
|
*/
|
||||||
|
namespace Mp_server_test {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test session interface definition
|
||||||
|
*/
|
||||||
|
struct Session : Genode::Session
|
||||||
|
{
|
||||||
|
static const char *service_name() { return "MP_RPC_TEST"; }
|
||||||
|
|
||||||
|
enum { CAP_QUOTA = 2 };
|
||||||
|
|
||||||
|
GENODE_RPC(Rpc_test_untyped, void, test_untyped, unsigned);
|
||||||
|
GENODE_RPC(Rpc_test_cap, void, test_cap, Genode::Native_capability);
|
||||||
|
GENODE_RPC(Rpc_test_cap_reply, Genode::Native_capability,
|
||||||
|
test_cap_reply, Genode::Native_capability);
|
||||||
|
GENODE_RPC_INTERFACE(Rpc_test_untyped, Rpc_test_cap, Rpc_test_cap_reply);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Client : Genode::Rpc_client<Session>
|
||||||
|
{
|
||||||
|
Client(Genode::Capability<Session> cap) : Rpc_client<Session>(cap) { }
|
||||||
|
|
||||||
|
void test_untyped(unsigned value) { call<Rpc_test_untyped>(value); }
|
||||||
|
void test_cap(Genode::Native_capability cap) { call<Rpc_test_cap>(cap); }
|
||||||
|
Genode::Native_capability test_cap_reply(Genode::Native_capability cap) {
|
||||||
|
return call<Rpc_test_cap_reply>(cap); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Component : Genode::Rpc_object<Session, Component>
|
||||||
|
{
|
||||||
|
/* Test to just sent plain words (untyped items) */
|
||||||
|
void test_untyped(unsigned);
|
||||||
|
/* Test to transfer a object capability during send */
|
||||||
|
void test_cap(Genode::Native_capability);
|
||||||
|
/* Test to transfer a object capability during send+reply */
|
||||||
|
Genode::Native_capability test_cap_reply(Genode::Native_capability);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Genode::Capability<Session> Capability;
|
||||||
|
|
||||||
|
struct Cpu_compound
|
||||||
|
{
|
||||||
|
enum { STACK_SIZE = 2*1024*sizeof(long) };
|
||||||
|
|
||||||
|
Genode::Rpc_entrypoint rpc;
|
||||||
|
Component comp { };
|
||||||
|
Capability cap { rpc.manage(&comp) };
|
||||||
|
Client cli { cap };
|
||||||
|
|
||||||
|
Cpu_compound(Genode::Affinity::Location l, Genode::Env &env)
|
||||||
|
: rpc(&env.pd(), STACK_SIZE, "rpc en", true, l) {}
|
||||||
|
~Cpu_compound() { rpc.dissolve(&comp); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session implementation
|
||||||
|
*/
|
||||||
|
void Component::test_untyped(unsigned value) {
|
||||||
|
Genode::log("RPC: function ", __FUNCTION__, ": got value ", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Component::test_cap(Genode::Native_capability cap) {
|
||||||
|
Genode::log("RPC: function ", __FUNCTION__, ": capability is valid ? ",
|
||||||
|
cap.valid() ? "yes" : "no", " - idx ", cap.local_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Native_capability Component::test_cap_reply(Genode::Native_capability cap) {
|
||||||
|
Genode::log("RPC: function ", __FUNCTION__, ": capability is valid ? ",
|
||||||
|
cap.valid() ? "yes" : "no", " - idx ", cap.local_name());
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void execute(Genode::Env & env, Genode::Heap & heap,
|
||||||
|
Genode::Affinity::Space & cpus)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
log("RPC: --- test started ---");
|
||||||
|
|
||||||
|
Cpu_compound ** compounds = new (heap) Cpu_compound*[cpus.total()];
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++)
|
||||||
|
compounds[i] = new (heap) Cpu_compound(cpus.location_of_index(i), env);
|
||||||
|
|
||||||
|
/* Invoke RPC entrypoint on different CPUs */
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++) {
|
||||||
|
log("RPC: call server on CPU ", i);
|
||||||
|
compounds[i]->cli.test_untyped(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer a capability to RPC Entrypoints on different CPUs */
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++) {
|
||||||
|
Native_capability cap = compounds[0]->cap;
|
||||||
|
log("RPC: call server on CPU ", i, " - transfer cap ", cap.local_name());
|
||||||
|
compounds[i]->cli.test_cap(cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer a capability to RPC Entrypoints and back */
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++) {
|
||||||
|
Native_capability cap = compounds[0]->cap;
|
||||||
|
log("RPC: call server on CPU ", i, " - transfer cap ", cap.local_name());
|
||||||
|
Native_capability rcap = compounds[i]->cli.test_cap_reply(cap);
|
||||||
|
log("RPC: got from server on CPU ", i, " - received cap ", rcap.local_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++)
|
||||||
|
destroy(heap, compounds[i]);
|
||||||
|
destroy(heap, compounds);
|
||||||
|
|
||||||
|
log("RPC: --- test finished ---");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Affinity_test {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STACK_SIZE = sizeof(long)*2048,
|
||||||
|
COUNT_VALUE = 10 * 1024 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Spinning_thread : Genode::Thread
|
||||||
|
{
|
||||||
|
Genode::Affinity::Location const location;
|
||||||
|
Genode::uint64_t volatile cnt;
|
||||||
|
Genode::Lock barrier;
|
||||||
|
|
||||||
|
void entry()
|
||||||
|
{
|
||||||
|
barrier.unlock();
|
||||||
|
Genode::log("Affinity: thread started on CPU ",
|
||||||
|
location, " spinning...");
|
||||||
|
|
||||||
|
for (;;) cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spinning_thread(Genode::Env &env, Location location)
|
||||||
|
: Genode::Thread(env, Name("spinning_thread"), STACK_SIZE, location,
|
||||||
|
Weight(), env.cpu()),
|
||||||
|
location(location), cnt(0ULL), barrier(Genode::Lock::LOCKED) {
|
||||||
|
start(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void execute(Genode::Env &env, Genode::Heap & heap,
|
||||||
|
Genode::Affinity::Space & cpus)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
log("Affinity: --- test started ---");
|
||||||
|
|
||||||
|
/* get some memory for the thread objects */
|
||||||
|
Spinning_thread ** threads = new (heap) Spinning_thread*[cpus.total()];
|
||||||
|
uint64_t * thread_cnt = new (heap) uint64_t[cpus.total()];
|
||||||
|
|
||||||
|
/* construct the thread objects */
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++)
|
||||||
|
threads[i] = new (heap)
|
||||||
|
Spinning_thread(env, cpus.location_of_index(i));
|
||||||
|
|
||||||
|
/* wait until all threads are up and running */
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++)
|
||||||
|
threads[i]->barrier.lock();
|
||||||
|
|
||||||
|
log("Affinity: Threads started on a different CPU each.");
|
||||||
|
log("Affinity: You may inspect them using the kernel debugger - if you have one.");
|
||||||
|
log("Affinity: Main thread monitors client threads and prints the status of them.");
|
||||||
|
log("Affinity: Legend : D - DEAD, A - ALIVE");
|
||||||
|
|
||||||
|
volatile uint64_t cnt = 0;
|
||||||
|
unsigned round = 0;
|
||||||
|
|
||||||
|
char const text_cpu[] = "Affinity: CPU: ";
|
||||||
|
char const text_round[] = "Affinity: Round %2u: ";
|
||||||
|
char * output_buffer = new (heap) char [sizeof(text_cpu) + 3 * cpus.total()];
|
||||||
|
|
||||||
|
for (; round < 11;) {
|
||||||
|
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.total(); i++) {
|
||||||
|
snprintf(output, 4, "%2u ", i);
|
||||||
|
output += 3;
|
||||||
|
}
|
||||||
|
log(Cstring(output_buffer));
|
||||||
|
|
||||||
|
output = output_buffer;
|
||||||
|
snprintf(output, sizeof(text_round), text_round, round);
|
||||||
|
output += sizeof(text_round) - 2;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++) {
|
||||||
|
snprintf(output, 4, "%s ",
|
||||||
|
thread_cnt[i] == threads[i]->cnt ? " D" : " A");
|
||||||
|
output += 3;
|
||||||
|
thread_cnt[i] = threads[i]->cnt;
|
||||||
|
}
|
||||||
|
log(Cstring(output_buffer));
|
||||||
|
|
||||||
|
round ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < cpus.total(); i++)
|
||||||
|
destroy(heap, threads[i]);
|
||||||
|
destroy(heap, threads);
|
||||||
|
destroy(heap, thread_cnt);
|
||||||
|
log("Affinity: --- test finished ---");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Component::construct(Genode::Env & env)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
log("--- SMP testsuite started ---");
|
||||||
|
|
||||||
|
Affinity::Space cpus = env.cpu().affinity_space();
|
||||||
|
log("Detected ", cpus.width(), "x", cpus.height(), " CPU",
|
||||||
|
cpus.total() > 1 ? "s." : ".");
|
||||||
|
|
||||||
|
Heap heap(env.ram(), env.rm());
|
||||||
|
|
||||||
|
Mp_server_test::execute(env, heap, cpus);
|
||||||
|
Affinity_test::execute(env, heap, cpus);
|
||||||
|
|
||||||
|
log("--- SMP testsuite finished ---");
|
||||||
|
}
|
@ -1,3 +1,3 @@
|
|||||||
TARGET = test-affinity
|
TARGET = test-smp
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = base
|
LIBS = base
|
@ -1,82 +0,0 @@
|
|||||||
assert_spec foc
|
|
||||||
assert_spec arndale
|
|
||||||
|
|
||||||
#
|
|
||||||
# Build
|
|
||||||
#
|
|
||||||
|
|
||||||
# generic components
|
|
||||||
set build_components {
|
|
||||||
core
|
|
||||||
init
|
|
||||||
drivers/platform
|
|
||||||
drivers/timer
|
|
||||||
test/affinity
|
|
||||||
test/cpufreq
|
|
||||||
}
|
|
||||||
|
|
||||||
build $build_components
|
|
||||||
create_boot_directory
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Config
|
|
||||||
#
|
|
||||||
|
|
||||||
set config {
|
|
||||||
<config>
|
|
||||||
<parent-provides>
|
|
||||||
<service name="ROM"/>
|
|
||||||
<service name="IRQ"/>
|
|
||||||
<service name="IO_MEM"/>
|
|
||||||
<service name="PD"/>
|
|
||||||
<service name="RM"/>
|
|
||||||
<service name="CPU"/>
|
|
||||||
<service name="LOG"/>
|
|
||||||
</parent-provides>
|
|
||||||
<default-route>
|
|
||||||
<any-service> <any-child/> <parent/> </any-service>
|
|
||||||
</default-route>
|
|
||||||
|
|
||||||
<start name="platform_drv">
|
|
||||||
<resource name="RAM" quantum="1M"/>
|
|
||||||
<provides><service name="Regulator"/></provides>
|
|
||||||
</start>
|
|
||||||
<start name="timer">
|
|
||||||
<resource name="RAM" quantum="1M"/>
|
|
||||||
<provides><service name="Timer"/></provides>
|
|
||||||
</start>
|
|
||||||
<start name="test-affinity">
|
|
||||||
<resource name="RAM" quantum="10M"/>
|
|
||||||
</start>
|
|
||||||
<start name="test-cpufreq">
|
|
||||||
<resource name="RAM" quantum="10M"/>
|
|
||||||
</start>
|
|
||||||
</config>
|
|
||||||
}
|
|
||||||
|
|
||||||
install_config $config
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Boot modules
|
|
||||||
#
|
|
||||||
|
|
||||||
# generic modules
|
|
||||||
set boot_modules {
|
|
||||||
core ld.lib.so init
|
|
||||||
platform_drv
|
|
||||||
timer
|
|
||||||
test-affinity
|
|
||||||
test-cpufreq
|
|
||||||
}
|
|
||||||
|
|
||||||
build_boot_image $boot_modules
|
|
||||||
run_genode_until {.*Round 04: A A.*\n.*Setting CPU frequency low.*\n.*Setting CPU frequency high.*\n.*Round 05: A A} 60
|
|
||||||
|
|
||||||
grep_output {^\[init -> test-cpufreq\] }
|
|
||||||
|
|
||||||
compare_output_to {
|
|
||||||
[init -> test-cpufreq] Setting CPU frequency low
|
|
||||||
[init -> test-cpufreq] Setting CPU frequency high
|
|
||||||
}
|
|
@ -66,7 +66,7 @@ proc precise_ref_time { } {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
build "core init drivers/platform drivers/timer test/timeout test/cpufreq"
|
build "core init drivers/platform drivers/timer test/timeout"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Boot image
|
# Boot image
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Test for changing the CPU frequency
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \author Martin Stein
|
|
||||||
* \date 2013-06-14
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2013-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/component.h>
|
|
||||||
#include <regulator/consts.h>
|
|
||||||
#include <regulator_session/connection.h>
|
|
||||||
#include <timer_session/connection.h>
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
struct Main
|
|
||||||
{
|
|
||||||
enum { PERIOD_US = 8 * 1000 * 1000 };
|
|
||||||
|
|
||||||
Env &env;
|
|
||||||
Timer::Connection timer { env };
|
|
||||||
Regulator::Connection cpu_regulator { env, Regulator::CLK_CPU };
|
|
||||||
Signal_handler<Main> timer_handler { env.ep(), *this, &Main::handle_timer };
|
|
||||||
bool high { true };
|
|
||||||
|
|
||||||
void handle_timer()
|
|
||||||
{
|
|
||||||
log("Setting CPU frequency ", high ? "low" : "high");
|
|
||||||
cpu_regulator.level(high ? Regulator::CPU_FREQ_200 :
|
|
||||||
Regulator::CPU_FREQ_1600);
|
|
||||||
high = !high;
|
|
||||||
timer.trigger_once(PERIOD_US);
|
|
||||||
}
|
|
||||||
|
|
||||||
Main(Env &env) : env(env)
|
|
||||||
{
|
|
||||||
timer.sigh(timer_handler);
|
|
||||||
timer.trigger_once(PERIOD_US);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void Component::construct(Env &env) { static Main main(env); }
|
|
@ -1,4 +0,0 @@
|
|||||||
TARGET = test-cpufreq
|
|
||||||
REQUIRES = arndale
|
|
||||||
SRC_CC = main.cc
|
|
||||||
LIBS = base
|
|
@ -1,4 +1,3 @@
|
|||||||
affinity
|
|
||||||
bomb
|
bomb
|
||||||
cpu_quota
|
cpu_quota
|
||||||
cpu_sampler
|
cpu_sampler
|
||||||
@ -22,7 +21,6 @@ lx_hybrid_ctors
|
|||||||
lx_hybrid_exception
|
lx_hybrid_exception
|
||||||
lx_hybrid_pthread_ipc
|
lx_hybrid_pthread_ipc
|
||||||
moon
|
moon
|
||||||
mp_server
|
|
||||||
netperf_lwip
|
netperf_lwip
|
||||||
netperf_lwip_bridge
|
netperf_lwip_bridge
|
||||||
netperf_lwip_router
|
netperf_lwip_router
|
||||||
@ -48,6 +46,7 @@ rump_ext2
|
|||||||
sd_card_bench
|
sd_card_bench
|
||||||
seoul-auto
|
seoul-auto
|
||||||
smartcard
|
smartcard
|
||||||
|
smp
|
||||||
solo5
|
solo5
|
||||||
sub_rm
|
sub_rm
|
||||||
tar_rom
|
tar_rom
|
||||||
|
Loading…
x
Reference in New Issue
Block a user