summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-10-01 15:18:09 -0400
committerDavid Robillard <d@drobilla.net>2016-10-02 12:24:57 -0400
commita172e76897157e5a0d2ebd3fa3f7f77ec38a5df0 (patch)
treeafc1962fc5123ff8ad4558912e69227bca2a4192
parent5c4356827e51b3d6e1256a050e6273a87728d588 (diff)
downloadingen-a172e76897157e5a0d2ebd3fa3f7f77ec38a5df0.tar.gz
ingen-a172e76897157e5a0d2ebd3fa3f7f77ec38a5df0.tar.bz2
ingen-a172e76897157e5a0d2ebd3fa3f7f77ec38a5df0.zip
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.
-rw-r--r--ingen/ingen.h8
-rw-r--r--src/server/Engine.cpp8
-rw-r--r--src/server/Event.hpp3
-rw-r--r--src/server/GraphImpl.cpp9
-rw-r--r--src/server/GraphImpl.hpp7
-rw-r--r--src/server/PostProcessor.cpp2
-rw-r--r--src/server/PreProcessContext.hpp70
-rw-r--r--src/server/PreProcessor.cpp14
-rw-r--r--src/server/events/Connect.cpp11
-rw-r--r--src/server/events/Connect.hpp2
-rw-r--r--src/server/events/Copy.cpp23
-rw-r--r--src/server/events/Copy.hpp8
-rw-r--r--src/server/events/CreateBlock.cpp10
-rw-r--r--src/server/events/CreateBlock.hpp2
-rw-r--r--src/server/events/CreateGraph.cpp13
-rw-r--r--src/server/events/CreateGraph.hpp2
-rw-r--r--src/server/events/CreatePort.cpp2
-rw-r--r--src/server/events/CreatePort.hpp2
-rw-r--r--src/server/events/Delete.cpp21
-rw-r--r--src/server/events/Delete.hpp2
-rw-r--r--src/server/events/Delta.cpp13
-rw-r--r--src/server/events/Delta.hpp2
-rw-r--r--src/server/events/Disconnect.cpp11
-rw-r--r--src/server/events/Disconnect.hpp2
-rw-r--r--src/server/events/DisconnectAll.cpp11
-rw-r--r--src/server/events/DisconnectAll.hpp2
-rw-r--r--src/server/events/Get.cpp2
-rw-r--r--src/server/events/Get.hpp2
-rw-r--r--src/server/events/Mark.cpp27
-rw-r--r--src/server/events/Mark.hpp11
-rw-r--r--src/server/events/Move.cpp2
-rw-r--r--src/server/events/Move.hpp2
-rw-r--r--src/server/events/SetPortValue.cpp2
-rw-r--r--src/server/events/SetPortValue.hpp2
-rw-r--r--src/server/events/Undo.cpp2
-rw-r--r--src/server/events/Undo.hpp2
36 files changed, 233 insertions, 81 deletions
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<Interface>(), -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 <cstdlib>
+#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<PortImpl*>* external_ports() { return _ports; }
void external_ports(Raul::Array<PortImpl*>* 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 <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_ENGINE_PREPROCESSCONTEXT_HPP
+#define INGEN_ENGINE_PREPROCESSCONTEXT_HPP
+
+#include <unordered_set>
+
+#include "GraphImpl.hpp"
+
+namespace Ingen {
+namespace Server {
+
+/** Event pre-processing context.
+ *
+ * \ingroup engine
+ */
+class PreProcessContext
+{
+public:
+ typedef std::unordered_set<GraphImpl*> 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<int32_t>()) {
+ 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<std::mutex> 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<std::mutex> 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<GraphImpl> graph = dynamic_ptr_cast<GraphImpl>(_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<Event> 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<Event> 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<int32_t>()) {
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<std::mutex> lock(_engine.store()->mutex());
@@ -166,8 +168,9 @@ Disconnect::pre_process()
dynamic_cast<OutputPort*>(tail),
dynamic_cast<InputPort*>(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<std::mutex> lock(_engine.store()->mutex(), std::defer_lock);
@@ -136,7 +139,7 @@ DisconnectAll::pre_process()
dynamic_cast<InputPort*>(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<std::mutex> 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<GraphImpl*, CompiledGraph*> 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<std::mutex> 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();