[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