[kepler-dev] kepler/ptolemy problem

Christopher Brooks cxh at eecs.berkeley.edu
Tue Jul 5 17:15:38 PDT 2005


Well, I might be out to lunch on this, but here goes.

The short answer is that Edward modified SDF so that it is much
more picky about the capacity of buffers.

If you check out sdf/kernel from June 30, then your model runs.
I did:
cd $PTII
cvs update -D 2005/06/30
make fast

The longer answer is below:
 
Below I've appended a copy of your TextFileWriter actor.  If
I place that code as $PTII/ptolemy/actor/lib/io/TextFileWriter.java
and modify the model to use ptolemy.actor.lib.io.TextFileWriter
then I can run it within Ptolemy II.

During the first iteration, I think your model writes tokens to both
the string and fileToWrite ports of your TextFileWriter actor.  The
string is then written to the file (yay).

During the second iteration, the model writes a token to only the
string port, the fileToWrite port does not receive a token so
it starves.  

During the third (?) iteration, the model tries to write to the string
port again, but there is a token in the string buffer, so you 
are at capacity.

I'm not totally sure if this is happening during the second or third
iteration, but you get the idea.

If I replace your TextFileWriter actor with an Expression actor
that has two input ports (a and b), then when I run it, I get
a somewhat more informative error message:

ptolemy.kernel.util.IllegalActionException: Actor is not ready to
fire.
  in .testExpression.SDF Director and .testExpression.Expression
  at  ptolemy.actor.sched.StaticSchedulingDirector.fire(StaticSchedulingDirector.java:174)
  at ptolemy.actor.CompositeActor.fire(CompositeActor.java:329)
  at ptolemy.actor.Manager.iterate(Manager.java:601)
  at ptolemy.actor.Manager.execute(Manager.java:319)
  at ptolemy.actor.Manager.run(Manager.java:951)
  at ptolemy.actor.Manager$2.run(Manager.java:1003)

This is because the Expression actor has a prefire() method that
checks to see if data is present at all the ports.  If data is
not present, then prefire() returns false.

If I modify your TextFileWriter actor to have a prefire() method:


    /** Prefire this actor.  Return false if an input port has no
     *  data, otherwise return true.
     *  @exception IllegalActionException If the superclass throws it.
     */
    public boolean prefire() throws IllegalActionException {
        if (!string.hasToken(0) || !fileToWrite.hasToken(0) ) {
            return false;
        }

        return super.prefire();
    }

Then I get similar behaviour to the Expression example.


Below is some email from Edward about this.  The email
record is a little skimpy, I might of missed something over
the weekend.

Edward wrote:
> Also, with regard to code generation, the SDFScheduler no longer
> stores buffer sizes in the relations.  This never really made
> sense anyway.  I suspect that this will break code generation
> of all flavors...

And then Edward wrote:
> At 09:14 AM 6/30/2005 -0700, Stephen Neuendorffer wrote:
> >So how is the information stored now?
> 
> The buffer size is stored in the relation using its pre-existing
> setCapacity() and getCapacity().
> 
> Interestingly, this exposed a number of memory leaks that we had.
> E.g., the iterate() method of Ramp was not reading trigger port
> inputs, and hence they were accumulating forever in the input
> buffer of the receiver.
> 
> One disadvantage is that the buffer size is not currently easily
> accessible from the UI, since it's not in a parameter...
> 
> A second downside, which you pointed out before, and
> presumably affects PSDF, is that the buffer size cannot
> easily be an expression that depends on parameters...
> But I'm confused about how this would be useful...
> It seems that the buffer size really needs to be a
> maximum, no?

There are a few issues here:
1) It would probably be better if your TextFileWriter actor had
a prefire() method
2) Using BooleanSwitch in SDF causes no end of problems.
3) The change Edward implemented breaks HDF and the various
code generators.  We need to fix these failures
4) Perhaps it would be nice if the new error message was a little more
helpful, like it suggested adding a prefire() method?

Perhaps there is a way to set the buffer size so that it will grow
without bounds.  However, this was not obvious to me, and I don't
think it is really SDF is the capacity grows forever?

Perhaps Edward can shed some light on this?

_Christopher

--------
    
    Hi All,
    
    I have run into a problem with the attached workflow (test.xml). The 
    graphical representation is shown below.
    
    The model is fairly simple. The ramp iterates from 0 through 4 and the 
    first time (0) the switch should output a token which causes "Testing" 
    to be written to the output file. When the ramp output is not 0, no 
    token should be sent to the T output and nothing should be output.
    
    This model runs just fine with Kepler using PTII5.0-beta as its base. 
    However, it does NOT run when I use the head of Ptolemy CVS! (This would 
    seem to indicate that some recent change in Ptolemy is the problem, 
    since I am using identical Kepler code int the 2 cases.)
    
    The error message is "Queue is at capacity of 1" and this occurs when 
    the ramp output is 1 (i.e. it works OK for a ramp output of 0)
    
    Any ideas from anyone on what the problem is?
    
    
    
    The stack trace is:
    
    ptolemy.kernel.util.IllegalActionException:   in .test.manager
    Because:
    Queue is at capacity of 1. Cannot put a token.
      in .test.Text File Writer.string
    
        at ptolemy.actor.Manager.execute(Manager.java:383)
    
        at ptolemy.actor.Manager.run(Manager.java:951)
    
        at ptolemy.actor.Manager$2.run(Manager.java:1003)
    
    Caused by: ptolemy.actor.NoRoomException: Queue is at capacity of 1. 
    Cannot put a token.
      in .test.Text File Writer.string
    
        at ptolemy.domains.sdf.kernel.SDFReceiver.put(SDFReceiver.java:296)
    
        at ptolemy.actor.TypedIOPort.send(TypedIOPort.java:575)
    
        at ptolemy.actor.lib.Const.fire(Const.java:113)
    
        at ptolemy.actor.AtomicActor.iterate(AtomicActor.java:310)
    
        at 
    ptolemy.actor.sched.StaticSchedulingDirector.fire(StaticSchedulingDirector.
   java:169)
    
        at ptolemy.actor.CompositeActor.fire(CompositeActor.java:329)
    
        at ptolemy.actor.Manager.iterate(Manager.java:601)
    
        at ptolemy.actor.Manager.execute(Manager.java:319)
    
        ... 2 more
    
    Caused by: ptolemy.actor.NoRoomException: Queue is at capacity of 1. 
    Cannot put a token.
      in .test.Text File Writer.string
    
        at ptolemy.domains.sdf.kernel.SDFReceiver.put(SDFReceiver.java:296)
    
        at ptolemy.actor.TypedIOPort.send(TypedIOPort.java:575)
    
        at ptolemy.actor.lib.Const.fire(Const.java:113)
    
        at ptolemy.actor.AtomicActor.iterate(AtomicActor.java:310)
    
        at 
    ptolemy.actor.sched.StaticSchedulingDirector.fire(StaticSchedulingDirector.
   java:169)
    
        at ptolemy.actor.CompositeActor.fire(CompositeActor.java:329)
    
        at ptolemy.actor.Manager.iterate(Manager.java:601)
    
        at ptolemy.actor.Manager.execute(Manager.java:319)
    
        at ptolemy.actor.Manager.run(Manager.java:951)
    
        at ptolemy.actor.Manager$2.run(Manager.java:1003)
    
    
    
    
    
    -- 
    *******************************************************************
    Dan Higgins                                  higgins at nceas.ucsb.edu
    http://www.nceas.ucsb.edu/    Ph: 805-893-5127
    National Center for Ecological Analysis and Synthesis (NCEAS) 
    Marine Science Building - Room 3405
    Santa Barbara, CA 93195
-----



Place this as $PTII/ptolemy/actor/lib/io/TextFileWriter.java
and modify the model to use ptolemy.actor.lib.io.TextFileWriter



/* Write a string to a file.

 Copyright (c) 2005 The Regents of the University of California.
 All rights reserved.

 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 software and its documentation for any purpose, provided that the
 above copyright notice and the following two paragraphs appear in all
 copies of this software.

 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 IF
 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
 UPDATES,
 ENHANCEMENTS, OR MODIFICATIONS.

                                        PT_COPYRIGHT_VERSION_2
                                        COPYRIGHTENDKEY
*/

package ptolemy.actor.lib.io;

//package org.resurgence.actor;

import ptolemy.actor.TypedAtomicActor;
import ptolemy.actor.TypedIOPort;
import ptolemy.data.StringToken;
import ptolemy.data.expr.StringParameter;
import ptolemy.data.type.BaseType;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;

import java.io.File;
import java.io.FileWriter;

//////////////////////////////////////////////////////////////////////////
//// TextFileWriter

/** This actor reads a string-valued input token and writes it
 *  to the corresponding file without any extra line breaks. It does
 not
 *  include any enclosing quotation marks in the output. The path and
 *  name of the file are given via an input port.
 *  The user can decide if the text is appended to the file if it
 exists,
 *  if an existing file is overwritten, or left as it is.
 *  <p>
 *  This actor is based on the Ptolemy II LineWriter actor.
 *  @author Wibke Sudholt, University and ETH Zurich, November 2004
 *  @version $Id: TextFileWriter.java,v 1.1 2005/03/18 18:16:58
 sudholt Exp $
 */
public class TextFileWriter extends TypedAtomicActor {

    /** Construct a TextFileWriter with the given container and name.
     *  @param container The container.
     *  @param name The name of this actor.
     *  @exception IllegalActionException If the actor cannot be
    contained
     *   by the proposed container.
     *  @exception NameDuplicationException If the container already
    has an
     *   actor with this name.
     */
    public TextFileWriter(CompositeEntity container, String name)
        throws IllegalActionException, NameDuplicationException {
        super(container, name);

        string = new TypedIOPort(this, "string", true, false);
        string.setTypeEquals(BaseType.STRING);

        fileToWrite = new TypedIOPort(this, "fileToWrite", true,
	false);
        fileToWrite.setTypeEquals(BaseType.STRING);

        fileWritten = new TypedIOPort(this, "fileWritten", false,
	true);
        fileWritten.setTypeEquals(BaseType.STRING);

        change = new StringParameter(this, "Change existing");
        change.setTypeEquals(BaseType.STRING);
        change.addChoice("No");
        change.addChoice("Append");
        change.addChoice("Overwrite");
        change.setToken(new StringToken("No"));

        _attachText("_iconDescription", "<svg>\n"
                + "<rect x=\"-25\" y=\"-20\" "
                + "width=\"50\" height=\"40\" "
                + "style=\"fill:white\"/>\n"
                + "<polygon points=\"-15,-10 -12,-10 -8,-14 -1,-14
                3,-10"
                + " 15,-10 15,10, -15,10\" "
                + "style=\"fill:red\"/>\n"
                + "</svg>\n");
    }

    ///////////////////////////////////////////////////////////////////
    ////                     ports and parameters
    ////

    /** The first input port, which contains the text to be written.
     */
    public TypedIOPort string = null;
    /** The second input port, which contains the file path and name
     *  to which to write.
     */
    public TypedIOPort fileToWrite = null;
    /** The output port, which contains the name and path of the
     *  written file.
     */
    public TypedIOPort fileWritten = null;
    /** The parameter, which specifies what should happen to
     *  existing files.
     */
    public StringParameter change = null;

    ///////////////////////////////////////////////////////////////////
    ////                         public methods
    ////

    /** Read an input string and write it to the corresponding file.
     *  @exception IllegalActionException If there's no director.
     */
    public void fire() throws IllegalActionException {
        super.fire();
        if (string.hasToken(0) && fileToWrite.hasToken(0)) {
            _text = ((StringToken)string.get(0)).stringValue();
            _path = ((StringToken)fileToWrite.get(0)).stringValue();
            _changeValue = change.stringValue();
            _handle = new File(_path);
            _needNew = !_handle.exists();
            if (_changeValue.equalsIgnoreCase("Append")) {
                _doChange = true;
                _append = true;
            } else if (_changeValue.equalsIgnoreCase("Overwrite")) {
                _doChange = true;
                _append = false;
            } else {
                _doChange = _needNew;
                _append = false;
            }
            _writer = null;
            if (_doChange) {
                if (_needNew) {
                    try {
                        _parentDir = _handle.getParentFile();
                        if (!_parentDir.exists()) {
                            _mkdirsSuccess = _parentDir.mkdirs();
                            if (!_mkdirsSuccess) {
                                throw new IllegalActionException(this,
                                    "Parent directory " + _parentDir +
                                    " was not successfully made.");
                            }
                        }
                        _handle.createNewFile();
                     } catch (Exception ex) {
                        _debug("File cannot be created.");
                     }
                }
                try {
                    _writer = new FileWriter(_handle, _append);
                    _writer.write(_text);
                    _writer.close();
                } catch (Exception ex) {
                    _debug("File cannot be written.");
                }
                try {
                    _changedFile = _handle.getCanonicalPath();
                } catch (Exception ex) {
                    _debug("Path cannot be determined.");
                }
                fileWritten.send(0, new StringToken(_changedFile));
            }
        }
    }

    ///////////////////////////////////////////////////////////////////
    ////                         protected methods
    ////

    ///////////////////////////////////////////////////////////////////
    ////                         protected members
    ////

    ///////////////////////////////////////////////////////////////////
    ////                         private members
    ////

    private String _path;
    private String _text;
    private String _changeValue;
    private File _handle;
    private boolean _needNew;
    private boolean _doChange;
    private boolean _append;
    private File _parentDir;
    private boolean _mkdirsSuccess;
    private FileWriter _writer;
    private String _changedFile;
}


More information about the Kepler-dev mailing list