diff options
author | Robin Gareus <robin@gareus.org> | 2016-05-03 14:26:25 +0200 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2016-05-03 14:27:36 +0200 |
commit | 6f858b51d2578eb6f505fb5f2a05c1fefb47816f (patch) | |
tree | 3c74228c0b06ff523dd2632853a21610d86fe93a /gtk2_ardour | |
parent | 255b5174c4f162006d564327fb54f48bbd7ddc09 (diff) |
speed up track creation
For every added Trackview/Mixerstrip, Ardour looks up GUI properties which
results in a total of 13 calls for the initial default items per track:
("height", "visible", "layer-display", "strip-width")
Since the tracks don't yet exist, the properties don't either.
Every lookup result in iterating over all all XMLNotes and for every
"Object". ->property ("id") and ->value () allocates memory.
Adding 64 tracks to an empty session results in 528293 string
allocations and deallocations in XMLNode::property() taking ~30%
of the track creation time.
This commit XMLnode's const method to prevent memory allocation
and caches a pointer to the XMLNode* to skip iterating over object
state.
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/gui_object.cc | 87 | ||||
-rw-r--r-- | gtk2_ardour/gui_object.h | 26 |
2 files changed, 61 insertions, 52 deletions
diff --git a/gtk2_ardour/gui_object.cc b/gtk2_ardour/gui_object.cc index 3128e61f3a..5ea94f9c0c 100644 --- a/gtk2_ardour/gui_object.cc +++ b/gtk2_ardour/gui_object.cc @@ -25,34 +25,22 @@ using std::string; -const string GUIObjectState::xml_node_name (X_("GUIObjectState")); - -GUIObjectState::GUIObjectState () - : _state (X_("GUIObjectState")) -{ - -} - -XMLNode * +/*static*/ XMLNode * GUIObjectState::get_node (const XMLNode* parent, const string& id) { XMLNodeList const & children = parent->children (); for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { - if ((*i)->name() != X_("Object")) { continue; } - - XMLProperty* p = (*i)->property (X_("id")); - if (p && p->value() == id) { + if ((*i)->has_property_with_value(X_("id"), id)) { return *i; } } - return 0; } -XMLNode * +/*static*/ XMLNode * GUIObjectState::get_or_add_node (XMLNode* parent, const string& id) { XMLNode* child = get_node (parent, id); @@ -61,46 +49,52 @@ GUIObjectState::get_or_add_node (XMLNode* parent, const string& id) child->add_property (X_("id"), id); parent->add_child_nocopy (*child); } - return child; } + +const string GUIObjectState::xml_node_name (X_("GUIObjectState")); + +GUIObjectState::GUIObjectState () + : _state (X_("GUIObjectState")) +{ +} + XMLNode * GUIObjectState::get_or_add_node (const string& id) { - return get_or_add_node (&_state, id); + std::map <std::string, XMLNode*>::iterator i = object_map.find (id); + if (i != object_map.end()) { + return i->second; + } + //assert (get_node (&_state, id) == 0); // XXX + XMLNode* child = new XMLNode (X_("Object")); + child->add_property (X_("id"), id); + _state.add_child_nocopy (*child); + object_map[id] = child; + return child; } -/** Remove node with provided id. - * @param id property of Object node to look for. - */ - void GUIObjectState::remove_node (const std::string& id) { + object_map.erase (id); _state.remove_nodes_and_delete(X_("id"), id ); } -/** Get a string from our state. - * @param id property of Object node to look for. - * @param prop_name name of the Object property to return. - * @param empty if non-0, filled in with true if the property is currently non-existant, otherwise false. - * @return value of property `prop_name', or empty. - */ - string GUIObjectState::get_string (const string& id, const string& prop_name, bool* empty) { - XMLNode* child = get_node (&_state, id); - - if (!child) { + std::map <std::string, XMLNode*>::const_iterator i = object_map.find (id); + if (i == object_map.end()) { + //assert (get_node (&_state, id) == 0); // XXX if (empty) { *empty = true; } return string (); } - XMLProperty* p = child->property (prop_name); + const XMLProperty* p (i->second->property (prop_name)); if (!p) { if (empty) { *empty = true; @@ -128,7 +122,20 @@ GUIObjectState::set_state (const XMLNode& node) return -1; } + object_map.clear (); _state = node; + + XMLNodeList const & children (_state.children ()); + for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { + if ((*i)->name() != X_("Object")) { + continue; + } + const XMLProperty* prop = (*i)->property (X_("id")); + if (!prop) { + continue; + } + object_map[prop->value ()] = *i; + } return 0; } @@ -142,19 +149,9 @@ std::list<string> GUIObjectState::all_ids () const { std::list<string> ids; - XMLNodeList const & children = _state.children (); - for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) { - if ((*i)->name() != X_("Object")) { - continue; - } - - XMLProperty* p = (*i)->property (X_("id")); - if (p) { - ids.push_back (p->value ()); - } + for (std::map <std::string, XMLNode*>::const_iterator i = object_map.begin (); + i != object_map.end (); ++i) { + ids.push_back (i->first); } - return ids; } - - diff --git a/gtk2_ardour/gui_object.h b/gtk2_ardour/gui_object.h index 39cf579fb5..16b43f31e3 100644 --- a/gtk2_ardour/gui_object.h +++ b/gtk2_ardour/gui_object.h @@ -33,12 +33,18 @@ class GUIObjectState public: GUIObjectState (); - XMLNode& get_state () const; - int set_state (const XMLNode&); - static const std::string xml_node_name; void load (const XMLNode&); + int set_state (const XMLNode&); + XMLNode& get_state () const; + + /** Get a string from our state. + * @param id property of Object node to look for. + * @param prop_name name of the Object property to return. + * @param empty if non-0, filled in with true if the property is currently non-existant, otherwise false. + * @return value of property `prop_name', or empty. + */ std::string get_string (const std::string& id, const std::string& prop_name, bool* empty = 0); template<typename T> void set_property (const std::string& id, const std::string& prop_name, const T& val) { @@ -48,17 +54,23 @@ public: child->add_property (prop_name.c_str(), s.str()); } + /** Remove node with provided id. + * @param id property of Object node to look for. + */ + void remove_node (const std::string& id); std::list<std::string> all_ids () const; - static XMLNode* get_node (const XMLNode *, const std::string &); XMLNode* get_or_add_node (const std::string &); - static XMLNode* get_or_add_node (XMLNode *, const std::string &); - void remove_node (const std::string& id); + static XMLNode* get_node (const XMLNode *, const std::string &); + static XMLNode* get_or_add_node (XMLNode *, const std::string &); private: + XMLNode _state; + // ideally we'd use a O(1) hash table here, + // but O(log(N)) is fine already. + std::map <std::string, XMLNode*> object_map; }; - #endif /* __gtk_ardour_gui_object_h__ */ |