001/* Director for the synchronous dataflow model of computation which
002 finds an optimized schedule.
003
004 Copyright (c) 1997-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.domains.sdf.optimize;
029
030import java.util.Iterator;
031
032import ptolemy.actor.Actor;
033import ptolemy.actor.FiringEvent;
034import ptolemy.actor.sched.Firing;
035import ptolemy.actor.sched.Schedule;
036import ptolemy.actor.util.PeriodicDirectorHelper;
037import ptolemy.data.expr.Parameter;
038import ptolemy.data.type.BaseType;
039import ptolemy.domains.sdf.kernel.SDFDirector;
040import ptolemy.kernel.CompositeEntity;
041import ptolemy.kernel.util.Attribute;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.InvalidStateException;
044import ptolemy.kernel.util.NameDuplicationException;
045
046///////////////////////////////////////////////////////////////////
047////OptimizingSDFDirector
048
049/**
050Director for the synchronous dataflow (SDF) model of computation which finds
051an optimized schedule according to a defined criterion.
052
053<h1>Class comments</h1>
054An OptimizingSDFDirector is the class that controls execution of actors under the
055SDF domain, while using an optimal schedule.  For this it uses the OptimizingSDFScheduler
056class.
057<p>
058See {@link ptolemy.domains.sdf.kernel.SDFDirector},
059{@link ptolemy.domains.sdf.kernel.SDFScheduler} and
060{@link ptolemy.domains.sdf.optimize.OptimizingSDFScheduler} for more information.
061</p><p>
062The <i>optimizationCriterion</i> parameter of this director
063selects the optimization criterion.
064</p>
065@see ptolemy.domains.sdf.kernel.SDFScheduler
066@see ptolemy.domains.sdf.kernel.SDFDirector
067@see ptolemy.domains.sdf.optimize.OptimizingSDFScheduler
068
069@author Marc Geilen
070@version $Id$
071@since Ptolemy II 10.0
072@Pt.ProposedRating Red (mgeilen)
073@Pt.AcceptedRating Red ()
074 */
075
076public class OptimizingSDFDirector extends SDFDirector {
077
078    /**
079     * Enumeration type to define the supported optimization criteria.
080     */
081    public enum OptimizationCriteria {
082    /**
083     * Optimize for minimum number of frame buffers.
084     */
085    BUFFERS,
086    /**
087     * Optimize execution time (estimate).
088     */
089    EXECUTIONTIME
090    }
091
092    /**
093     * Parameter defining the optimization criterion.
094     */
095    public Parameter optimizationCriterion;
096
097    /**
098     * Construct on OptimizingSDFDirector in the given container with the given name.
099     * The container argument must not be null, or a
100     * NullPointerException will be thrown.
101     * If the name argument is null, then the name is set to the
102     * empty string. Increment the version number of the workspace.
103     * The OptimizingSDFDirector will have a default scheduler of type
104     * OptimizingSDFScheduler.
105     *
106     *  @param container Container of the director.
107     *  @param name Name of this director.
108     *  @exception IllegalActionException If the director is not compatible
109     *   with the specified container.  May be thrown in a derived class.
110     *  @exception NameDuplicationException If the container is not a
111     *   CompositeActor and the name collides with an entity in the container.
112     */
113    public OptimizingSDFDirector(CompositeEntity container, String name)
114            throws IllegalActionException, NameDuplicationException {
115        super(container, name);
116        // FIXME: super(container, name) above calls SDFDirector._init in which the scheduler is set to an
117        // SDFScheduler, but we need an OptimizingSDFScheduler (set in OptimizingSDFDirector._init)
118        // before setting the value of the OptimizationCriterion parameter
119        // Perhaps getting the preferred Scheduler type could be factored out, but I don't want to
120        // touch the SDFDirector code.
121
122        // initialize the parameter
123        optimizationCriterion = new Parameter(this, "OptimizationCriterion");
124        optimizationCriterion.setTypeEquals(BaseType.STRING);
125        optimizationCriterion.addChoice("\"Buffers\"");
126        optimizationCriterion.addChoice("\"Execution Time\"");
127
128        // initialize
129        _init();
130
131    }
132
133    /** Calculate the current schedule, if necessary, and iterate the
134     *  contained actors in the order given by the schedule.
135     *  method copied from super class SDFDirector. Modifies only the firing
136     *  by firing the BufferingProfile if the interface is defined.
137     *  Factoring out difference might be a good idea.
138     *
139     *  @exception IllegalActionException If any actor executed by this
140     *   actor return false in prefire.
141     *  @exception InvalidStateException If this director does not have a
142     *   container.
143     */
144    @Override
145    public void fire() throws IllegalActionException {
146        // Don't call "super.fire();" here because if you do then
147        // everything happens twice.
148
149        OptimizingSDFScheduler scheduler = (OptimizingSDFScheduler) getScheduler();
150
151        if (scheduler == null) {
152            throw new IllegalActionException(
153                    "Attempted to fire " + "system with no scheduler");
154        }
155
156        // This will throw IllegalActionException if this director
157        // does not have a container.
158        Schedule schedule = scheduler.getSchedule();
159        Iterator firings = schedule.firingIterator();
160
161        while (firings.hasNext() && !_stopRequested) {
162            Firing firing = (Firing) firings.next();
163            Actor actor = firing.getActor();
164            int iterationCount = firing.getIterationCount();
165
166            if (_debugging) {
167                _debug(new FiringEvent(this, actor, FiringEvent.BEFORE_ITERATE,
168                        iterationCount));
169            }
170
171            int returnValue;
172            // check if the actor has the interface BufferingProfile
173            if (actor instanceof BufferingProfile) {
174                BufferingProfile bp = (BufferingProfile) actor;
175                // Then the firing must be a BufferProfileFiring
176                BufferingProfileFiring f = (BufferingProfileFiring) firing;
177                returnValue = bp.iterate(iterationCount, f.fireExclusive);
178            } else {
179                returnValue = actor.iterate(iterationCount);
180            }
181
182            if (returnValue == STOP_ITERATING) {
183                _postfireReturns = false;
184            } else if (returnValue == NOT_READY) {
185                // See de/test/auto/knownFailedTests/DESDFClockTest.xml
186                throw new IllegalActionException(this, actor, "Actor "
187                        + "is not ready to fire.  Perhaps " + actor.getName()
188                        + ".prefire() returned false? "
189                        + "Try debugging the actor by selecting "
190                        + "\"Listen to Actor\".  Also, for SDF check moml for "
191                        + "tokenConsumptionRate on input.");
192            }
193
194            if (_debugging) {
195                _debug(new FiringEvent(this, actor, FiringEvent.AFTER_ITERATE,
196                        iterationCount));
197            }
198        }
199    }
200
201    /** React to a change in an attribute. If the changed attribute
202     *  matches a parameter of the director, then the corresponding
203     *  local copy of the parameter value will be updated.
204     *  @param attribute The changed parameter.
205     *  @exception IllegalActionException If the parameter set is not valid.
206     */
207    @Override
208    public void attributeChanged(Attribute attribute)
209            throws IllegalActionException {
210        // NOTE: Invalidate the schedules only if the values of these
211        // parameters have changed.
212        if (attribute == optimizationCriterion) {
213            _setOptimizationCriterionValue();
214        }
215        super.attributeChanged(attribute);
216    }
217
218    ///////////////////////////////////////////////////////////////////
219    ////                   private fields                                  ////
220
221    /** Initialize the object.   In this case, we give the OptimizingSDFDirector a
222     *  default scheduler of the class OptimizingSDFScheduler, an iterations
223     *  parameter and a vectorizationFactor parameter.
224     */
225    private void _init()
226            throws IllegalActionException, NameDuplicationException {
227
228        // set the schedule to an instance of OptimizingSDFScheduler
229        OptimizingSDFScheduler scheduler = new OptimizingSDFScheduler(this,
230                uniqueName("OptimizingSDFScheduler"),
231                _optimizationCriterionValue);
232
233        // set the default value of the parameter
234        optimizationCriterion.setExpression("\"Buffers\"");
235
236        // if necessary, copy the string parameter to the enumerated value
237        _setOptimizationCriterionValue();
238
239        // set the constrainBufferSizes parameter
240        scheduler.constrainBufferSizes.setExpression("constrainBufferSizes");
241        setScheduler(scheduler);
242
243        // Subclasses may set this to null and handle this themselves.
244        _periodicDirectorHelper = new PeriodicDirectorHelper(this);
245    }
246
247    /**
248     * Set the _optimizationCriterionValue to the proper value corresponding to the
249     * OptimizationCriterion string parameter
250     * @exception IllegalActionException if the criterion used is unknown
251     */
252    private void _setOptimizationCriterionValue()
253            throws IllegalActionException {
254        OptimizingSDFScheduler os = (OptimizingSDFScheduler) getScheduler();
255        if (optimizationCriterion.getValueAsString().equals("\"Buffers\"")) {
256            _optimizationCriterionValue = OptimizationCriteria.BUFFERS;
257        } else if (optimizationCriterion.getValueAsString()
258                .equals("\"Execution Time\"")) {
259            _optimizationCriterionValue = OptimizationCriteria.EXECUTIONTIME;
260        } else {
261            throw new IllegalActionException("Unknown optimization criterion");
262        }
263        if (os != null) {
264            os.optimizationCriterion = _optimizationCriterionValue;
265        }
266        // invalidate the schedule, because the criterion has changed
267        invalidateSchedule();
268    }
269
270    private OptimizationCriteria _optimizationCriterionValue = OptimizationCriteria.BUFFERS;
271
272}