mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-19 23:53:55 +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:
committed by
Christian Helmuth
parent
19d7a488de
commit
36fe50ebad
@ -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
|
||||
LIBS = base
|
Reference in New Issue
Block a user