From a172e76897157e5a0d2ebd3fa3f7f77ec38a5df0 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 1 Oct 2016 15:18:09 -0400 Subject: Defer graph compilation in atomic bundles This avoids situations like compiling a graph hundreds of times when it is loaded because it has hundreds of nodes and each event triggers a re-compile. This speeds things up dramatically, but exacerbates the theoretical problem of there not being enough time in a cycle to execute a bundle. As far as I can tell, the execute phase of events is very fast, so hundreds or thousands can easily run in a tiny fraction of the process cycle, but this still needs resolution to be truly hard real-time. What probably needs to happen is that all context and state used to process is moved to CompiledGraph and nodes do not access their own fields at all, but have some references into the CompiledGraph. This way, a compiled graph is separate from its "source code", and an old one could continue to be run while a new one is beng applied across several cycles. --- ingen/ingen.h | 8 +++++ src/server/Engine.cpp | 8 +++-- src/server/Event.hpp | 3 +- src/server/GraphImpl.cpp | 9 ++--- src/server/GraphImpl.hpp | 7 ++-- src/server/PostProcessor.cpp | 2 +- src/server/PreProcessContext.hpp | 70 +++++++++++++++++++++++++++++++++++++ src/server/PreProcessor.cpp | 14 +++++++- src/server/events/Connect.cpp | 11 +++--- src/server/events/Connect.hpp | 2 +- src/server/events/Copy.cpp | 23 ++++++------ src/server/events/Copy.hpp | 8 ++--- src/server/events/CreateBlock.cpp | 10 +++--- src/server/events/CreateBlock.hpp | 2 +- src/server/events/CreateGraph.cpp | 13 ++++--- src/server/events/CreateGraph.hpp | 2 +- src/server/events/CreatePort.cpp | 2 +- src/server/events/CreatePort.hpp | 2 +- src/server/events/Delete.cpp | 21 ++++++----- src/server/events/Delete.hpp | 2 +- src/server/events/Delta.cpp | 13 ++++--- src/server/events/Delta.hpp | 2 +- src/server/events/Disconnect.cpp | 11 ++++-- src/server/events/Disconnect.hpp | 2 +- src/server/events/DisconnectAll.cpp | 11 ++++-- src/server/events/DisconnectAll.hpp | 2 +- src/server/events/Get.cpp | 2 +- src/server/events/Get.hpp | 2 +- src/server/events/Mark.cpp | 27 ++++++++++++-- src/server/events/Mark.hpp | 11 ++++-- src/server/events/Move.cpp | 2 +- src/server/events/Move.hpp | 2 +- src/server/events/SetPortValue.cpp | 2 +- src/server/events/SetPortValue.hpp | 2 +- src/server/events/Undo.cpp | 2 +- src/server/events/Undo.hpp | 2 +- 36 files changed, 233 insertions(+), 81 deletions(-) create mode 100644 src/server/PreProcessContext.hpp diff --git a/ingen/ingen.h b/ingen/ingen.h index e4a36ade..11fd592a 100644 --- a/ingen/ingen.h +++ b/ingen/ingen.h @@ -34,6 +34,14 @@ # define INGEN_API #endif +#ifndef INGEN_WARN_UNUSED_RESULT +# if __GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 4 +# define INGEN_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define INGEN_WARN_UNUSED_RESULT +# endif +#endif + #define INGEN_NS "http://drobilla.net/ns/ingen#" #define INGEN__Arc INGEN_NS "Arc" diff --git a/src/server/Engine.cpp b/src/server/Engine.cpp index 893f6f92..0b468ce1 100644 --- a/src/server/Engine.cpp +++ b/src/server/Engine.cpp @@ -47,6 +47,7 @@ #include "GraphImpl.hpp" #include "LV2Options.hpp" #include "PostProcessor.hpp" +#include "PreProcessContext.hpp" #include "PreProcessor.hpp" #include "RunContext.hpp" #include "ThreadManager.hpp" @@ -374,9 +375,10 @@ Engine::activate() *this, SPtr(), -1, 0, Raul::Path("/"), graph_properties); // Execute in "fake" process context (we are single threaded) - RunContext context(run_context()); - ev.pre_process(); - ev.execute(context); + PreProcessContext pctx; + RunContext rctx(run_context()); + ev.pre_process(pctx); + ev.execute(rctx); ev.post_process(); _root_graph = ev.graph(); diff --git a/src/server/Event.hpp b/src/server/Event.hpp index 8ed25c0f..203e5d1d 100644 --- a/src/server/Event.hpp +++ b/src/server/Event.hpp @@ -35,6 +35,7 @@ namespace Server { class Engine; class RunContext; +class PreProcessContext; /** An event (command) to perform some action on Ingen. * @@ -60,7 +61,7 @@ public: enum class Execution { NORMAL, BLOCK, UNBLOCK }; /** Pre-process event before execution (non-realtime). */ - virtual bool pre_process() = 0; + virtual bool pre_process(PreProcessContext& ctx) = 0; /** Execute this event in the audio thread (realtime). */ virtual void execute(RunContext& context) = 0; diff --git a/src/server/GraphImpl.cpp b/src/server/GraphImpl.cpp index bdd0a69a..c1ee6a2b 100644 --- a/src/server/GraphImpl.cpp +++ b/src/server/GraphImpl.cpp @@ -297,14 +297,15 @@ GraphImpl::has_arc(const PortImpl* tail, const PortImpl* dst_port) const return (i != _arcs.end()); } -void -GraphImpl::set_compiled_graph(CompiledGraph* cg) +CompiledGraph* +GraphImpl::swap_compiled_graph(CompiledGraph* cg) { - if (_compiled_graph && _compiled_graph != cg) { - _engine.maid()->dispose(_compiled_graph); + CompiledGraph* const old = _compiled_graph; + if (old && cg != old) { _engine.reset_load(); } _compiled_graph = cg; + return old; } uint32_t diff --git a/src/server/GraphImpl.hpp b/src/server/GraphImpl.hpp index 124614de..f7d0be32 100644 --- a/src/server/GraphImpl.hpp +++ b/src/server/GraphImpl.hpp @@ -19,6 +19,8 @@ #include +#include "ingen/ingen.h" + #include "BlockImpl.hpp" #include "CompiledGraph.hpp" #include "DuplexPort.hpp" @@ -160,7 +162,8 @@ public: bool has_arc(const PortImpl* tail, const PortImpl* head) const; - void set_compiled_graph(CompiledGraph* cp); + /** Set a new compiled graph to run, and return the old one. */ + CompiledGraph* swap_compiled_graph(CompiledGraph* cp) INGEN_WARN_UNUSED_RESULT; Raul::Array* external_ports() { return _ports; } void external_ports(Raul::Array* pa) { _ports = pa; } @@ -185,7 +188,7 @@ private: Ports _inputs; ///< Pre-process thread only Ports _outputs; ///< Pre-process thread only Blocks _blocks; ///< Pre-process thread only - bool _process; + bool _process; ///< True iff graph is enabled }; } // namespace Server diff --git a/src/server/PostProcessor.cpp b/src/server/PostProcessor.cpp index 65323f7f..6c709518 100644 --- a/src/server/PostProcessor.cpp +++ b/src/server/PostProcessor.cpp @@ -30,7 +30,7 @@ class Sentinel : public Event { public: Sentinel(Engine& engine) : Event(engine) {} - bool pre_process() { return false; } + bool pre_process(PreProcessContext& ctx) { return false; } void execute(RunContext& context) {} void post_process() {} }; diff --git a/src/server/PreProcessContext.hpp b/src/server/PreProcessContext.hpp new file mode 100644 index 00000000..bf1115e8 --- /dev/null +++ b/src/server/PreProcessContext.hpp @@ -0,0 +1,70 @@ +/* + This file is part of Ingen. + Copyright 2007-2016 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_ENGINE_PREPROCESSCONTEXT_HPP +#define INGEN_ENGINE_PREPROCESSCONTEXT_HPP + +#include + +#include "GraphImpl.hpp" + +namespace Ingen { +namespace Server { + +/** Event pre-processing context. + * + * \ingroup engine + */ +class PreProcessContext +{ +public: + typedef std::unordered_set DirtyGraphs; + + /** Return true iff an atomic bundle is currently being pre-processed. */ + bool in_bundle() const { return _in_bundle; } + + /** Set/unset atomic bundle flag. */ + void set_in_bundle(bool b) { _in_bundle = b; } + + /** Return true iff graph should be compiled now (after a change). + * + * This may return false when an atomic bundle is deferring compilation, in + * which case the graph is flagged as dirty for later compilation. + */ + bool must_compile(GraphImpl* graph) { + if (!graph->enabled()) { + return false; + } else if (_in_bundle) { + _dirty_graphs.insert(graph); + return false; + } else { + return true; + } + } + + /** Return all graphs that require compilation after an atomic bundle. */ + const DirtyGraphs& dirty_graphs() const { return _dirty_graphs; } + DirtyGraphs& dirty_graphs() { return _dirty_graphs; } + +private: + DirtyGraphs _dirty_graphs; + bool _in_bundle = false; +}; + +} // namespace Server +} // namespace Ingen + +#endif // INGEN_ENGINE_PREPROCESSCONTEXT_HPP diff --git a/src/server/PreProcessor.cpp b/src/server/PreProcessor.cpp index f0008afc..9933bde2 100644 --- a/src/server/PreProcessor.cpp +++ b/src/server/PreProcessor.cpp @@ -18,10 +18,12 @@ #include "ingen/AtomSink.hpp" #include "ingen/AtomWriter.hpp" +#include "ingen/Configuration.hpp" #include "Engine.hpp" #include "Event.hpp" #include "PostProcessor.hpp" +#include "PreProcessContext.hpp" #include "PreProcessor.hpp" #include "RunContext.hpp" #include "ThreadManager.hpp" @@ -131,6 +133,14 @@ PreProcessor::process(RunContext& context, PostProcessor& dest, size_t limit) } if (n_processed > 0) { + Engine& engine = context.engine(); + if (engine.world()->conf().option("trace").get()) { + const uint64_t start = engine.cycle_start_time(context); + const uint64_t end = engine.current_time(context); + fprintf(stderr, "Processed %zu events in %zu us\n", + n_processed, end - start); + } + Event* next = (Event*)last->next(); last->next(NULL); dest.append(context, head, last); @@ -149,6 +159,8 @@ PreProcessor::process(RunContext& context, PostProcessor& dest, size_t limit) void PreProcessor::run() { + PreProcessContext ctx; + UndoStack& undo_stack = *_engine.undo_stack(); UndoStack& redo_stack = *_engine.redo_stack(); AtomWriter undo_writer( @@ -168,7 +180,7 @@ PreProcessor::run() } assert(!ev->is_prepared()); - if (ev->pre_process()) { + if (ev->pre_process(ctx)) { switch (ev->get_mode()) { case Event::Mode::NORMAL: case Event::Mode::REDO: diff --git a/src/server/events/Connect.cpp b/src/server/events/Connect.cpp index 17fa640f..35084ea6 100644 --- a/src/server/events/Connect.cpp +++ b/src/server/events/Connect.cpp @@ -26,8 +26,9 @@ #include "InputPort.hpp" #include "OutputPort.hpp" #include "PortImpl.hpp" -#include "types.hpp" +#include "PreProcessContext.hpp" #include "internals/BlockDelay.hpp" +#include "types.hpp" namespace Ingen { namespace Server { @@ -49,7 +50,7 @@ Connect::Connect(Engine& engine, {} bool -Connect::pre_process() +Connect::pre_process(PreProcessContext& ctx) { std::lock_guard lock(_engine.store()->mutex()); @@ -125,7 +126,7 @@ Connect::pre_process() tail_block->dependants().insert(head_block); } - if (_graph->enabled()) { + if (ctx.must_compile(_graph)) { if (!(_compiled_graph = CompiledGraph::compile(_graph))) { head_block->providers().erase(tail_block); tail_block->dependants().erase(head_block); @@ -161,7 +162,7 @@ Connect::execute(RunContext& context) } _head->connect_buffers(); if (_compiled_graph) { - _graph->set_compiled_graph(_compiled_graph); + _compiled_graph = _graph->swap_compiled_graph(_compiled_graph); } } } @@ -181,6 +182,8 @@ Connect::post_process() Node::path_to_uri(_tail_path), _tail_remove, _tail_add); } } + + delete _compiled_graph; } void diff --git a/src/server/events/Connect.hpp b/src/server/events/Connect.hpp index 84b2854b..9b98b167 100644 --- a/src/server/events/Connect.hpp +++ b/src/server/events/Connect.hpp @@ -52,7 +52,7 @@ public: const Raul::Path& tail, const Raul::Path& head); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/Copy.cpp b/src/server/events/Copy.cpp index 8959e4e1..03519610 100644 --- a/src/server/events/Copy.cpp +++ b/src/server/events/Copy.cpp @@ -26,6 +26,7 @@ #include "Engine.hpp" #include "EnginePort.hpp" #include "GraphImpl.hpp" +#include "PreProcessContext.hpp" #include "events/Copy.hpp" namespace Ingen { @@ -48,7 +49,7 @@ Copy::Copy(Engine& engine, {} bool -Copy::pre_process() +Copy::pre_process(PreProcessContext& ctx) { std::lock_guard lock(_engine.store()->mutex()); @@ -69,16 +70,16 @@ Copy::pre_process() if (Node::uri_is_path(_new_uri)) { // Copy to path within the engine - return engine_to_engine(); + return engine_to_engine(ctx); } else if (_new_uri.scheme() == "file") { // Copy to filesystem path (i.e. save) - return engine_to_filesystem(); + return engine_to_filesystem(ctx); } else { return Event::pre_process_done(Status::BAD_REQUEST); } } else if (_old_uri.scheme() == "file") { if (Node::uri_is_path(_new_uri)) { - filesystem_to_engine(); + filesystem_to_engine(ctx); } else { // Ingen is not your file manager return Event::pre_process_done(Status::BAD_REQUEST); @@ -89,7 +90,7 @@ Copy::pre_process() } bool -Copy::engine_to_engine() +Copy::engine_to_engine(PreProcessContext& ctx) { // Only support a single source for now const Raul::Path new_path = Node::uri_to_path(_new_uri); @@ -125,7 +126,7 @@ Copy::engine_to_engine() _engine.store()->add(_block); // Compile graph with new block added for insertion in audio thread - if (_parent->enabled()) { + if (ctx.must_compile(_parent)) { _compiled_graph = CompiledGraph::compile(_parent); } @@ -142,7 +143,7 @@ ends_with(const std::string& str, const std::string& end) } bool -Copy::engine_to_filesystem() +Copy::engine_to_filesystem(PreProcessContext& ctx) { // Ensure source is a graph SPtr graph = dynamic_ptr_cast(_old_block); @@ -168,7 +169,7 @@ Copy::engine_to_filesystem() } bool -Copy::filesystem_to_engine() +Copy::filesystem_to_engine(PreProcessContext& ctx) { if (!_engine.world()->parser()) { return Event::pre_process_done(Status::INTERNAL_ERROR); @@ -196,9 +197,8 @@ Copy::filesystem_to_engine() void Copy::execute(RunContext& context) { - if (_block) { - _parent->set_compiled_graph(_compiled_graph); - _compiled_graph = NULL; // Graph takes ownership + if (_block && _compiled_graph) { + _compiled_graph = _parent->swap_compiled_graph(_compiled_graph); } } @@ -209,6 +209,7 @@ Copy::post_process() if (respond() == Status::SUCCESS) { _engine.broadcaster()->copy(_old_uri, _new_uri); } + delete _compiled_graph; } void diff --git a/src/server/events/Copy.hpp b/src/server/events/Copy.hpp index 68ee31da..55310757 100644 --- a/src/server/events/Copy.hpp +++ b/src/server/events/Copy.hpp @@ -46,15 +46,15 @@ public: const Raul::URI& old_uri, const Raul::URI& new_uri); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); private: - bool engine_to_engine(); - bool engine_to_filesystem(); - bool filesystem_to_engine(); + bool engine_to_engine(PreProcessContext& ctx); + bool engine_to_filesystem(PreProcessContext& ctx); + bool filesystem_to_engine(PreProcessContext& ctx); const Raul::URI _old_uri; const Raul::URI _new_uri; diff --git a/src/server/events/CreateBlock.cpp b/src/server/events/CreateBlock.cpp index d1060fa4..231df4e2 100644 --- a/src/server/events/CreateBlock.cpp +++ b/src/server/events/CreateBlock.cpp @@ -28,6 +28,7 @@ #include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" +#include "PreProcessContext.hpp" namespace Ingen { namespace Server { @@ -53,7 +54,7 @@ CreateBlock::~CreateBlock() } bool -CreateBlock::pre_process() +CreateBlock::pre_process(PreProcessContext& ctx) { typedef Resource::Properties::const_iterator iterator; @@ -137,7 +138,7 @@ CreateBlock::pre_process() /* Compile graph with new block added for insertion in audio thread TODO: Since the block is not connected at this point, a full compilation could be avoided and the block simply appended. */ - if (_graph->enabled()) { + if (ctx.must_compile(_graph)) { _compiled_graph = CompiledGraph::compile(_graph); } @@ -149,9 +150,8 @@ CreateBlock::pre_process() void CreateBlock::execute(RunContext& context) { - if (_status == Status::SUCCESS) { - _graph->set_compiled_graph(_compiled_graph); - _compiled_graph = NULL; // Graph takes ownership + if (_status == Status::SUCCESS && _compiled_graph) { + _compiled_graph = _graph->swap_compiled_graph(_compiled_graph); } } diff --git a/src/server/events/CreateBlock.hpp b/src/server/events/CreateBlock.hpp index 00205c6a..b0aa6aa4 100644 --- a/src/server/events/CreateBlock.hpp +++ b/src/server/events/CreateBlock.hpp @@ -47,7 +47,7 @@ public: ~CreateBlock(); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/CreateGraph.cpp b/src/server/events/CreateGraph.cpp index a2e4e6c4..ae359e17 100644 --- a/src/server/events/CreateGraph.cpp +++ b/src/server/events/CreateGraph.cpp @@ -23,6 +23,7 @@ #include "Driver.hpp" #include "Engine.hpp" #include "GraphImpl.hpp" +#include "PreProcessContext.hpp" #include "events/CreateGraph.hpp" #include "events/CreatePort.hpp" @@ -92,7 +93,7 @@ CreateGraph::build_child_events() } bool -CreateGraph::pre_process() +CreateGraph::pre_process(PreProcessContext& ctx) { if (_engine.store()->get(_path)) { return Event::pre_process_done(Status::EXISTS, _path); @@ -163,6 +164,8 @@ CreateGraph::pre_process() _parent->add_block(*_graph); if (_parent->enabled()) { _graph->enable(); + } + if (ctx.must_compile(_parent)) { _compiled_graph = CompiledGraph::compile(_parent); } } @@ -179,7 +182,7 @@ CreateGraph::pre_process() // Build and pre-process child events to create standard ports build_child_events(); for (SPtr ev : _child_events) { - ev->pre_process(); + ev->pre_process(ctx); } return Event::pre_process_done(Status::SUCCESS); @@ -189,8 +192,8 @@ void CreateGraph::execute(RunContext& context) { if (_graph) { - if (_parent) { - _parent->set_compiled_graph(_compiled_graph); + if (_parent && _compiled_graph) { + _compiled_graph = _parent->swap_compiled_graph(_compiled_graph); } for (SPtr ev : _child_events) { @@ -213,6 +216,8 @@ CreateGraph::post_process() } } _child_events.clear(); + + delete _compiled_graph; } void diff --git a/src/server/events/CreateGraph.hpp b/src/server/events/CreateGraph.hpp index 9cae32ba..794742ac 100644 --- a/src/server/events/CreateGraph.hpp +++ b/src/server/events/CreateGraph.hpp @@ -44,7 +44,7 @@ public: const Raul::Path& path, const Resource::Properties& properties); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp index 9384ce09..60e57a71 100644 --- a/src/server/events/CreatePort.cpp +++ b/src/server/events/CreatePort.cpp @@ -86,7 +86,7 @@ CreatePort::CreatePort(Engine& engine, } bool -CreatePort::pre_process() +CreatePort::pre_process(PreProcessContext& ctx) { if (_port_type == PortType::UNKNOWN) { return Event::pre_process_done(Status::UNKNOWN_TYPE, _path); diff --git a/src/server/events/CreatePort.hpp b/src/server/events/CreatePort.hpp index c002df59..f3e2092d 100644 --- a/src/server/events/CreatePort.hpp +++ b/src/server/events/CreatePort.hpp @@ -51,7 +51,7 @@ public: const Raul::Path& path, const Resource::Properties& properties); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp index 0d202f84..bab2594a 100644 --- a/src/server/events/Delete.cpp +++ b/src/server/events/Delete.cpp @@ -29,6 +29,7 @@ #include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" +#include "PreProcessContext.hpp" namespace Ingen { namespace Server { @@ -54,10 +55,11 @@ Delete::Delete(Engine& engine, Delete::~Delete() { delete _disconnect_event; + delete _compiled_graph; } bool -Delete::pre_process() +Delete::pre_process(PreProcessContext& ctx) { if (_path.is_root() || _path == "/control" || _path == "/notify") { return Event::pre_process_done(Status::NOT_DELETABLE, _path); @@ -91,19 +93,22 @@ Delete::pre_process() if (_block) { parent->remove_block(*_block); _disconnect_event = new DisconnectAll(_engine, parent, _block.get()); - _disconnect_event->pre_process(); + _disconnect_event->pre_process(ctx); - if (parent->enabled()) { + if (ctx.must_compile(parent)) { _compiled_graph = CompiledGraph::compile(parent); } } else if (_port) { parent->remove_port(*_port); _disconnect_event = new DisconnectAll(_engine, parent, _port.get()); - _disconnect_event->pre_process(); + _disconnect_event->pre_process(ctx); - if (parent->enabled()) { + if (ctx.must_compile(parent)) { _compiled_graph = CompiledGraph::compile(parent); - _ports_array = parent->build_ports_array(); + } + + if (parent->enabled()) { + _ports_array = parent->build_ports_array(); assert(_ports_array->size() == parent->num_ports_non_rt()); } @@ -137,8 +142,8 @@ Delete::execute(RunContext& context) } } - if (parent) { - parent->set_compiled_graph(_compiled_graph); + if (parent && _compiled_graph) { + _compiled_graph = parent->swap_compiled_graph(_compiled_graph); } } diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp index 5cd40b14..fd797804 100644 --- a/src/server/events/Delete.hpp +++ b/src/server/events/Delete.hpp @@ -54,7 +54,7 @@ public: ~Delete(); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp index 8c94fac7..62d08367 100644 --- a/src/server/events/Delta.cpp +++ b/src/server/events/Delta.cpp @@ -79,6 +79,7 @@ Delta::~Delta() delete s; delete _create_event; + delete _compiled_graph; } void @@ -98,7 +99,6 @@ Delta::add_set_event(const char* port_symbol, _engine, _request_client, _request_id, _time, port, Atom(size, type, value), true); - ev->pre_process(); _set_events.push_back(ev); } @@ -155,7 +155,7 @@ get_file_node(LilvWorld* lworld, const URIs& uris, const Atom& value) */ bool -Delta::pre_process() +Delta::pre_process(PreProcessContext& ctx) { const Ingen::URIs& uris = _engine.world()->uris(); @@ -231,7 +231,7 @@ Delta::pre_process() path, _properties); } if (_create_event) { - if (_create_event->pre_process()) { + if (_create_event->pre_process(ctx)) { _object = _engine.store()->get(path); // Get object for setting } else { return Event::pre_process_done(Status::CREATION_FAILED, _subject); @@ -322,7 +322,6 @@ Delta::pre_process() } else if (key == uris.ingen_value || key == uris.ingen_activity) { SetPortValue* ev = new SetPortValue( _engine, _request_client, _request_id, _time, port, value); - ev->pre_process(); _set_events.push_back(ev); } else if (key == uris.midi_binding) { if (port->is_a(PortType::CONTROL) || port->is_a(PortType::CV)) { @@ -449,6 +448,10 @@ Delta::pre_process() _types.push_back(op); } + for (auto& s : _set_events) { + s->pre_process(ctx); + } + if (poly_changed) { lock.unlock(); _poly_lock.lock(); @@ -496,7 +499,7 @@ Delta::execute(RunContext& context) if (_graph) { if (value.get()) { if (_compiled_graph) { - _graph->set_compiled_graph(_compiled_graph); + _compiled_graph = _graph->swap_compiled_graph(_compiled_graph); } _graph->enable(); } else { diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp index 24330199..9e6cbecd 100644 --- a/src/server/events/Delta.hpp +++ b/src/server/events/Delta.hpp @@ -73,7 +73,7 @@ public: uint32_t size, uint32_t type); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/Disconnect.cpp b/src/server/events/Disconnect.cpp index ed9312d5..476a0cee 100644 --- a/src/server/events/Disconnect.cpp +++ b/src/server/events/Disconnect.cpp @@ -29,6 +29,7 @@ #include "InputPort.hpp" #include "OutputPort.hpp" #include "PortImpl.hpp" +#include "PreProcessContext.hpp" #include "RunContext.hpp" #include "ThreadManager.hpp" #include "events/Disconnect.hpp" @@ -55,6 +56,7 @@ Disconnect::Disconnect(Engine& engine, Disconnect::~Disconnect() { delete _impl; + delete _compiled_graph; } Disconnect::Impl::Impl(Engine& e, @@ -112,7 +114,7 @@ Disconnect::Impl::Impl(Engine& e, } bool -Disconnect::pre_process() +Disconnect::pre_process(PreProcessContext& ctx) { std::lock_guard lock(_engine.store()->mutex()); @@ -166,8 +168,9 @@ Disconnect::pre_process() dynamic_cast(tail), dynamic_cast(head)); - if (_graph->enabled()) + if (ctx.must_compile(_graph)) { _compiled_graph = CompiledGraph::compile(_graph); + } return Event::pre_process_done(Status::SUCCESS); } @@ -204,7 +207,9 @@ Disconnect::execute(RunContext& context) { if (_status == Status::SUCCESS) { if (_impl->execute(context, true)) { - _graph->set_compiled_graph(_compiled_graph); + if (_compiled_graph) { + _compiled_graph = _graph->swap_compiled_graph(_compiled_graph); + } } else { _status = Status::NOT_FOUND; } diff --git a/src/server/events/Disconnect.hpp b/src/server/events/Disconnect.hpp index 69d9469c..19ffcf3b 100644 --- a/src/server/events/Disconnect.hpp +++ b/src/server/events/Disconnect.hpp @@ -54,7 +54,7 @@ public: ~Disconnect(); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/DisconnectAll.cpp b/src/server/events/DisconnectAll.cpp index e4866d30..2dea6a76 100644 --- a/src/server/events/DisconnectAll.cpp +++ b/src/server/events/DisconnectAll.cpp @@ -31,6 +31,7 @@ #include "InputPort.hpp" #include "OutputPort.hpp" #include "PortImpl.hpp" +#include "PreProcessContext.hpp" #include "events/Disconnect.hpp" #include "events/DisconnectAll.hpp" #include "util.hpp" @@ -76,10 +77,12 @@ DisconnectAll::~DisconnectAll() { for (auto& i : _impls) delete i; + + delete _compiled_graph; } bool -DisconnectAll::pre_process() +DisconnectAll::pre_process(PreProcessContext& ctx) { std::unique_lock lock(_engine.store()->mutex(), std::defer_lock); @@ -136,7 +139,7 @@ DisconnectAll::pre_process() dynamic_cast(a->head()))); } - if (!_deleting && _parent->enabled()) { + if (!_deleting && ctx.must_compile(_parent)) { if (!(_compiled_graph = CompiledGraph::compile(_parent))) { return Event::pre_process_done(Status::COMPILATION_FAILED); } @@ -155,7 +158,9 @@ DisconnectAll::execute(RunContext& context) } } - _parent->set_compiled_graph(_compiled_graph); + if (_compiled_graph) { + _compiled_graph = _parent->swap_compiled_graph(_compiled_graph); + } } void diff --git a/src/server/events/DisconnectAll.hpp b/src/server/events/DisconnectAll.hpp index 1ddfc536..1fc1f757 100644 --- a/src/server/events/DisconnectAll.hpp +++ b/src/server/events/DisconnectAll.hpp @@ -56,7 +56,7 @@ public: ~DisconnectAll(); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp index b018c1a9..dfa16ef5 100644 --- a/src/server/events/Get.cpp +++ b/src/server/events/Get.cpp @@ -46,7 +46,7 @@ Get::Get(Engine& engine, {} bool -Get::pre_process() +Get::pre_process(PreProcessContext& ctx) { std::lock_guard lock(_engine.store()->mutex()); diff --git a/src/server/events/Get.hpp b/src/server/events/Get.hpp index f685df21..35955d9a 100644 --- a/src/server/events/Get.hpp +++ b/src/server/events/Get.hpp @@ -47,7 +47,7 @@ public: SampleCount timestamp, const Raul::URI& uri); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context) {} void post_process(); diff --git a/src/server/events/Mark.cpp b/src/server/events/Mark.cpp index 11690487..c72cc14f 100644 --- a/src/server/events/Mark.cpp +++ b/src/server/events/Mark.cpp @@ -15,6 +15,7 @@ */ #include "Engine.hpp" +#include "PreProcessContext.hpp" #include "UndoStack.hpp" #include "events/Mark.hpp" @@ -32,8 +33,15 @@ Mark::Mark(Engine& engine, , _depth(0) {} +Mark::~Mark() +{ + for (const auto& g : _compiled_graphs) { + delete g.second; + } +} + bool -Mark::pre_process() +Mark::pre_process(PreProcessContext& ctx) { UndoStack* const stack = ((_mode == Mode::UNDO) ? _engine.redo_stack() @@ -41,10 +49,21 @@ Mark::pre_process() switch (_type) { case Type::BUNDLE_START: + ctx.set_in_bundle(true); _depth = stack->start_entry(); break; case Type::BUNDLE_END: _depth = stack->finish_entry(); + ctx.set_in_bundle(false); + if (!ctx.dirty_graphs().empty()) { + for (GraphImpl* g : ctx.dirty_graphs()) { + CompiledGraph* cg = CompiledGraph::compile(g); + if (cg) { + _compiled_graphs.insert(std::make_pair(g, cg)); + } + } + ctx.dirty_graphs().clear(); + } break; } @@ -53,7 +72,11 @@ Mark::pre_process() void Mark::execute(RunContext& context) -{} +{ + for (auto& g : _compiled_graphs) { + g.second = g.first->swap_compiled_graph(g.second); + } +} void Mark::post_process() diff --git a/src/server/events/Mark.hpp b/src/server/events/Mark.hpp index d2db0834..68ba5149 100644 --- a/src/server/events/Mark.hpp +++ b/src/server/events/Mark.hpp @@ -44,15 +44,20 @@ public: SampleCount timestamp, Type type); - bool pre_process(); + ~Mark(); + + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); Execution get_execution() const; private: - Type _type; - int _depth; + typedef std::map CompiledGraphs; + + CompiledGraphs _compiled_graphs; + Type _type; + int _depth; }; } // namespace Events diff --git a/src/server/events/Move.cpp b/src/server/events/Move.cpp index d6eae6d6..aee74ab6 100644 --- a/src/server/events/Move.cpp +++ b/src/server/events/Move.cpp @@ -46,7 +46,7 @@ Move::~Move() } bool -Move::pre_process() +Move::pre_process(PreProcessContext& ctx) { std::lock_guard lock(_engine.store()->mutex()); diff --git a/src/server/events/Move.hpp b/src/server/events/Move.hpp index ef308a01..c45c73aa 100644 --- a/src/server/events/Move.hpp +++ b/src/server/events/Move.hpp @@ -45,7 +45,7 @@ public: ~Move(); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); void undo(Interface& target); diff --git a/src/server/events/SetPortValue.cpp b/src/server/events/SetPortValue.cpp index 0fac88c2..5bcb6dbf 100644 --- a/src/server/events/SetPortValue.cpp +++ b/src/server/events/SetPortValue.cpp @@ -53,7 +53,7 @@ SetPortValue::~SetPortValue() } bool -SetPortValue::pre_process() +SetPortValue::pre_process(PreProcessContext& ctx) { if (_port->is_output()) { return Event::pre_process_done(Status::DIRECTION_MISMATCH, _port->path()); diff --git a/src/server/events/SetPortValue.hpp b/src/server/events/SetPortValue.hpp index 7b49096f..aac5e033 100644 --- a/src/server/events/SetPortValue.hpp +++ b/src/server/events/SetPortValue.hpp @@ -47,7 +47,7 @@ public: ~SetPortValue(); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); diff --git a/src/server/events/Undo.cpp b/src/server/events/Undo.cpp index 0510d50f..83279744 100644 --- a/src/server/events/Undo.cpp +++ b/src/server/events/Undo.cpp @@ -34,7 +34,7 @@ Undo::Undo(Engine& engine, {} bool -Undo::pre_process() +Undo::pre_process(PreProcessContext& ctx) { UndoStack* const stack = _is_redo ? _engine.redo_stack() : _engine.undo_stack(); const Event::Mode mode = _is_redo ? Event::Mode::REDO : Event::Mode::UNDO; diff --git a/src/server/events/Undo.hpp b/src/server/events/Undo.hpp index c95daea9..300c74f2 100644 --- a/src/server/events/Undo.hpp +++ b/src/server/events/Undo.hpp @@ -38,7 +38,7 @@ public: SampleCount timestamp, bool is_redo); - bool pre_process(); + bool pre_process(PreProcessContext& ctx); void execute(RunContext& context); void post_process(); -- cgit v1.2.1