cpu_sampler component for statistical profiling

Fixes #2075
This commit is contained in:
Christian Prochaska 2016-08-24 17:23:06 +02:00 committed by Christian Helmuth
parent 901b39259c
commit dc26910fc3
21 changed files with 1331 additions and 0 deletions

View File

@ -0,0 +1,90 @@
if { ![have_spec foc] && ![have_spec hw] && ![have_spec nova] &&
![have_spec okl4] && ![have_spec sel4] } {
puts "Run script is not supported on this platform"
exit 0
}
build {
core
init
drivers/timer
server/cpu_sampler
test/cpu_sampler
}
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="CAP"/>
<service name="CPU"/>
<service name="IO_PORT"/>
<service name="IRQ"/>
<service name="LOG"/>
<service name="PD"/>
<service name="RAM"/>
<service name="ROM"/>
<service name="RM"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides>
<service name="Timer"/>
</provides>
</start>
<start name="cpu_sampler">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="CPU"/>
</provides>
<config sample_interval_ms="100" sample_duration_s="1">
<policy label="init -> test-cpu_sampler -> ep" />
</config>
</start>
<start name="init">
<resource name="RAM" quantum="2M"/>
<config>
<parent-provides>
<service name="CAP"/>
<service name="LOG"/>
<service name="RM"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <parent/> </any-service>
</default-route>
<start name="test-cpu_sampler">
<resource name="RAM" quantum="1M"/>
<config ld_verbose="yes"/>
</start>
</config>
<route>
<service name="CPU"> <child name="cpu_sampler"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>
}
build_boot_image {
core
init
timer
cpu_sampler
test-cpu_sampler
}
append qemu_args "-nographic -m 128"
set match_string "Test started. func: 0x(\[0-9a-f\]+).*\n"
run_genode_until "$match_string" 10
regexp $match_string $output all func
run_genode_until "\\\[init -> cpu_sampler -> samples -> init -> test-cpu_sampler -> ep\\\.1] \[0\]*$func" 2 [output_spawn_id]

View File

@ -0,0 +1,81 @@
This component implements a CPU service which samples the instruction pointer
of the configured threads on a regular basis for the purpose of statistical
profiling.
The collected samples are written to the LOG session with an individual label
for each thread. By using the 'fs_log' component, the sample data can be
written into separate files if desired.
Configuration options
---------------------
! <config sample_interval_ms="100" sample_duration_s="1">
! <policy label="init -> test-cpu_sampler -> ep" />
! </config>
The 'sample_interval_ms' attribute configures the time between two samples in
milliseconds.
The 'sample_duration_s' attribute configures the overall duration of the
sampling activity in seconds.
The policy configures the threads to be sampled.
The clients of the CPU sampler component must be at least grand children of the
initial init process to have their CPU sessions routed correctly. An example
configuration using a sub-init process can be found in the 'cpu_sampler.run'
script.
Evaluation
----------
Currently, some basic tools for the evaluation of the sampled addresses are
available at
[https://github.com/cproc/genode_stuff/tree/cpu_sampler-16.08]
* Filtering the sampled addresses from the Genode log output
! filter_sampled_addresses_from_log <file containing the Genode log output>
This script extracts the sampled addresses from a file containing the Genode
log output and saves them in the file 'sampled_addresses.txt'. It is not
needed when the addresses have already been written into a separate file by
the 'fs_log' component. The match string (label) in the script might need to
be adapted for the specific scenario.
* Filtering the shared library load addresses from the Genode log output
! filter_ldso_addresses_from_log <file containing the Genode log output>
This script extracts the shared library load addresses from a file containing
the Genode log output and saves them in the file 'ldso_addresses.txt'. To have
these addresses appear in the Genode log output, the sampled component should
be configured with the 'ld_verbose="yes"' XML attribute if it uses shared
libraries. If multiple components in a scenario are configured with this
attribute, the script needs to be adapted to match a specific label.
* Generating statistics
! generate_statistics <ELF image> <file with sampled addresses> [<file with ldso addresses>]
This script generates the files 'statistics_by_function.txt' and
'statistics_by_address.txt'.
The first argument is the name of the ELF image of the sampled component.
The second argument is the name of a file containing the sampled addresses.
The third argument is the name of a file containing the shared library load
addresses. It is only needed if the sampled component uses shared libraries.
The 'statistics_by_function.txt' file lists the names of the sampled
functions, sorted by the highest sample count. Each line comprehends
all sampled addresses which belong to the particular function.
The 'statistics_by_address.txt' file is more detailed than the
'statistics_by_function.txt' file. It lists the sampled addresses, sorted by
the highest sample count, together with the name and file location of the
function the particular address belongs to.
The 'generate_statistics' script uses the 'backtrace' script to determine the
function names and file locations. The best location to use the scripts is
the 'build/.../bin' directory, where all the shared libraries can be found.

View File

@ -0,0 +1,72 @@
/*
* \brief CPU root interface
* \author Christian Prochaska
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_ROOT_H_
#define _CPU_ROOT_H_
/* Genode includes */
#include <root/component.h>
/* local includes */
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
#include "thread_list_change_handler.h"
namespace Cpu_sampler {
using namespace Genode;
class Cpu_root;
}
class Cpu_sampler::Cpu_root : public Root_component<Cpu_session_component>
{
private:
Rpc_entrypoint &_thread_ep;
Allocator &_md_alloc;
Thread_list &_thread_list;
Thread_list_change_handler &_thread_list_change_handler;
protected:
Cpu_session_component *_create_session(const char *args) override
{
Cpu_session_component *cpu_session_component =
new (md_alloc()) Cpu_session_component(_thread_ep,
_md_alloc,
_thread_list,
_thread_list_change_handler,
args);
return cpu_session_component;
}
void _upgrade_session(Cpu_session_component *cpu, const char *args) override
{
env()->parent()->upgrade(cpu->parent_cpu_session(), args);
}
public:
Cpu_root(Rpc_entrypoint &session_ep,
Rpc_entrypoint &thread_ep,
Allocator &md_alloc,
Thread_list &thread_list,
Thread_list_change_handler &thread_list_change_handler)
: Root_component<Cpu_session_component>(&session_ep, &md_alloc),
_thread_ep(thread_ep),
_md_alloc(md_alloc),
_thread_list(thread_list),
_thread_list_change_handler(thread_list_change_handler) { }
};
#endif /* _CPU_ROOT_H_ */

View File

@ -0,0 +1,152 @@
/*
* \brief Implementation of the CPU session interface
* \author Christian Prochaska
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/env.h>
#include "cpu_session_component.h"
#include <util/arg_string.h>
#include <util/list.h>
using namespace Genode;
using namespace Cpu_sampler;
Thread_capability
Cpu_sampler::Cpu_session_component::create_thread(Pd_session_capability pd,
Name const &name,
Affinity::Location affinity,
Weight weight,
addr_t utcb)
{
Cpu_thread_component *cpu_thread = new (_md_alloc)
Cpu_thread_component(*this,
_md_alloc,
pd,
name,
affinity,
weight,
utcb,
name.string(),
_next_thread_id);
_thread_list.insert(new (_md_alloc) Thread_element(cpu_thread));
_thread_list_change_handler.thread_list_changed();
_next_thread_id++;
return cpu_thread->cap();
}
void Cpu_sampler::Cpu_session_component::kill_thread(Thread_capability thread_cap)
{
auto lambda = [&] (Thread_element *cpu_thread_element) {
Cpu_thread_component *cpu_thread = cpu_thread_element->object();
if (cpu_thread->cap() == thread_cap) {
_thread_list.remove(cpu_thread_element);
destroy(_md_alloc, cpu_thread_element);
destroy(_md_alloc, cpu_thread);
_thread_list_change_handler.thread_list_changed();
}
};
for_each_thread(_thread_list, lambda);
_parent_cpu_session.kill_thread(thread_cap);
}
void
Cpu_sampler::Cpu_session_component::exception_sigh(Signal_context_capability handler)
{
_parent_cpu_session.exception_sigh(handler);
}
Affinity::Space Cpu_sampler::Cpu_session_component::affinity_space() const
{
return _parent_cpu_session.affinity_space();
}
Dataspace_capability
Cpu_sampler::Cpu_session_component::trace_control()
{
return _parent_cpu_session.trace_control();
}
Cpu_sampler::Cpu_session_component::Cpu_session_component(
Rpc_entrypoint &thread_ep,
Allocator &md_alloc,
Thread_list &thread_list,
Thread_list_change_handler &thread_list_change_handler,
char const *args)
: _thread_ep(thread_ep),
_parent_cpu_session(env()->parent()->session<Cpu_session>(args)),
_md_alloc(md_alloc),
_thread_list(thread_list),
_thread_list_change_handler(thread_list_change_handler),
_session_label(label_from_args(args)),
_native_cpu_cap(_setup_native_cpu())
{ }
Cpu_sampler::Cpu_session_component::~Cpu_session_component()
{
_cleanup_native_cpu();
auto lambda = [&] (Thread_element *cpu_thread_element) {
Cpu_thread_component *cpu_thread = cpu_thread_element->object();
if (cpu_thread->cpu_session_component() == this) {
_thread_list.remove(cpu_thread_element);
destroy(_md_alloc, cpu_thread_element);
destroy(_md_alloc, cpu_thread);
}
};
for_each_thread(_thread_list, lambda);
_thread_list_change_handler.thread_list_changed();
}
int Cpu_sampler::Cpu_session_component::ref_account(Cpu_session_capability cap)
{
return _parent_cpu_session.ref_account(cap);
}
int Cpu_sampler::Cpu_session_component::transfer_quota(Cpu_session_capability cap,
size_t size)
{
return _parent_cpu_session.transfer_quota(cap, size);
}
Cpu_session::Quota Cpu_sampler::Cpu_session_component::quota()
{
return _parent_cpu_session.quota();
}
Capability<Cpu_session::Native_cpu>
Cpu_sampler::Cpu_session_component::native_cpu()
{
return _native_cpu_cap;
}

View File

@ -0,0 +1,112 @@
/*
* \brief CPU session component interface
* \author Christian Prochaska
* \date 2016-01-18
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_SESSION_COMPONENT_H_
#define _CPU_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator.h>
#include <base/rpc_server.h>
#include <cpu_session/client.h>
#include <os/session_policy.h>
/* local includes */
#include "cpu_thread_component.h"
#include "thread_list_change_handler.h"
namespace Cpu_sampler {
using namespace Genode;
class Cpu_session_component;
typedef List<List_element<Cpu_thread_component>> Thread_list;
typedef List_element<Cpu_thread_component> Thread_element;
template <typename FN>
void for_each_thread(Thread_list &thread_list, FN const &fn);
}
template <typename FN>
void Cpu_sampler::for_each_thread(Thread_list &thread_list, FN const &fn)
{
Thread_element *next_cpu_thread_element = 0;
for (Thread_element *cpu_thread_element = thread_list.first();
cpu_thread_element;
cpu_thread_element = next_cpu_thread_element) {
next_cpu_thread_element = cpu_thread_element->next();
fn(cpu_thread_element);
}
}
class Cpu_sampler::Cpu_session_component : public Rpc_object<Cpu_session>
{
private:
Rpc_entrypoint &_thread_ep;
Cpu_session_client _parent_cpu_session;
Allocator &_md_alloc;
Thread_list &_thread_list;
Thread_list_change_handler &_thread_list_change_handler;
Session_label _session_label;
unsigned int _next_thread_id = 0;
Capability<Cpu_session::Native_cpu> _native_cpu_cap;
Capability<Cpu_session::Native_cpu> _setup_native_cpu();
void _cleanup_native_cpu();
public:
Session_label &session_label() { return _session_label; }
Cpu_session_client &parent_cpu_session() { return _parent_cpu_session; }
Rpc_entrypoint &thread_ep() { return _thread_ep; }
/**
* Constructor
*/
Cpu_session_component(Rpc_entrypoint &thread_ep,
Allocator &md_alloc,
Thread_list &thread_list,
Thread_list_change_handler &thread_list_change_handler,
char const *args);
/**
* Destructor
*/
~Cpu_session_component();
/***************************
** CPU session interface **
***************************/
Thread_capability create_thread(Pd_session_capability pd,
Name const &,
Affinity::Location,
Weight,
addr_t) override;
void kill_thread(Thread_capability) override;
void exception_sigh(Signal_context_capability handler) override;
Affinity::Space affinity_space() const override;
Dataspace_capability trace_control() override;
int ref_account(Cpu_session_capability c) override;
int transfer_quota(Cpu_session_capability c, size_t q) override;
Quota quota() override;
Capability<Cpu_session::Native_cpu> native_cpu() override;
};
#endif /* _CPU_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,219 @@
/*
* \brief Cpu_thread_component implementation
* \author Christian Prochaska
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/snprintf.h>
/* local includes */
#include "cpu_session_component.h"
static constexpr bool verbose_take_sample = false;
using namespace Genode;
Cpu_sampler::Cpu_thread_component::Cpu_thread_component(
Cpu_session_component &cpu_session_component,
Allocator &md_alloc,
Pd_session_capability pd,
Cpu_session::Name const &name,
Affinity::Location affinity,
Cpu_session::Weight weight,
addr_t utcb,
char const *thread_name,
unsigned int thread_id)
: _cpu_session_component(cpu_session_component),
_md_alloc(md_alloc),
_parent_cpu_thread(
_cpu_session_component.parent_cpu_session().create_thread(pd,
name,
affinity,
weight,
utcb))
{
char label_buf[Session_label::size()];
snprintf(label_buf, sizeof(label_buf), "%s -> %s",
_cpu_session_component.session_label().string(),
thread_name);
_label = Session_label(label_buf);
snprintf(label_buf, sizeof(label_buf), "samples -> %s.%u",
_label.string(), thread_id);
_log_session_label = Session_label(label_buf);
_cpu_session_component.thread_ep().manage(this);
}
Cpu_sampler::Cpu_thread_component::~Cpu_thread_component()
{
flush();
if (_log)
destroy(_md_alloc, _log);
_cpu_session_component.thread_ep().dissolve(this);
}
void Cpu_sampler::Cpu_thread_component::take_sample()
{
if (verbose_take_sample)
Genode::log("taking sample of thread ", _label.string());
if (!_started) {
if (verbose_take_sample)
Genode::log("cannot take sample, thread not started yet");
return;
}
try {
_parent_cpu_thread.pause();
Thread_state thread_state = _parent_cpu_thread.state();
_parent_cpu_thread.resume();
_sample_buf[_sample_buf_index++] = thread_state.ip;
if (_sample_buf_index == SAMPLE_BUF_SIZE)
flush();
} catch (Cpu_thread::State_access_failed) {
Genode::log("thread state access failed");
}
}
void Cpu_sampler::Cpu_thread_component::reset()
{
_sample_buf_index = 0;
}
void Cpu_sampler::Cpu_thread_component::flush()
{
if (_sample_buf_index == 0)
return;
if (!_log)
_log = new (_md_alloc) Log_connection(_log_session_label);
/* number of hex characters + newline + '\0' */
enum { SAMPLE_STRING_SIZE = 2 * sizeof(addr_t) + 1 + 1 };
char sample_string[SAMPLE_STRING_SIZE];
char const *format_string;
if (sizeof(addr_t) == 8)
format_string = "%16lX\n";
else
format_string = "%8X\n";
for (unsigned int i = 0; i < _sample_buf_index; i++) {
snprintf(sample_string, SAMPLE_STRING_SIZE, format_string,
_sample_buf[i]);
_log->write(sample_string);
}
_sample_buf_index = 0;
}
Dataspace_capability
Cpu_sampler::Cpu_thread_component::utcb()
{
return _parent_cpu_thread.utcb();
}
void Cpu_sampler::Cpu_thread_component::start(addr_t ip, addr_t sp)
{
_parent_cpu_thread.start(ip, sp);
_started = true;
}
void Cpu_sampler::Cpu_thread_component::pause()
{
_parent_cpu_thread.pause();
}
void Cpu_sampler::Cpu_thread_component::resume()
{
_parent_cpu_thread.resume();
}
void Cpu_sampler::Cpu_thread_component::single_step(bool enable)
{
_parent_cpu_thread.single_step(enable);
}
void Cpu_sampler::Cpu_thread_component::cancel_blocking()
{
_parent_cpu_thread.cancel_blocking();
}
Thread_state Cpu_sampler::Cpu_thread_component::state()
{
return _parent_cpu_thread.state();
}
void Cpu_sampler::Cpu_thread_component::state(Thread_state const &state)
{
_parent_cpu_thread.state(state);
}
void
Cpu_sampler::Cpu_thread_component::exception_sigh(Signal_context_capability sigh_cap)
{
_parent_cpu_thread.exception_sigh(sigh_cap);
}
void Cpu_sampler::Cpu_thread_component::affinity(Affinity::Location location)
{
_parent_cpu_thread.affinity(location);
}
unsigned Cpu_sampler::Cpu_thread_component::trace_control_index()
{
return _parent_cpu_thread.trace_control_index();
}
Dataspace_capability
Cpu_sampler::Cpu_thread_component::trace_buffer()
{
return _parent_cpu_thread.trace_buffer();
}
Dataspace_capability
Cpu_sampler::Cpu_thread_component::trace_policy()
{
return _parent_cpu_thread.trace_policy();
}

View File

@ -0,0 +1,95 @@
/*
* \brief Cpu_thread_component interface
* \author Christian Prochaska
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CPU_THREAD_COMPONENT_H_
#define _CPU_THREAD_COMPONENT_H_
/* Genode includes */
#include <base/thread.h>
#include <cpu_thread/client.h>
#include <log_session/connection.h>
/* local includes */
#include "cpu_session_component.h"
namespace Cpu_sampler {
using namespace Genode;
class Cpu_thread_component;
class Cpu_session_component;
}
class Cpu_sampler::Cpu_thread_component : public Rpc_object<Cpu_thread>
{
private:
enum { SAMPLE_BUF_SIZE = 1024 };
Cpu_session_component &_cpu_session_component;
Allocator &_md_alloc;
Cpu_thread_client _parent_cpu_thread;
bool _started = false;
Session_label _label;
Session_label _log_session_label;
Genode::addr_t _sample_buf[SAMPLE_BUF_SIZE];
unsigned int _sample_buf_index = 0;
Log_connection *_log = 0;
public:
Cpu_thread_component(Cpu_session_component &cpu_session_component,
Allocator &md_alloc,
Pd_session_capability pd,
Cpu_session::Name const &name,
Affinity::Location affinity,
Cpu_session::Weight weight,
addr_t utcb,
char const *thread_name,
unsigned int thread_id);
~Cpu_thread_component();
Cpu_session_component const *cpu_session_component() const
{ return &_cpu_session_component; }
Thread_capability parent_thread() { return _parent_cpu_thread; }
Session_label &label() { return _label; }
void take_sample();
void reset();
void flush();
/**************************
** CPU thread interface **
*************************/
Dataspace_capability utcb() override;
void start(addr_t, addr_t) override;
void pause() override;
void resume() override;
void single_step(bool) override;
void cancel_blocking() override;
Thread_state state() override;
void state(Thread_state const &) override;
void exception_sigh(Signal_context_capability) override;
void affinity(Affinity::Location) override;
unsigned trace_control_index() override;
Dataspace_capability trace_buffer() override;
Dataspace_capability trace_policy() override;
};
#endif /* _CPU_THREAD_COMPONENT_H_ */

View File

@ -0,0 +1,205 @@
/*
* \brief CPU sampler
* \author Christian Prochaska
* \date 2016-01-15
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
#include <cpu_session/cpu_session.h>
#include <os/attached_dataspace.h>
#include <os/server.h>
#include <os/session_policy.h>
#include <os/static_root.h>
#include <timer_session/connection.h>
#include <util/list.h>
/* local includes */
#include "cpu_root.h"
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
#include "thread_list_change_handler.h"
namespace Cpu_sampler { struct Main; }
static constexpr bool verbose = false;
static constexpr bool verbose_missed_timeouts = false;
static constexpr bool verbose_sample_duration = true;
/******************
** Main program **
******************/
struct Cpu_sampler::Main : Thread_list_change_handler
{
Genode::Env &env;
Genode::Heap alloc;
Cpu_root cpu_root;
Attached_rom_dataspace config;
Timer::Connection timer;
Thread_list thread_list;
Thread_list selected_thread_list;
unsigned int sample_index;
unsigned int max_sample_index;
unsigned int timeout_us;
void handle_timeout(unsigned int num)
{
if (verbose_missed_timeouts && (num > 1))
Genode::log("missed ", num - 1, " timeouts");
auto lambda = [&] (Thread_element *cpu_thread_element) {
Cpu_thread_component *cpu_thread = cpu_thread_element->object();
cpu_thread->take_sample();
if (sample_index == max_sample_index)
cpu_thread->flush();
};
for_each_thread(selected_thread_list, lambda);
if (verbose_sample_duration && (sample_index == max_sample_index))
Genode::log("sample period finished");
sample_index++;
if (sample_index == max_sample_index)
timer.trigger_once(timeout_us);
}
Signal_rpc_member<Main> timeout_dispatcher =
{ env.ep(), *this, &Main::handle_timeout };
void handle_config_update(unsigned)
{
config.update();
sample_index = 0;
unsigned int sample_interval_ms =
config.xml().attribute_value<unsigned int>("sample_interval_ms", 1000);
unsigned int sample_duration_s =
config.xml().attribute_value<unsigned int>("sample_duration_s", 10);
max_sample_index = ((sample_duration_s * 1000) / sample_interval_ms) - 1;
timeout_us = sample_interval_ms * 1000;
thread_list_changed();
if (verbose_sample_duration)
Genode::log("starting a new sample period");
timer.trigger_periodic(timeout_us);
}
Signal_rpc_member<Main> config_update_dispatcher =
{ env.ep(), *this, &Main::handle_config_update};
void thread_list_changed() override
{
/* clear selected_thread_list */
auto remove_lambda = [&] (Thread_element *cpu_thread_element) {
if (verbose)
Genode::log("removing thread ",
cpu_thread_element->object()->label().string(),
" from selection");
selected_thread_list.remove(cpu_thread_element);
destroy(&alloc, cpu_thread_element);
};
for_each_thread(selected_thread_list, remove_lambda);
/* generate new selected_thread_list */
auto insert_lambda = [&] (Thread_element *cpu_thread_element) {
Cpu_thread_component *cpu_thread = cpu_thread_element->object();
if (verbose)
Genode::log("evaluating thread ", cpu_thread->label().string());
try {
Session_policy policy(cpu_thread->label(), config.xml());
cpu_thread->reset();
selected_thread_list.insert(new (&alloc)
Thread_element(cpu_thread));
if (verbose)
Genode::log("added thread ",
cpu_thread->label().string(),
" to selection");
} catch (Session_policy::No_policy_defined) {
if (verbose)
Genode::log("no session policy defined for thread ",
cpu_thread->label().string());
}
};
for_each_thread(thread_list, insert_lambda);
}
/**
* Constructor
*/
Main(Genode::Env &env)
: env(env),
alloc(env.ram(), env.rm()),
cpu_root(env.ep().rpc_ep(), env.ep().rpc_ep(), alloc, thread_list, *this),
config(env, "config")
{
/*
* Register signal handlers
*/
config.sigh(config_update_dispatcher);
timer.sigh(timeout_dispatcher);
/*
* Apply initial configuration
*/
handle_config_update(0);
/*
* Announce service
*/
env.parent().announce(env.ep().manage(cpu_root));
}
};
/***************
** Component **
***************/
namespace Component {
Genode::size_t stack_size() { return 4*1024*sizeof(Genode::addr_t); }
void construct(Genode::Env &env) { static Cpu_sampler::Main inst(env); }
}

View File

@ -0,0 +1,26 @@
/*
* \brief Generic 'Native_cpu' setup
* \author Christian Prochaska
* \date 2016-05-13
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Cpu_sampler includes */
#include "cpu_session_component.h"
Genode::Capability<Genode::Cpu_session::Native_cpu>
Cpu_sampler::Cpu_session_component::_setup_native_cpu()
{
return parent_cpu_session().native_cpu();
}
void Cpu_sampler::Cpu_session_component::_cleanup_native_cpu() { }

View File

@ -0,0 +1,96 @@
/*
* \brief Fiasco.OC-specific 'Native_cpu' setup
* \author Christian Prochaska
* \date 2016-05-13
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <foc_native_cpu/client.h>
/* GDB monitor includes */
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
namespace Cpu_sampler {
class Native_cpu_component;
}
using namespace Genode;
class Cpu_sampler::Native_cpu_component : public Rpc_object<Foc_native_cpu,
Native_cpu_component>
{
private:
Cpu_session_component &_cpu_session_component;
Foc_native_cpu_client _foc_native_cpu;
public:
Native_cpu_component(Cpu_session_component &cpu_session_component)
: _cpu_session_component(cpu_session_component),
_foc_native_cpu(_cpu_session_component.parent_cpu_session().native_cpu())
{
_cpu_session_component.thread_ep().manage(this);
}
~Native_cpu_component()
{
_cpu_session_component.thread_ep().dissolve(this);
}
void enable_vcpu(Thread_capability thread_cap, addr_t vcpu_state) override
{
auto lambda = [&] (Cpu_sampler::Cpu_thread_component *cpu_thread) {
_foc_native_cpu.enable_vcpu(cpu_thread->parent_thread(), vcpu_state);
};
_cpu_session_component.thread_ep().apply(thread_cap, lambda);
}
Native_capability native_cap(Thread_capability thread_cap) override
{
auto lambda = [&] (Cpu_sampler::Cpu_thread_component *cpu_thread) {
return _foc_native_cpu.native_cap(cpu_thread->parent_thread());
};
return _cpu_session_component.thread_ep().apply(thread_cap, lambda);
}
Native_capability alloc_irq() override
{
return _foc_native_cpu.alloc_irq();
}
};
Capability<Cpu_session::Native_cpu>
Cpu_sampler::Cpu_session_component::_setup_native_cpu()
{
Native_cpu_component *native_cpu_component =
new (_md_alloc) Native_cpu_component(*this);
return native_cpu_component->cap();
}
void Cpu_sampler::Cpu_session_component::_cleanup_native_cpu()
{
Native_cpu_component *native_cpu_component = nullptr;
_thread_ep.apply(_native_cpu_cap, [&] (Native_cpu_component *c) { native_cpu_component = c; });
if (!native_cpu_component) return;
destroy(_md_alloc, native_cpu_component);
}

View File

@ -0,0 +1,7 @@
REQUIRES += foc
SRC_CC += native_cpu.cc
vpath native_cpu.cc $(PRG_DIR)
include $(PRG_DIR)/../../target.inc

View File

@ -0,0 +1,7 @@
REQUIRES += hw
SRC_CC += native_cpu.cc
vpath native_cpu.cc $(PRG_DIR)/../..
include $(PRG_DIR)/../../target.inc

View File

@ -0,0 +1,83 @@
/*
* \brief NOVA-specific 'Native_cpu' setup
* \author Christian Prochaska
* \date 2016-05-13
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <nova_native_cpu/client.h>
/* Cpu_sampler includes */
#include "cpu_session_component.h"
#include "cpu_thread_component.h"
namespace Cpu_sampler {
class Native_cpu_component;
}
using namespace Genode;
class Cpu_sampler::Native_cpu_component : public Rpc_object<Nova_native_cpu,
Native_cpu_component>
{
private:
Cpu_session_component &_cpu_session_component;
Nova_native_cpu_client _nova_native_cpu;
public:
Native_cpu_component(Cpu_session_component &cpu_session_component)
: _cpu_session_component(cpu_session_component),
_nova_native_cpu(_cpu_session_component.parent_cpu_session().native_cpu())
{
_cpu_session_component.thread_ep().manage(this);
}
~Native_cpu_component()
{
_cpu_session_component.thread_ep().dissolve(this);
}
Native_capability pager_cap(Thread_capability thread_cap) override
{
auto lambda = [&] (Cpu_sampler::Cpu_thread_component *cpu_thread) {
return _nova_native_cpu.pager_cap(cpu_thread->parent_thread());
};
return _cpu_session_component.thread_ep().apply(thread_cap, lambda);
}
};
Capability<Cpu_session::Native_cpu>
Cpu_sampler::Cpu_session_component::_setup_native_cpu()
{
Native_cpu_component *native_cpu_component =
new (_md_alloc) Native_cpu_component(*this);
return native_cpu_component->cap();
}
void Cpu_sampler::Cpu_session_component::_cleanup_native_cpu()
{
Native_cpu_component *native_cpu_component = nullptr;
_thread_ep.apply(_native_cpu_cap,
[&] (Native_cpu_component *c) { native_cpu_component = c; });
if (!native_cpu_component) return;
destroy(_md_alloc, native_cpu_component);
}

View File

@ -0,0 +1,7 @@
REQUIRES += nova
SRC_CC += native_cpu.cc
vpath native_cpu.cc $(PRG_DIR)
include $(PRG_DIR)/../../target.inc

View File

@ -0,0 +1,7 @@
REQUIRES += okl4
SRC_CC += native_cpu.cc
vpath native_cpu.cc $(PRG_DIR)/../..
include $(PRG_DIR)/../../target.inc

View File

@ -0,0 +1,7 @@
REQUIRES += sel4
SRC_CC += native_cpu.cc
vpath native_cpu.cc $(PRG_DIR)/../..
include $(PRG_DIR)/../../target.inc

View File

@ -0,0 +1,11 @@
TARGET = cpu_sampler
SRC_CC += main.cc \
cpu_session_component.cc \
cpu_thread_component.cc
INC_DIR = $(REP_DIR)/src/server/cpu_sampler
LIBS = base
vpath %.cc $(REP_DIR)/src/server/cpu_sampler

View File

@ -0,0 +1,22 @@
/*
* \brief Thread list change handler interface
* \author Christian Prochaska
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _THREAD_LIST_CHANGE_HANDLER_H_
#define _THREAD_LIST_CHANGE_HANDLER_H_
struct Thread_list_change_handler
{
virtual void thread_list_changed() = 0;
};
#endif /* _THREAD_LIST_CHANGE_HANDLER_H_ */

View File

@ -0,0 +1,28 @@
/*
* \brief Test for the CPU sampler component
* \author Christian Prochaska
* \date 2016-01-18
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/log.h>
void __attribute((noinline)) func()
{
for (;;) { }
}
int main(int argc, char *argv[])
{
Genode::log("Test started. func: ", func);
func();
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = test-cpu_sampler
SRC_CC = main.cc
LIBS = base

View File

@ -68,3 +68,4 @@ xml_node
fpu
ds_ownership
fs_log
cpu_sampler