diff --git a/repos/os/run/trace_logger.run b/repos/os/run/trace_logger.run new file mode 100644 index 0000000000..708cd798d2 --- /dev/null +++ b/repos/os/run/trace_logger.run @@ -0,0 +1,172 @@ +# +# Build +# + +set build_components { + core + init + drivers/timer + server/dynamic_rom + app/cpu_burner + test/trace_logger + app/trace_logger + lib/trace/policy/null + lib/trace/policy/rpc_name +} + +proc gpio_drv { } { if {[have_spec rpi] && [have_spec hw]} { return hw_gpio_drv } + if {[have_spec rpi] && [have_spec foc]} { return foc_gpio_drv } + return gpio_drv } + +source ${genode_dir}/repos/base/run/platform_drv.inc + +lappend_if [have_spec gpio] build_components drivers/gpio + +append_platform_drv_build_components + +build $build_components + +create_boot_directory + +# +# Generate config +# + +append config { + + + + + + + + + + + + + + + + } + +append_platform_drv_config + +append_if [have_spec gpio] config " + + + + + " + +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + + +# +# Boot modules +# + +# generic modules +set boot_modules { + core + ld.lib.so + init + timer + dynamic_rom + cpu_burner + trace_logger + test-trace_logger + null + rpc_name +} + +# platform-specific modules +append_platform_drv_boot_modules + +lappend_if [have_spec gpio] boot_modules [gpio_drv] + +build_boot_image $boot_modules + +append qemu_args " -smp 4,cores=4 " + +run_genode_until forever diff --git a/repos/os/src/app/trace_logger/README b/repos/os/src/app/trace_logger/README new file mode 100644 index 0000000000..17671819bf --- /dev/null +++ b/repos/os/src/app/trace_logger/README @@ -0,0 +1,100 @@ + + ========================== + Convenient tracing fronted + ========================== + + +Brief +##### + +The 'trace_logger' component can be used to easily gather, process and export +different types of tracing data. Which subjects to select is configurable via +session label policies and thread names. Which data to collect from the +selected subjects can be configured for each subject individually, for groups +of subjects, or for all subjects. The gathered data can be exported as log +output. + + +Configuration +############# + +This is an example configuration of the 'trace_logger' component which shows +the default value for each attribute except the policy.thread and +policy.label: + +! +! +! +! +! +! + + +This is a short description of the tags and attributes: + +:config.verbose: + Optional. Toggles wether the trace_logger shall log debugging information. + +:config.session_ram: + Optional. Amount of RAM donated to the trace session. + +:config.session_arg_buffer: + Optional. Size of the trace sessions argument buffer. + +:config.session_parent_levels: + Optional. Number of parent levels to trace. + +:config.period_sec: + Optional. Length of processing/export interval in seconds. + +:config.activity: + Optional. Wether to export thread-activity information. + +:config.affinity: + Optional. Wether to export thread-affinity information. + +:config.default_policy: + Optional. Name of tracing policy for subjects without individual config. + +:config.default_policy: + Optional. Size of tracing buffer for subjects without individual config. + +:config.policy: + Subject selector. For matching subjects, tracing is enabled and the defined + individual configuration is applied. + +:config.policy.label: +:config.policy.label_prefix: +:config.policy.label_suffix: + Mutually exclusive. Filters subjects according to their session label. + +:config.policy.thread: + Optional. Filters subjects according to their exact thread name. + +:config.policy.buffer: + Optional. Size of tracing buffer used for matching subjects. + +:config.policy.policy: + Optional. Name of tracing policy used for matching subjects. + + +Sessions +######## + +This is an overview of the sessions required and provided by the +'trace_logger' component apart from the environment sessions: + +* Requires ROM sessions to all configured tracing policies. +* Requires one TRACE session that provides the desired subjects. +* Requires one Timer session. diff --git a/repos/os/src/app/trace_logger/avl_tree.h b/repos/os/src/app/trace_logger/avl_tree.h new file mode 100644 index 0000000000..0d9e6b74e2 --- /dev/null +++ b/repos/os/src/app/trace_logger/avl_tree.h @@ -0,0 +1,59 @@ +/* + * \brief AVL-tree wrapper for additional functionality + * \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. + */ + +#ifndef _AVL_TREE_H_ +#define _AVL_TREE_H_ + +/* Genode includes */ +#include + +namespace Local { + + template class Avl_node; + template class Avl_tree; +} + + +/** + * AVL-node wrapper for additional functionality + */ +template +struct Local::Avl_node : Genode::Avl_node +{ + using Base = Genode::Avl_node; + + template + void for_each(FUNC && functor) + { + if (NT * l = Base::child(Avl_node::LEFT)) l->for_each(functor); + functor(*static_cast(this)); + if (NT * r = Base::child(Avl_node::RIGHT)) r->for_each(functor); + } +}; + + +/** + * AVL-tree wrapper for additional functionality + */ +template +struct Local::Avl_tree : Genode::Avl_tree +{ + using Base = Genode::Avl_tree; + + template + void for_each(FUNC && functor) { + if (Base::first()) Base::first()->for_each(functor); } +}; + + +#endif /* _AVL_TREE_H_ */ diff --git a/repos/os/src/app/trace_logger/config.xsd b/repos/os/src/app/trace_logger/config.xsd new file mode 100644 index 0000000000..21987052f7 --- /dev/null +++ b/repos/os/src/app/trace_logger/config.xsd @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/src/app/trace_logger/main.cc b/repos/os/src/app/trace_logger/main.cc new file mode 100644 index 0000000000..a87b371121 --- /dev/null +++ b/repos/os/src/app/trace_logger/main.cc @@ -0,0 +1,196 @@ +/* + * \brief Log information about trace subjects + * \author Martin Stein + * \date 2018-01-15 + */ + +/* + * 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 +#include +#include + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +using namespace Genode; +using Thread_name = String<40>; + + +class Main +{ + private: + + enum { MAX_SUBJECTS = 512 }; + enum { DEFAULT_PERIOD_SEC = 5 }; + enum { DEFAULT_BUFFER = 1024 * 4 }; + enum { DEFAULT_SESSION_ARG_BUFFER = 1024 * 4 }; + enum { DEFAULT_SESSION_RAM = 1024 * 1024 }; + enum { DEFAULT_SESSION_PARENT_LEVELS = 0 }; + + Env &_env; + Timer::Connection _timer { _env }; + Attached_rom_dataspace _config_rom { _env, "config" }; + Xml_node const _config { _config_rom.xml() }; + Trace::Connection _trace { _env, + _config.attribute_value("session_ram", Number_of_bytes(DEFAULT_SESSION_RAM)), + _config.attribute_value("session_arg_buffer", Number_of_bytes(DEFAULT_SESSION_ARG_BUFFER)), + _config.attribute_value("session_parent_levels", (unsigned)DEFAULT_SESSION_PARENT_LEVELS) }; + bool const _affinity { _config.attribute_value("affinity", false) }; + bool const _activity { _config.attribute_value("activity", false) }; + bool const _verbose { _config.attribute_value("verbose", false) }; + Microseconds const _period_us { read_sec_attr(_config, "period_sec", DEFAULT_PERIOD_SEC) }; + Number_of_bytes const _default_buf_sz { _config.attribute_value("default_buffer", Number_of_bytes(DEFAULT_BUFFER)) }; + Timer::Periodic_timeout
_period { _timer, *this, &Main::_handle_period, _period_us }; + Heap _heap { _env.ram(), _env.rm() }; + Monitor_tree _monitors_0 { }; + Monitor_tree _monitors_1 { }; + bool _monitors_switch { false }; + Policy_tree _policies { }; + Policy_name _default_policy_name { _config.attribute_value("default_policy", Policy_name("null")) }; + Policy _default_policy { _env, _trace, _default_policy_name }; + unsigned long _report_id { 0 }; + unsigned long _num_subjects { 0 }; + unsigned long _num_monitors { 0 }; + Trace::Subject_id _subjects[MAX_SUBJECTS]; + + void _handle_period(Duration) + { + /* + * Update monitors + * + * Which monitors are held and how they are configured depends on: + * + * 1) Which subjects are available at the Trace session, + * 2) which tracing state the subjects are currently in, + * 3) the configuration of this component about which subjects + * to monitor and how + * + * All this might have changed since the last call of this method. + * So, adapt the monitors and the monitor tree accordingly. + */ + + /* + * Switch monitor trees so that the new tree is empty and the old + * tree contains all monitors. + */ + Monitor_tree &old_monitors = _monitors_switch ? _monitors_1 : _monitors_0; + Monitor_tree &new_monitors = _monitors_switch ? _monitors_0 : _monitors_1; + _monitors_switch = !_monitors_switch; + + /* update available subject IDs and iterate over them */ + try { _num_subjects = _trace.subjects(_subjects, MAX_SUBJECTS); } + catch (Out_of_ram ) { warning("Cannot list subjects: Out_of_ram" ); return; } + catch (Out_of_caps) { warning("Cannot list subjects: Out_of_caps"); return; } + for (unsigned i = 0; i < _num_subjects; i++) { + + Trace::Subject_id const id = _subjects[i]; + try { + /* skip dead subjects */ + if (_trace.subject_info(id).state() == Trace::Subject_info::DEAD) + continue; + + /* check if there is a matching policy in the XML config */ + Session_policy session_policy = _session_policy(id); + try { + /* lookup monitor by subject ID */ + Monitor &monitor = old_monitors.find_by_subject_id(id); + + /* move monitor from old to new tree */ + old_monitors.remove(&monitor); + new_monitors.insert(&monitor); + + } catch (Monitor_tree::No_match) { + + /* create monitor for subject in the new tree */ + _new_monitor(new_monitors, id, session_policy); + } + } + catch (Trace::Nonexistent_subject ) { continue; } + catch (Session_policy::No_policy_defined) { continue; } + } + /* all monitors in the old tree are deprecated, destroy them */ + while (Monitor *monitor = old_monitors.first()) + _destroy_monitor(old_monitors, *monitor); + + /* dump information of each monitor in the new tree */ + log(""); + log("--- Report ", _report_id++, " (", _num_monitors, "/", _num_subjects, " subjects) ---"); + new_monitors.for_each([&] (Monitor &monitor) { + monitor.print(_activity, _affinity); + }); + } + + void _destroy_monitor(Monitor_tree &monitors, Monitor &monitor) + { + if (_verbose) + log("destroy monitor: subject ", monitor.subject_id().id); + + try { _trace.free(monitor.subject_id()); } + catch (Trace::Nonexistent_subject) { } + monitors.remove(&monitor); + destroy(_heap, &monitor); + _num_monitors--; + } + + void _new_monitor(Monitor_tree &monitors, + Trace::Subject_id id, + Session_policy &session_policy) + { + try { + Number_of_bytes const buffer_sz = session_policy.attribute_value("buffer", _default_buf_sz); + Policy_name const policy_name = session_policy.attribute_value("policy", _default_policy_name); + try { + _trace.trace(id.id, _policies.find_by_name(policy_name).id(), buffer_sz); + } catch (Policy_tree::No_match) { + Policy &policy = *new (_heap) Policy(_env, _trace, policy_name); + _policies.insert(policy); + _trace.trace(id.id, policy.id(), buffer_sz); + } + monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id)); + } + catch (Out_of_ram ) { warning("Cannot activate tracing: Out_of_ram" ); return; } + catch (Out_of_caps ) { warning("Cannot activate tracing: Out_of_caps" ); return; } + catch (Trace::Already_traced ) { warning("Cannot activate tracing: Already_traced" ); return; } + catch (Trace::Source_is_dead ) { warning("Cannot activate tracing: Source_is_dead" ); return; } + catch (Trace::Nonexistent_policy ) { warning("Cannot activate tracing: Nonexistent_policy" ); return; } + catch (Trace::Traced_by_other_session) { warning("Cannot activate tracing: Traced_by_other_session"); return; } + catch (Trace::Nonexistent_subject ) { warning("Cannot activate tracing: Nonexistent_subject" ); return; } + catch (Region_map::Invalid_dataspace ) { warning("Cannot activate tracing: Loading policy failed" ); return; } + + + _num_monitors++; + if (_verbose) + log("new monitor: subject ", id.id); + } + + Session_policy _session_policy(Trace::Subject_id id) + { + Trace::Subject_info info = _trace.subject_info(id); + Session_label const label(info.session_label()); + Session_policy policy(label, _config); + if (policy.has_attribute("thread")) + if (policy.attribute_value("thread", Thread_name()) != info.thread_name()) + throw Session_policy::No_policy_defined(); + + return policy; + } + + public: + + Main(Env &env) : _env(env) { _policies.insert(_default_policy); } +}; + + +void Component::construct(Env &env) { static Main main(env); } diff --git a/repos/os/src/app/trace_logger/monitor.cc b/repos/os/src/app/trace_logger/monitor.cc new file mode 100644 index 0000000000..a65eb6110c --- /dev/null +++ b/repos/os/src/app/trace_logger/monitor.cc @@ -0,0 +1,155 @@ +/* + * \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 + +/* Genode includes */ +#include + +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::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); + + unsigned long long const last_execution_time = + _info.execution_time().value; + + _info = info; + _recent_exec_time = + _info.execution_time().value - 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(""); + + /* print subjects activity if desired */ + if (activity) + log(" "); + + /* print subjects affinity if desired */ + if (affinity) + log(" "); + + /* 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'; + + /* print copied entry data out to log */ + if (!printed_buf_entries) { + log(" "); + printed_buf_entries = true; + } + log(Cstring(_curr_entry_data)); + }); + /* print end tags */ + if (printed_buf_entries) + log(" "); + else + log(" "); + log(""); +} + + +/****************** + ** 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); +} diff --git a/repos/os/src/app/trace_logger/monitor.h b/repos/os/src/app/trace_logger/monitor.h new file mode 100644 index 0000000000..e701ecf721 --- /dev/null +++ b/repos/os/src/app/trace_logger/monitor.h @@ -0,0 +1,103 @@ +/* + * \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. + */ + +#ifndef _MONITOR_H_ +#define _MONITOR_H_ + +/* local includes */ +#include +#include + +/* Genode includes */ +#include + +namespace Genode { namespace Trace { class Connection; } } + + +/** + * To attach and detach trace-buffer dataspace in the right moments + */ +class Monitor_base +{ + protected: + + Genode::Trace::Connection &_trace; + Genode::Region_map &_rm; + Genode::Trace::Buffer &_buffer_raw; + + Monitor_base(Genode::Trace::Connection &trace, + Genode::Region_map &rm, + Genode::Trace::Subject_id subject_id); + + ~Monitor_base(); +}; + + +/** + * Monitors tracing information of one tracing subject + */ +class Monitor : public Monitor_base, + public Local::Avl_node +{ + private: + + enum { MAX_ENTRY_LENGTH = 256 }; + + Genode::Trace::Subject_id const _subject_id; + Trace_buffer _buffer; + unsigned long _report_id { 0 }; + Genode::Trace::Subject_info _info { }; + unsigned long long _recent_exec_time { 0 }; + char _curr_entry_data[MAX_ENTRY_LENGTH]; + + void _update_info(); + + public: + + Monitor(Genode::Trace::Connection &trace, + Genode::Region_map &rm, + Genode::Trace::Subject_id subject_id); + + void print(bool activity, bool affinity); + + + /************** + ** Avl_node ** + **************/ + + Monitor &find_by_subject_id(Genode::Trace::Subject_id const subject_id); + + bool higher(Monitor *monitor) { return monitor->_subject_id.id > _subject_id.id; } + + + /*************** + ** Accessors ** + ***************/ + + Genode::Trace::Subject_id subject_id() const { return _subject_id; } + Genode::Trace::Subject_info const &info() const { return _info; } +}; + + +/** + * AVL tree of monitors with their subject ID as index + */ +struct Monitor_tree : Local::Avl_tree +{ + struct No_match : Genode::Exception { }; + + Monitor &find_by_subject_id(Genode::Trace::Subject_id const subject_id); +}; + + +#endif /* _MONITOR_H_ */ diff --git a/repos/os/src/app/trace_logger/policy.cc b/repos/os/src/app/trace_logger/policy.cc new file mode 100644 index 0000000000..ac48619084 --- /dev/null +++ b/repos/os/src/app/trace_logger/policy.cc @@ -0,0 +1,68 @@ +/* + * \brief Installs and maintains a tracing policy + * \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 + +using namespace Genode; + + +/*********************** + ** Policy_avl_member ** + ***********************/ + +Policy_avl_member::Policy_avl_member(Policy_name const &name, + ::Policy &policy) +: + Avl_string_base(name.string()), _policy(policy) +{ } + + +/************ + ** Policy ** + ************/ + +Policy::Policy(Env &env, Trace::Connection &trace, Policy_name const &name) +: + Policy_base(name), _avl_member(_name, *this), _env(env), _trace(trace) +{ + Dataspace_capability dst_ds = _trace.policy(_id); + void *dst = _env.rm().attach(dst_ds); + void *src = _env.rm().attach(_ds); + memcpy(dst, src, _size); + _env.rm().detach(dst); + _env.rm().detach(src); +} + + +/***************** + ** Policy_tree ** + *****************/ + +Policy &Policy_tree::policy(Avl_string_base const &node) +{ + return static_cast(&node)->policy(); +} + + +Policy &Policy_tree::find_by_name(Policy_name name) +{ + if (name == Policy_name() || !first()) { + throw No_match(); } + + Avl_string_base *node = first()->find_by_name(name.string()); + if (!node) { + throw No_match(); } + + return policy(*node); +} diff --git a/repos/os/src/app/trace_logger/policy.h b/repos/os/src/app/trace_logger/policy.h new file mode 100644 index 0000000000..46921a4be8 --- /dev/null +++ b/repos/os/src/app/trace_logger/policy.h @@ -0,0 +1,120 @@ +/* + * \brief Installs and maintains a tracing policy + * \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. + */ + +#ifndef _POLICY_H_ +#define _POLICY_H_ + +/* Genode includes */ +#include +#include +#include +#include + +using Policy_name = Genode::String<40>; + +class Policy; + + +/** + * Member of a policy that allows the policy to be managed in a tree + */ +class Policy_avl_member : public Genode::Avl_string_base +{ + private: + + ::Policy &_policy; + + public: + + Policy_avl_member(Policy_name const &name, + ::Policy &policy); + + + /*************** + ** Accessors ** + ***************/ + + ::Policy &policy() const { return _policy; } +}; + + +/** + * Ensure that policy name is constructed before it is used as tree index + */ +class Policy_base +{ + protected: + + Policy_name const _name; + + Policy_base(Policy_name const &name) : _name(name) { } +}; + + +/** + * Installs and maintains a tracing policy + */ +class Policy : public Policy_base +{ + private: + + Policy_avl_member _avl_member; + Genode::Env &_env; + Genode::Trace::Connection &_trace; + Genode::Rom_connection _rom { _env, _name.string() }; + Genode::Rom_dataspace_capability const _ds { _rom.dataspace() }; + Genode::size_t const _size { Genode::Dataspace_client(_ds).size() }; + Genode::Trace::Policy_id const _id { _trace.alloc_policy(_size) }; + + public: + + + Policy(Genode::Env &env, + Genode::Trace::Connection &trace, + Policy_name const &name); + + + /*************** + ** Accessors ** + ***************/ + + Genode::Trace::Policy_id id() const { return _id; } + Policy_avl_member &avl_member() { return _avl_member; } +}; + + +/** + * AVL tree of policies with their name as index + */ +struct Policy_tree : Genode::Avl_tree +{ + using Avl_tree = Genode::Avl_tree; + + struct No_match : Genode::Exception { }; + + static ::Policy &policy(Genode::Avl_string_base const &node); + + ::Policy &find_by_name(Policy_name name); + + template + void for_each(FUNC && functor) const { + Avl_tree::for_each([&] (Genode::Avl_string_base const &node) { + functor(policy(node)); + }); + } + + void insert(::Policy &policy) { Avl_tree::insert(&policy.avl_member()); } +}; + + +#endif /* _POLICY_H_ */ diff --git a/repos/os/src/app/trace_logger/target.mk b/repos/os/src/app/trace_logger/target.mk new file mode 100644 index 0000000000..788e2a360c --- /dev/null +++ b/repos/os/src/app/trace_logger/target.mk @@ -0,0 +1,5 @@ +TARGET = trace_logger +INC_DIR += $(PRG_DIR) +SRC_CC = main.cc monitor.cc policy.cc xml_node.cc +CONFIG_XSD = config.xsd +LIBS += base diff --git a/repos/os/src/app/trace_logger/trace_buffer.h b/repos/os/src/app/trace_logger/trace_buffer.h new file mode 100644 index 0000000000..45c433e4bb --- /dev/null +++ b/repos/os/src/app/trace_logger/trace_buffer.h @@ -0,0 +1,61 @@ +/* + * \brief Wrapper for Trace::Buffer that adds some convenient functionality + * \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. + */ + +#ifndef _TRACE_BUFFER_H_ +#define _TRACE_BUFFER_H_ + +/* Genode includes */ +#include + + +/** + * Wrapper for Trace::Buffer that adds some convenient functionality + */ +class Trace_buffer +{ + private: + + Genode::Trace::Buffer &_buffer; + Genode::Trace::Buffer::Entry _curr { _buffer.first() }; + + public: + + Trace_buffer(Genode::Trace::Buffer &buffer) : _buffer(buffer) { } + + /** + * Call functor for each entry that wasn't yet processed + */ + template + void for_each_new_entry(FUNC && functor) + { + using namespace Genode; + + /* initialize _curr if _buffer was empty until now */ + if (_curr.last()) + _curr = _buffer.first(); + + /* iterate over all entries that were not processed yet */ + Trace::Buffer::Entry e1 = _curr; + for (Trace::Buffer::Entry e2 = _curr; !e2.last(); + e2 = _buffer.next(e2)) + { + e1 = e2; + functor(e1); + } + /* remember the last processed entry in _curr */ + _curr = e1; + } +}; + + +#endif /* _TRACE_BUFFER_H_ */ diff --git a/repos/os/src/app/trace_logger/xml_node.cc b/repos/os/src/app/trace_logger/xml_node.cc new file mode 100644 index 0000000000..be7d7b80cb --- /dev/null +++ b/repos/os/src/app/trace_logger/xml_node.cc @@ -0,0 +1,29 @@ +/* + * \brief Genode XML nodes plus local utilities + * \author Martin Stein + * \date 2016-08-19 + */ + +/* + * Copyright (C) 2016-2017 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 + +using namespace Genode; + + +Microseconds Genode::read_sec_attr(Xml_node const node, + char const *name, + unsigned long const default_sec) +{ + unsigned long sec = node.attribute_value(name, 0UL); + if (!sec) { + sec = default_sec; + } + return Microseconds(sec * 1000 * 1000); +} diff --git a/repos/os/src/app/trace_logger/xml_node.h b/repos/os/src/app/trace_logger/xml_node.h new file mode 100644 index 0000000000..86f3840a62 --- /dev/null +++ b/repos/os/src/app/trace_logger/xml_node.h @@ -0,0 +1,29 @@ +/* + * \brief Genode XML nodes plus local utilities + * \author Martin Stein + * \date 2016-08-19 + */ + +/* + * Copyright (C) 2016-2017 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. + */ + +#ifndef _XML_NODE_H_ +#define _XML_NODE_H_ + +/* Genode includes */ +#include +#include + + +namespace Genode { + + Microseconds read_sec_attr(Xml_node const node, + char const *name, + unsigned long const default_sec); +} + +#endif /* _XML_NODE_H_ */ diff --git a/repos/os/src/test/trace_logger/main.cc b/repos/os/src/test/trace_logger/main.cc new file mode 100644 index 0000000000..af1c5e5745 --- /dev/null +++ b/repos/os/src/test/trace_logger/main.cc @@ -0,0 +1,30 @@ +/* + * \brief Test functionality of the trace logger + * \author Martin Stein + * \date 2017-01-23 + */ + +/* + * Copyright (C) 2017 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. + */ + +/* Genode includes */ +#include +#include +#include + +using namespace Genode; + + +void Component::construct(Genode::Env &env) +{ + Timer::Connection timer(env); + for (unsigned i = 0; i < 20; i++) { + timer.msleep(500); + Thread::trace(String<32>(i, " ", Trace::timestamp()).string()); + } + env.parent().exit(0); +} diff --git a/repos/os/src/test/trace_logger/target.mk b/repos/os/src/test/trace_logger/target.mk new file mode 100644 index 0000000000..5febf0e7ef --- /dev/null +++ b/repos/os/src/test/trace_logger/target.mk @@ -0,0 +1,3 @@ +TARGET = test-trace_logger +SRC_CC = main.cc +LIBS += base