2015-06-15 20:41:59 +02:00
|
|
|
/*
|
|
|
|
* \brief Report information about present trace subjects
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2015-06-15
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 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 <trace_session/connection.h>
|
|
|
|
#include <timer_session/connection.h>
|
2016-11-25 16:54:49 +01:00
|
|
|
#include <base/component.h>
|
|
|
|
#include <base/attached_rom_dataspace.h>
|
|
|
|
#include <base/heap.h>
|
2015-06-15 20:41:59 +02:00
|
|
|
#include <os/reporter.h>
|
|
|
|
|
|
|
|
|
|
|
|
struct Trace_subject_registry
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
struct Entry : Genode::List<Entry>::Element
|
|
|
|
{
|
|
|
|
Genode::Trace::Subject_id const id;
|
|
|
|
|
|
|
|
Genode::Trace::Subject_info info;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execution time during the last period
|
|
|
|
*/
|
|
|
|
unsigned long long recent_execution_time = 0;
|
|
|
|
|
|
|
|
Entry(Genode::Trace::Subject_id id) : id(id) { }
|
|
|
|
|
|
|
|
void update(Genode::Trace::Subject_info const &new_info)
|
|
|
|
{
|
|
|
|
unsigned long long const last_execution_time = info.execution_time().value;
|
|
|
|
info = new_info;
|
|
|
|
recent_execution_time = info.execution_time().value - last_execution_time;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Genode::List<Entry> _entries;
|
|
|
|
|
|
|
|
Entry *_lookup(Genode::Trace::Subject_id const id)
|
|
|
|
{
|
|
|
|
for (Entry *e = _entries.first(); e; e = e->next())
|
|
|
|
if (e->id == id)
|
|
|
|
return e;
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum { MAX_SUBJECTS = 512 };
|
|
|
|
Genode::Trace::Subject_id _subjects[MAX_SUBJECTS];
|
|
|
|
|
|
|
|
void _sort_by_recent_execution_time()
|
|
|
|
{
|
|
|
|
Genode::List<Entry> sorted;
|
|
|
|
|
|
|
|
while (_entries.first()) {
|
|
|
|
|
|
|
|
/* find entry with lowest recent execution time */
|
|
|
|
Entry *lowest = _entries.first();
|
|
|
|
for (Entry *e = _entries.first(); e; e = e->next()) {
|
|
|
|
if (e->recent_execution_time < lowest->recent_execution_time)
|
|
|
|
lowest = e;
|
|
|
|
}
|
|
|
|
|
|
|
|
_entries.remove(lowest);
|
|
|
|
sorted.insert(lowest);
|
|
|
|
}
|
|
|
|
|
|
|
|
_entries = sorted;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
void update(Genode::Trace::Connection &trace, Genode::Allocator &alloc)
|
|
|
|
{
|
|
|
|
unsigned const num_subjects = trace.subjects(_subjects, MAX_SUBJECTS);
|
|
|
|
|
|
|
|
/* add and update existing entries */
|
|
|
|
for (unsigned i = 0; i < num_subjects; i++) {
|
|
|
|
|
|
|
|
Genode::Trace::Subject_id const id = _subjects[i];
|
|
|
|
|
|
|
|
Entry *e = _lookup(id);
|
|
|
|
if (!e) {
|
|
|
|
e = new (alloc) Entry(id);
|
|
|
|
_entries.insert(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
e->update(trace.subject_info(id));
|
|
|
|
|
|
|
|
/* purge dead threads */
|
|
|
|
if (e->info.state() == Genode::Trace::Subject_info::DEAD) {
|
|
|
|
trace.free(e->id);
|
|
|
|
_entries.remove(e);
|
|
|
|
Genode::destroy(alloc, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_sort_by_recent_execution_time();
|
|
|
|
}
|
|
|
|
|
|
|
|
void report(Genode::Xml_generator &xml,
|
|
|
|
bool report_affinity, bool report_activity)
|
|
|
|
{
|
|
|
|
for (Entry const *e = _entries.first(); e; e = e->next()) {
|
|
|
|
xml.node("subject", [&] () {
|
|
|
|
xml.attribute("label", e->info.session_label().string());
|
|
|
|
xml.attribute("thread", e->info.thread_name().string());
|
|
|
|
xml.attribute("id", e->id.id);
|
|
|
|
|
|
|
|
typedef Genode::Trace::Subject_info Subject_info;
|
|
|
|
Subject_info::State const state = e->info.state();
|
|
|
|
xml.attribute("state", Subject_info::state_name(state));
|
|
|
|
|
|
|
|
if (report_activity)
|
|
|
|
xml.node("activity", [&] () {
|
|
|
|
xml.attribute("total", e->info.execution_time().value);
|
|
|
|
xml.attribute("recent", e->recent_execution_time);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (report_affinity)
|
|
|
|
xml.node("affinity", [&] () {
|
|
|
|
xml.attribute("xpos", e->info.affinity().xpos());
|
|
|
|
xml.attribute("ypos", e->info.affinity().ypos());
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
namespace App {
|
|
|
|
|
|
|
|
struct Main;
|
|
|
|
using namespace Genode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct App::Main
|
2015-06-15 20:41:59 +02:00
|
|
|
{
|
2016-11-25 16:54:49 +01:00
|
|
|
Env &_env;
|
|
|
|
|
|
|
|
Trace::Connection _trace { _env, 512*1024, 32*1024, 0 };
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2017-01-03 11:24:16 +01:00
|
|
|
Reporter _reporter { _env, "trace_subjects", "trace_subjects", 64*1024 };
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
static unsigned long _default_period_ms() { return 5000; }
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
unsigned long _period_ms = _default_period_ms();
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
bool _report_affinity = false;
|
|
|
|
bool _report_activity = false;
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Attached_rom_dataspace _config { _env, "config" };
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
bool _config_report_attribute_enabled(char const *attr) const
|
2015-06-15 20:41:59 +02:00
|
|
|
{
|
|
|
|
try {
|
2016-11-25 16:54:49 +01:00
|
|
|
return _config.xml().sub_node("report").attribute_value(attr, false);
|
2015-06-15 20:41:59 +02:00
|
|
|
} catch (...) { return false; }
|
|
|
|
}
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Timer::Connection _timer { _env };
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Heap _heap { _env.ram(), _env.rm() };
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Trace_subject_registry _trace_subject_registry;
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void _handle_config();
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Signal_handler<Main> _config_handler = {
|
|
|
|
_env.ep(), *this, &Main::_handle_config};
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void _handle_period();
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
Signal_handler<Main> _periodic_handler = {
|
|
|
|
_env.ep(), *this, &Main::_handle_period};
|
|
|
|
|
|
|
|
Main(Env &env) : _env(env)
|
2015-06-15 20:41:59 +02:00
|
|
|
{
|
2016-11-25 16:54:49 +01:00
|
|
|
_config.sigh(_config_handler);
|
|
|
|
_handle_config();
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
_timer.sigh(_periodic_handler);
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
_reporter.enabled(true);
|
2015-06-15 20:41:59 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void App::Main::_handle_config()
|
2015-06-15 20:41:59 +02:00
|
|
|
{
|
2016-11-25 16:54:49 +01:00
|
|
|
_config.update();
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
_period_ms = _config.xml().attribute_value("period_ms", _default_period_ms());
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
_report_affinity = _config_report_attribute_enabled("affinity");
|
|
|
|
_report_activity = _config_report_attribute_enabled("activity");
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
log("period_ms=", _period_ms, ", "
|
|
|
|
"report_activity=", _report_activity, ", "
|
|
|
|
"report_affinity=", _report_affinity);
|
2015-06-15 20:41:59 +02:00
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
_timer.trigger_periodic(1000*_period_ms);
|
2015-06-15 20:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void App::Main::_handle_period()
|
2015-06-15 20:41:59 +02:00
|
|
|
{
|
|
|
|
/* update subject information */
|
2016-11-25 16:54:49 +01:00
|
|
|
_trace_subject_registry.update(_trace, _heap);
|
2015-06-15 20:41:59 +02:00
|
|
|
|
|
|
|
/* generate report */
|
2016-11-25 16:54:49 +01:00
|
|
|
_reporter.clear();
|
|
|
|
Genode::Reporter::Xml_generator xml(_reporter, [&] ()
|
2015-06-15 20:41:59 +02:00
|
|
|
{
|
2016-11-25 16:54:49 +01:00
|
|
|
_trace_subject_registry.report(xml, _report_affinity, _report_activity);
|
2015-06-15 20:41:59 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-25 16:54:49 +01:00
|
|
|
void Component::construct(Genode::Env &env) { static App::Main main(env); }
|
2015-06-15 20:41:59 +02:00
|
|
|
|