mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-06 10:38:31 +00:00
parent
901b39259c
commit
dc26910fc3
90
repos/gems/run/cpu_sampler.run
Normal file
90
repos/gems/run/cpu_sampler.run
Normal 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]
|
81
repos/gems/src/server/cpu_sampler/README
Normal file
81
repos/gems/src/server/cpu_sampler/README
Normal 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.
|
72
repos/gems/src/server/cpu_sampler/cpu_root.h
Normal file
72
repos/gems/src/server/cpu_sampler/cpu_root.h
Normal 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_ */
|
152
repos/gems/src/server/cpu_sampler/cpu_session_component.cc
Normal file
152
repos/gems/src/server/cpu_sampler/cpu_session_component.cc
Normal 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;
|
||||||
|
}
|
112
repos/gems/src/server/cpu_sampler/cpu_session_component.h
Normal file
112
repos/gems/src/server/cpu_sampler/cpu_session_component.h
Normal 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_ */
|
219
repos/gems/src/server/cpu_sampler/cpu_thread_component.cc
Normal file
219
repos/gems/src/server/cpu_sampler/cpu_thread_component.cc
Normal 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();
|
||||||
|
}
|
95
repos/gems/src/server/cpu_sampler/cpu_thread_component.h
Normal file
95
repos/gems/src/server/cpu_sampler/cpu_thread_component.h
Normal 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_ */
|
205
repos/gems/src/server/cpu_sampler/main.cc
Normal file
205
repos/gems/src/server/cpu_sampler/main.cc
Normal 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); }
|
||||||
|
}
|
26
repos/gems/src/server/cpu_sampler/native_cpu.cc
Normal file
26
repos/gems/src/server/cpu_sampler/native_cpu.cc
Normal 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() { }
|
96
repos/gems/src/server/cpu_sampler/spec/foc/native_cpu.cc
Normal file
96
repos/gems/src/server/cpu_sampler/spec/foc/native_cpu.cc
Normal 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);
|
||||||
|
}
|
7
repos/gems/src/server/cpu_sampler/spec/foc/target.mk
Normal file
7
repos/gems/src/server/cpu_sampler/spec/foc/target.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
REQUIRES += foc
|
||||||
|
|
||||||
|
SRC_CC += native_cpu.cc
|
||||||
|
|
||||||
|
vpath native_cpu.cc $(PRG_DIR)
|
||||||
|
|
||||||
|
include $(PRG_DIR)/../../target.inc
|
7
repos/gems/src/server/cpu_sampler/spec/hw/target.mk
Normal file
7
repos/gems/src/server/cpu_sampler/spec/hw/target.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
REQUIRES += hw
|
||||||
|
|
||||||
|
SRC_CC += native_cpu.cc
|
||||||
|
|
||||||
|
vpath native_cpu.cc $(PRG_DIR)/../..
|
||||||
|
|
||||||
|
include $(PRG_DIR)/../../target.inc
|
83
repos/gems/src/server/cpu_sampler/spec/nova/native_cpu.cc
Normal file
83
repos/gems/src/server/cpu_sampler/spec/nova/native_cpu.cc
Normal 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);
|
||||||
|
}
|
7
repos/gems/src/server/cpu_sampler/spec/nova/target.mk
Normal file
7
repos/gems/src/server/cpu_sampler/spec/nova/target.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
REQUIRES += nova
|
||||||
|
|
||||||
|
SRC_CC += native_cpu.cc
|
||||||
|
|
||||||
|
vpath native_cpu.cc $(PRG_DIR)
|
||||||
|
|
||||||
|
include $(PRG_DIR)/../../target.inc
|
7
repos/gems/src/server/cpu_sampler/spec/okl4/target.mk
Normal file
7
repos/gems/src/server/cpu_sampler/spec/okl4/target.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
REQUIRES += okl4
|
||||||
|
|
||||||
|
SRC_CC += native_cpu.cc
|
||||||
|
|
||||||
|
vpath native_cpu.cc $(PRG_DIR)/../..
|
||||||
|
|
||||||
|
include $(PRG_DIR)/../../target.inc
|
7
repos/gems/src/server/cpu_sampler/spec/sel4/target.mk
Normal file
7
repos/gems/src/server/cpu_sampler/spec/sel4/target.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
REQUIRES += sel4
|
||||||
|
|
||||||
|
SRC_CC += native_cpu.cc
|
||||||
|
|
||||||
|
vpath native_cpu.cc $(PRG_DIR)/../..
|
||||||
|
|
||||||
|
include $(PRG_DIR)/../../target.inc
|
11
repos/gems/src/server/cpu_sampler/target.inc
Normal file
11
repos/gems/src/server/cpu_sampler/target.inc
Normal 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
|
@ -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_ */
|
28
repos/gems/src/test/cpu_sampler/main.cc
Normal file
28
repos/gems/src/test/cpu_sampler/main.cc
Normal 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;
|
||||||
|
}
|
3
repos/gems/src/test/cpu_sampler/target.mk
Normal file
3
repos/gems/src/test/cpu_sampler/target.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
TARGET = test-cpu_sampler
|
||||||
|
SRC_CC = main.cc
|
||||||
|
LIBS = base
|
@ -68,3 +68,4 @@ xml_node
|
|||||||
fpu
|
fpu
|
||||||
ds_ownership
|
ds_ownership
|
||||||
fs_log
|
fs_log
|
||||||
|
cpu_sampler
|
||||||
|
Loading…
x
Reference in New Issue
Block a user