mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +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
|
||||
ds_ownership
|
||||
fs_log
|
||||
cpu_sampler
|
||||
|
Loading…
Reference in New Issue
Block a user