sculpt: cache runtime-config info for GUI

Instead of parsing the runtime's configuration each time when generating
the graph dialog (e.g., when changing the hover state), extract the
relevant information only on configuration changes.
This commit is contained in:
Norman Feske 2019-02-22 23:20:58 +01:00 committed by Christian Helmuth
parent 010caa6236
commit d0e1ddb8c2
3 changed files with 224 additions and 76 deletions

View File

@ -25,6 +25,7 @@
#include <xml.h>
#include <model/capacity.h>
#include <model/popup.h>
#include <model/runtime_config.h>
namespace Sculpt { struct Graph; }
@ -33,7 +34,8 @@ struct Sculpt::Graph
{
Env &_env;
Runtime_state &_runtime_state;
Runtime_state &_runtime_state;
Runtime_config const &_runtime_config;
Storage_target const &_sculpt_partition;
@ -43,18 +45,8 @@ struct Sculpt::Graph
Expanding_reporter _graph_dialog_reporter { _env, "dialog", "runtime_view_dialog" };
/*
* Even though the runtime configuration is generate by the sculpt
* manager, we still obtain it as a separate ROM session to keep both
* parts decoupled.
*/
Attached_rom_dataspace _runtime_config_rom { _env, "config -> managed/runtime" };
Attached_rom_dataspace _hover_rom { _env, "runtime_view_hover" };
Signal_handler<Graph> _runtime_config_handler {
_env.ep(), *this, &Graph::_handle_runtime_config };
Signal_handler<Graph> _hover_handler {
_env.ep(), *this, &Graph::_handle_hover };
@ -69,51 +61,6 @@ struct Sculpt::Graph
bool _hovered = false;
typedef Start_name Node_name;
/**
* Return component name targeted by the first route of the start node
*/
static Node_name _primary_dependency(Xml_node const start)
{
if (!start.has_sub_node("route"))
return Node_name();
Xml_node const route = start.sub_node("route");
if (!route.has_sub_node("service"))
return Node_name();
Xml_node const service = route.sub_node("service");
if (service.has_sub_node("child")) {
Xml_node const child = service.sub_node("child");
return child.attribute_value("name", Node_name());
}
return Node_name();
}
template <typename FN>
static void _for_each_secondary_dep(Xml_node const start, FN const &fn)
{
if (!start.has_sub_node("route"))
return;
Xml_node const route = start.sub_node("route");
bool first_route = true;
route.for_each_sub_node("service", [&] (Xml_node service) {
if (!first_route && service.has_sub_node("child")) {
Xml_node const child = service.sub_node("child");
fn(child.attribute_value("name", Start_name()));
}
first_route = false;
});
}
void _gen_selected_node_content(Xml_generator &xml, Start_name const &name,
Runtime_state::Info const &info) const
{
@ -147,8 +94,6 @@ struct Sculpt::Graph
void _gen_graph_dialog()
{
Xml_node const config = _runtime_config_rom.xml();
_graph_dialog_reporter.generate([&] (Xml_generator &xml) {
xml.node("depgraph", [&] () {
@ -164,9 +109,11 @@ struct Sculpt::Graph
xml.attribute("text", "+"); }); });
}
config.for_each_sub_node("start", [&] (Xml_node start) {
typedef Runtime_config::Component Component;
Start_name const name = start.attribute_value("name", Start_name());
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = component.name;
/* omit sculpt's helpers from the graph */
bool const blacklisted = (name == "runtime_view"
@ -179,7 +126,7 @@ struct Sculpt::Graph
gen_named_node(xml, "frame", name, [&] () {
Node_name primary_dep = _primary_dependency(start);
Start_name primary_dep = component.primary_dependency;
if (primary_dep == "default_fs_rw")
primary_dep = _sculpt_partition.fs();
@ -206,19 +153,19 @@ struct Sculpt::Graph
});
});
config.for_each_sub_node("start", [&] (Xml_node start) {
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = start.attribute_value("name", Start_name());
Start_name const name = component.name;
Runtime_state::Info const info = _runtime_state.info(name);
bool const show_details = info.selected;
if (show_details) {
_for_each_secondary_dep(start, [&] (Start_name const &dep) {
component.for_each_secondary_dep([&] (Start_name const &dep) {
xml.node("dep", [&] () {
xml.attribute("node", name);
xml.attribute("on", dep);
xml.attribute("on", dep);
});
});
}
@ -227,13 +174,6 @@ struct Sculpt::Graph
});
}
void _handle_runtime_config()
{
_runtime_config_rom.update();
_gen_graph_dialog();
}
void _handle_hover()
{
_hover_rom.update();
@ -284,15 +224,15 @@ struct Sculpt::Graph
Graph(Env &env,
Runtime_state &runtime_state,
Runtime_config const &runtime_config,
Storage_target const &sculpt_partition,
Popup::State const &popup_state,
Depot_deploy::Children const &deploy_children)
:
_env(env), _runtime_state(runtime_state),
_env(env), _runtime_state(runtime_state), _runtime_config(runtime_config),
_sculpt_partition(sculpt_partition),
_popup_state(popup_state), _deploy_children(deploy_children)
{
_runtime_config_rom.sigh(_runtime_config_handler);
_hover_rom.sigh(_hover_handler);
}
@ -339,6 +279,8 @@ struct Sculpt::Graph
_gen_graph_dialog();
}
void gen_dialog() { _gen_graph_dialog(); }
};
#endif /* _GRAPH_H_ */

View File

@ -364,6 +364,35 @@ struct Sculpt::Main : Input_event_handler,
void _handle_runtime_state();
/****************************************
** Cached model of the runtime config **
****************************************/
/*
* Even though the runtime configuration is generated by the sculpt
* manager, we still obtain it as a separate ROM session to keep the GUI
* part decoupled from the lower-level runtime configuration generator.
*/
Attached_rom_dataspace _runtime_config_rom { _env, "config -> managed/runtime" };
Signal_handler<Main> _runtime_config_handler {
_env.ep(), *this, &Main::_handle_runtime_config };
Runtime_config _cached_runtime_config { _heap };
void _handle_runtime_config()
{
_runtime_config_rom.update();
_cached_runtime_config.update_from_xml(_runtime_config_rom.xml());
_graph.gen_dialog();
}
/****************************
** Interactive operations **
****************************/
Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase };
Hovered::Dialog _last_clicked { Hovered::NONE };
@ -538,8 +567,8 @@ struct Sculpt::Main : Input_event_handler,
Popup _popup { };
Graph _graph { _env, _runtime_state, _storage._sculpt_partition,
_popup.state, _deploy._children };
Graph _graph { _env, _runtime_state, _cached_runtime_config,
_storage._sculpt_partition, _popup.state, _deploy._children };
Child_state _runtime_view_state {
"runtime_view", Ram_quota{8*1024*1024}, Cap_quota{200} };
@ -549,6 +578,7 @@ struct Sculpt::Main : Input_event_handler,
{
_manual_deploy_rom.sigh(_manual_deploy_handler);
_runtime_state_rom.sigh(_runtime_state_handler);
_runtime_config_rom.sigh(_runtime_config_handler);
_nitpicker_displays.sigh(_nitpicker_displays_handler);
/*
@ -573,6 +603,7 @@ struct Sculpt::Main : Input_event_handler,
_storage.handle_storage_devices_update();
_deploy.handle_deploy();
_handle_pci_devices();
_handle_runtime_config();
/*
* Generate initial config/managed/deploy configuration

View File

@ -0,0 +1,175 @@
/*
* \brief Cached information of the current runtime configuration
* \author Norman Feske
* \date 2019-02-22
*/
/*
* Copyright (C) 2019 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 _MODEL__RUNTIME_CONFIG_H_
#define _MODEL__RUNTIME_CONFIG_H_
/* Genode includes */
#include <util/xml_node.h>
#include <util/list_model.h>
/* local includes */
#include <types.h>
namespace Sculpt { class Runtime_config; }
class Sculpt::Runtime_config
{
private:
Allocator &_alloc;
/**
* Return component name targeted by the first route of the start node
*/
static Start_name _primary_dependency(Xml_node const start)
{
if (!start.has_sub_node("route"))
return Start_name();
Xml_node const route = start.sub_node("route");
if (!route.has_sub_node("service"))
return Start_name();
Xml_node const service = route.sub_node("service");
if (service.has_sub_node("child")) {
Xml_node const child = service.sub_node("child");
return child.attribute_value("name", Start_name());
}
return Start_name();
}
public:
struct Component : List_model<Component>::Element
{
Start_name const name;
Start_name primary_dependency { };
struct Child_dep : List_model<Child_dep>::Element
{
Start_name const to_name;
Child_dep(Start_name to_name) : to_name(to_name) { }
struct Update_policy
{
typedef Child_dep Element;
Allocator &_alloc;
Update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Child_dep &elem) { destroy(_alloc, &elem); }
static Start_name _to_name(Xml_node node)
{
Start_name result { };
node.with_sub_node("child", [&] (Xml_node child) {
result = child.attribute_value("name", Start_name()); });
return result;
}
Child_dep &create_element(Xml_node node)
{
return *new (_alloc) Child_dep(_to_name(node));
}
void update_element(Child_dep &, Xml_node) { }
static bool element_matches_xml_node(Child_dep const &elem, Xml_node node)
{
return _to_name(node) == elem.to_name;
}
static bool node_is_element(Xml_node node)
{
return _to_name(node).valid();
}
};
};
/* dependencies on other child components */
List_model<Child_dep> child_deps { };
template <typename FN>
void for_each_secondary_dep(FN const &fn) const
{
child_deps.for_each([&] (Child_dep const &dep) {
if (dep.to_name != primary_dependency)
fn(dep.to_name); });
}
Component(Start_name const &name) : name(name) { }
struct Update_policy
{
typedef Component Element;
Allocator &_alloc;
Update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Component &elem)
{
destroy(_alloc, &elem);
}
Component &create_element(Xml_node node)
{
return *new (_alloc)
Component(node.attribute_value("name", Start_name()));
}
void update_element(Component &elem, Xml_node node)
{
elem.primary_dependency = _primary_dependency(node);
Child_dep::Update_policy policy(_alloc);
node.with_sub_node("route", [&] (Xml_node route) {
elem.child_deps.update_from_xml(policy, route); });
}
static bool element_matches_xml_node(Component const &elem, Xml_node node)
{
return node.attribute_value("name", Start_name()) == elem.name;
}
static bool node_is_element(Xml_node node) { return node.has_type("start"); }
};
};
private:
List_model<Component> _components { };
public:
Runtime_config(Allocator &alloc) : _alloc(alloc) { }
void update_from_xml(Xml_node config)
{
Component::Update_policy policy(_alloc);
_components.update_from_xml(policy, config);
}
template <typename FN>
void for_each_component(FN const &fn) const { _components.for_each(fn); }
};
#endif /* _MODEL__RUNTIME_CONFIG_H_ */