diff --git a/src/backend/engine/scheduler-diagnostics.hpp b/src/backend/engine/scheduler-diagnostics.hpp new file mode 100644 index 000000000..94214d80c --- /dev/null +++ b/src/backend/engine/scheduler-diagnostics.hpp @@ -0,0 +1,147 @@ +/* + SCHEDULER-DIAGNOSTICS.hpp - diagnostic facility to investigate scheduler operation + + Copyright (C) Lumiera.org + 2013, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file scheduler-diagnostics.hpp + ** An facility to check and monitor the internal workings of the scheduler. + ** Once created, an SchedulerDiagnostics object connects to the scheduler implementation + ** through the SchedulerFrontend interface to activate additional diagnostic facilities. + ** This allows to verify the operation of the scheduler from within unit-tests; + ** typically doing so incurs a performance overhead. + ** + ** @see SchedulerFrontend + ** @see scheduler-interface-test.cpp + ** @see EngineServiceMock + */ + + +#ifndef BACKEND_ENGINE_SCHEDULER_DIAGNOSTICS_H +#define BACKEND_ENGINE_SCHEDULER_DIAGNOSTICS_H + + +#include "lib/error.hpp" +#include "lib/hash-value.h" +#include "backend/engine/scheduler-frontend.hpp" +//#include "include/dummy-player-facade.h" +//#include "include/display-facade.h" +//#include "proc/engine/calc-stream.hpp" +//#include "proc/mobject/model-port.hpp" +//#include "proc/play/timings.hpp" +//#include "proc/play/output-slot.hpp" +//#include "common/instancehandle.hpp" +//#include "lib/singleton-ref.hpp" +//#include "lib/polymorphic-value.hpp" +//#include "lib/singleton.hpp" +// +#include +//#include +//#include + + +namespace backend{ +namespace engine { + +// using std::string; +// using lumiera::Subsys; +// using lumiera::Display; +// using lumiera::DummyPlayer; +// using proc::play::Timings; + using lib::HashVal; + + + + + /******************************************************************* + * Render engine diagnostic facility. Creating an instance + * will activate additional tracing and diagnostic facilities + * within the scheduler implementation; results may be investigated + * through SchedulerDiagnostics public functions. + * The object acts like a smart handle, i.e. the tracing facilities + * will be disabled and disconnected when going out of scope. + * @warning not reentrant, no reference-counting. + * At any given time, at most a single instance + * of SchedulerDiagnostics may be used. + */ + class SchedulerDiagnostics + : boost::noncopyable + { + SchedulerFrontend& scheduler_; + + public: + SchedulerDiagnostics (SchedulerFrontend& sch) + : scheduler_(sch) + { + UNIMPLEMENTED ("attach tracing connector"); + scheduler_.activateTracing(); + } + + ~SchedulerDiagnostics() + { + TODO ("detach tracing connector"); + scheduler_.disableTracing(); + } + + /** */ + + bool + is_scheduled_timebound (HashVal jobID) + { + UNIMPLEMENTED ("query the scheduler to determine if the given job is planned for time-bound operation"); + } + + bool + is_scheduled_freewheeling (HashVal jobID) + { + UNIMPLEMENTED ("query the scheduler to determine if the given job is planned for freewheeling operation"); + } + + bool + is_scheduled_background (HashVal jobID) + { + UNIMPLEMENTED ("query the scheduler to determine if the given job is planned for background execution"); + } + + bool + is_scheduled_timebound (Job const& job) + { + return is_scheduled_timebound (hash_value (job)); + } + + bool + is_scheduled_freewheeling (Job const& job) + { + return is_scheduled_freewheeling (hash_value (job)); + } + + bool + is_scheduled_background (Job const& job) + { + return is_scheduled_background (hash_value (job)); + } + }; + + + + + + +}} // namespace backend::engine +#endif diff --git a/src/backend/engine/scheduler-frontend.cpp b/src/backend/engine/scheduler-frontend.cpp index 3cf1698ab..b76c0ae5e 100644 --- a/src/backend/engine/scheduler-frontend.cpp +++ b/src/backend/engine/scheduler-frontend.cpp @@ -21,6 +21,7 @@ * *****************************************************/ +#include "lib/error.h" #include "backend/engine/scheduler-frontend.hpp" namespace backend{ @@ -31,4 +32,25 @@ namespace engine { + /** + * Switch the complete engine into diagnostics mode. + * This activates additional logging and reporting facilities, + * allowing to verify some specific operations within the engine + * did indeed happen. Activating this mode incurs a performance hit. + */ + void + SchedulerFrontend::activateTracing() + { + UNIMPLEMENTED ("tracing/diagnostics mode of the render engine"); + } + + void + SchedulerFrontend::disableTracing() + { + UNIMPLEMENTED ("tracing/diagnostics mode of the render engine"); + ///////////TODO ensure this is EX_FREE + } + + + }} // namespace backend::engine diff --git a/src/backend/engine/scheduler-frontend.hpp b/src/backend/engine/scheduler-frontend.hpp index d2b0454d3..34b4f936e 100644 --- a/src/backend/engine/scheduler-frontend.hpp +++ b/src/backend/engine/scheduler-frontend.hpp @@ -27,6 +27,7 @@ //using std::list; +#include "lib/singleton.hpp" namespace backend{ @@ -34,19 +35,40 @@ namespace engine { /** + * Access point to the scheduler service provided by the back-end. + * Proc-Layer uses this service as the primary means of instructing + * the backend; suitably prepared and wired frame render jobs are + * handed over to the scheduler for time-bound or bandwidth-controlled + * execution + * * @todo this is planned to become the frontend * to the render node network, which can be considered * at the lower end of the middle layer; the actual * render operations are mostly implemented by the backend - * ////////TODO WIP as of 12/2010 + * @todo define the low-level scheduler interface and hook in + * the necessary calls to implement this frontend. + * ////////TODO WIP as of 9/2013 */ class SchedulerFrontend { public: + /** access point to the Engine Interface. + * @internal this is an facade interface for internal use + * by the player. Client code should use the Player. + */ + static lib::Singleton instance; + + ///// TODO: find out about the public operations // note: the play controller lives in the proc-layer, // but is a subsystem separate of the session. + protected: + void activateTracing(); + void disableTracing(); ///< EX_FREE + + friend class SchedulerDiagnostics; + private: }; diff --git a/src/proc/engine/engine-diagnostics.hpp b/src/proc/engine/engine-diagnostics.hpp index be4e50859..a29b051b7 100644 --- a/src/proc/engine/engine-diagnostics.hpp +++ b/src/proc/engine/engine-diagnostics.hpp @@ -75,6 +75,9 @@ namespace engine{ * EngineDiagnostics public functions. The object acts * like a smart handle, i.e. the tracing facilities will * be disabled and disconnected when going out of scope. + * @warning not reentrant, no reference-counting. + * At any given time, at most a single instance + * of EngineDiagnostics may be used. */ class EngineDiagnostics : boost::noncopyable diff --git a/src/proc/engine/engine-service.cpp b/src/proc/engine/engine-service.cpp index 8f52a9ad8..1121970fd 100644 --- a/src/proc/engine/engine-service.cpp +++ b/src/proc/engine/engine-service.cpp @@ -156,6 +156,28 @@ namespace engine{ + /** + * Switch the complete engine into diagnostics mode. + * This activates additional logging and reporting facilities, + * allowing to verify some specific operations within the engine + * did indeed happen. Activating this mode incurs a performance hit. + */ + void + EngineService::activateTracing() + { + UNIMPLEMENTED ("tracing/diagnostics mode of the render engine"); + } + + void + EngineService::disableTracing() + { + UNIMPLEMENTED ("tracing/diagnostics mode of the render engine"); + ///////////TODO ensure this is EX_FREE + } + + + + /* ===== Quality-of-Service ===== */ diff --git a/tests/core/backend/engine/scheduler-interface-test.cpp b/tests/core/backend/engine/scheduler-interface-test.cpp index cd27aefdc..28ec400c3 100644 --- a/tests/core/backend/engine/scheduler-interface-test.cpp +++ b/tests/core/backend/engine/scheduler-interface-test.cpp @@ -22,16 +22,21 @@ #include "lib/test/run.hpp" +#include "lib/util.hpp" #include "proc/play/timings.hpp" #include "lib/time/timevalue.hpp" #include "backend/engine/job.h" +#include "backend/engine/scheduler-frontend.hpp" +#include "backend/engine/scheduler-diagnostics.hpp" namespace backend { namespace engine { namespace test { + using util::isSameObject; + using lib::time::Time; using lib::time::TimeVar; using lib::time::Duration; @@ -161,26 +166,60 @@ namespace test { virtual void run (Arg) { - verify_simple_job_specification(); - demonstrate_nested_job_specification(); + SchedulerFrontend& scheduler = SchedulerFrontend::instance(); + + verify_simple_job_specification (scheduler); + verify_job_specification_variations (scheduler); + demonstrate_nested_job_specification (scheduler); } void - verify_simple_job_specification () + verify_simple_job_specification (SchedulerFronend& scheduler) { + SchedulerDiagnostics monitor(scheduler); + InvocationInstanceID invoKey; invoKey.frameNumber = 111; Job job(dummyClosure, invoKey, Time::ZERO); - JobTransaction definitionContext; ///////////////TODO: get this "somehow" from the SchedulerFrontend + JobTransaction definitionContext; + scheduler.startJobTransaction() + .addJob(job) + .commit(); - definitionContext.addFreewheeling(job); - definitionContext.addBackground (job); + CHECK ( monitor.is_scheduled_timebound (job)); + CHECK (!monitor.is_scheduled_background (job)); + CHECK (!monitor.is_scheduled_freewheeling (job)); + } + + + void + verify_job_specification_variations (SchedulerFronend& scheduler) + { + SchedulerDiagnostics monitor(scheduler); - UNIMPLEMENTED ("find a way to verify what has been scheduled"); + InvocationInstanceID invoKey; + invoKey.frameNumber = 111; + + Job job(dummyClosure, invoKey, Time::ZERO); + + JobTransaction tx = scheduler.startJobTransaction(); + + tx.addFreewheeling(job); + tx.addBackground (job); + + CHECK (!monitor.is_scheduled_timebound (job)); + CHECK (!monitor.is_scheduled_background (job)); + CHECK (!monitor.is_scheduled_freewheeling (job)); + + tx.commit(); + + CHECK (!monitor.is_scheduled_timebound (job)); + CHECK ( monitor.is_scheduled_background (job)); + CHECK ( monitor.is_scheduled_freewheeling (job)); } @@ -194,14 +233,26 @@ namespace test { * @see HierarchyOrientationIndicator_test#demonstrate_tree_rebuilding */ void - demonstrate_nested_job_specification () + demonstrate_nested_job_specification (SchedulerFronend& scheduler) { - JobTransaction startTx; + SchedulerDiagnostics monitor(scheduler); + + JobTransaction startTx = scheduler.startJobTransaction(); uint dummyLevel = 5; specifyJobs (startTx, dummyLevel); - UNIMPLEMENTED ("find a way to verify what has been scheduled"); + startTx.commit(); + + for (uint i=0; i <=5; ++i) + { + Time nominalTime(dummyLevel*TEST_FRAME_DURATION); + Time deadline(testStartTime + i*TEST_FRAME_DURATION); + + CHECK (monitor.has_job_scheduled_at (deadline)); + CHECK (isSameObject (dummyClosure, monitor.job_at(deadline).jobClosure)); + CHECK (nominalTime == monitor.job_at(deadline).parameter.nominalTime); + } } /** recursive helper function to add several levels of prerequisites @@ -218,7 +269,7 @@ namespace test { Time nominalTime(dummyLevel*TEST_FRAME_DURATION); Time deadline(testStartTime + dummyLevel*TEST_FRAME_DURATION); - Job job(dummyClosure,invoKey, nominalTime); + Job job(dummyClosure, invoKey, nominalTime); currentTx.addJob (deadline, job);