genode/repos/os/src/app/trace_logger/monitor.cc

160 lines
3.8 KiB
C++

/*
* \brief Monitoring of a trace subject
* \author Martin Stein
* \date 2018-01-12
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <monitor.h>
/* Genode includes */
#include <trace_session/connection.h>
using namespace Genode;
/******************
** Monitor_base **
******************/
Monitor_base::Monitor_base(Trace::Connection &trace,
Region_map &rm,
Trace::Subject_id subject_id)
:
_trace(trace), _rm(rm),
_buffer_raw(*(Trace::Buffer *)rm.attach(_trace.buffer(subject_id)))
{ }
Monitor_base::~Monitor_base()
{
_rm.detach(&_buffer_raw);
}
/*************
** Monitor **
*************/
Monitor &Monitor::find_by_subject_id(Trace::Subject_id const subject_id)
{
if (subject_id.id == _subject_id.id) {
return *this; }
bool const side = subject_id.id > _subject_id.id;
Monitor *const monitor = Avl_node<Monitor>::child(side);
if (!monitor) {
throw Monitor_tree::No_match(); }
return monitor->find_by_subject_id(subject_id);
}
Monitor::Monitor(Trace::Connection &trace,
Region_map &rm,
Trace::Subject_id subject_id)
:
Monitor_base(trace, rm, subject_id),
_subject_id(subject_id), _buffer(_buffer_raw)
{
_update_info();
}
void Monitor::_update_info()
{
try {
Trace::Subject_info const &info =
_trace.subject_info(_subject_id);
uint64_t const last_execution_time =
_info.execution_time().thread_context;
_info = info;
_recent_exec_time =
_info.execution_time().thread_context - last_execution_time;
}
catch (Trace::Nonexistent_subject) { warning("Cannot update subject info: Nonexistent_subject"); }
}
void Monitor::print(bool activity, bool affinity)
{
_update_info();
/* print general subject information */
typedef Trace::Subject_info Subject_info;
Subject_info::State const state = _info.state();
log("<subject label=\"", _info.session_label().string(),
"\" thread=\"", _info.thread_name().string(),
"\" id=\"", _subject_id.id,
"\" state=\"", Subject_info::state_name(state),
"\">");
/* print subjects activity if desired */
if (activity)
log(" <activity total=\"", _info.execution_time().thread_context,
"\" recent=\"", _recent_exec_time,
"\">");
/* print subjects affinity if desired */
if (affinity)
log(" <affinity xpos=\"", _info.affinity().xpos(),
"\" ypos=\"", _info.affinity().ypos(),
"\">");
/* print all buffer entries that we haven't yet printed */
bool printed_buf_entries = false;
_buffer.for_each_new_entry([&] (Trace::Buffer::Entry entry) {
/* get readable data length and skip empty entries */
size_t length = min(entry.length(), (unsigned)MAX_ENTRY_LENGTH - 1);
if (!length)
return;
/* copy entry data from buffer and add terminating '0' */
memcpy(_curr_entry_data, entry.data(), length);
_curr_entry_data[length] = '\0';
/* avoid output of empty lines due to end of line character at end */
if (_curr_entry_data[length - 1] == '\n')
_curr_entry_data[length - 1] = '\0';
/* print copied entry data out to log */
if (!printed_buf_entries) {
log(" <buffer>");
printed_buf_entries = true;
}
log(Cstring(_curr_entry_data));
});
/* print end tags */
if (printed_buf_entries)
log(" </buffer>");
else
log(" <buffer />");
log("</subject>");
}
/******************
** Monitor_tree **
******************/
Monitor &Monitor_tree::find_by_subject_id(Trace::Subject_id const subject_id)
{
Monitor *const monitor = first();
if (!monitor)
throw No_match();
return monitor->find_by_subject_id(subject_id);
}