/** * Return a list of source ports connected to this port on the same layer that can send data to * this port. This includes output ports that are connected on the outside to this port, and input * ports that are connected on the inside to this port. * * @param input TypedIOPort * @return A list of IOPort objects. */ private LinkedList _shallowSourcePortList(TypedIOPort input) { try { _workspace.getReadAccess(); Actor container = (Actor) input.getContainer(); Director excDirector = ((Actor) container).getExecutiveDirector(); int depthOfContainer = ((NamedObj) container).depthInHierarchy(); LinkedList result = new LinkedList(); Iterator ports = input.connectedPortList().iterator(); while (ports.hasNext()) { IOPort port = (IOPort) ports.next(); int depth = port.depthInHierarchy(); if (port.isInput() && (depth <= depthOfContainer)) { result.addLast(port); } else if (port.isOutput() && (depth == (depthOfContainer + 1))) { result.addLast(port); } } return result; } finally { _workspace.doneReading(); } }
/** * Return true if the receiver containing this boundary detector is contained on the outside of a * boundary port. A boundary port is an opaque port that is contained by a composite actor. If the * containing receiver is contained on the outside of a boundary port then return true; otherwise * return false. This method is not synchronized so the caller should be. * * @return True if the containing receiver is contained on the outside of a boundary port; return * false otherwise. */ public boolean isOutsideBoundary() { if (_outsideBoundaryCacheIsOn) { return _isInsideBoundaryValue; } else { IOPort innerPort = _receiver.getContainer(); if (innerPort == null) { _outsideBoundaryCacheIsOn = false; _isOutsideBoundaryValue = false; return _isOutsideBoundaryValue; } ComponentEntity innerEntity = (ComponentEntity) innerPort.getContainer(); if ((innerEntity != null) && !innerEntity.isAtomic() && innerPort.isOpaque()) { // The containing receiver is contained by the port // of a composite actor. if (innerPort.isOutput() && !innerPort.isInput()) { _isOutsideBoundaryValue = false; } else if (!innerPort.isOutput() && innerPort.isInput()) { _isOutsideBoundaryValue = true; } else if (!innerPort.isOutput() && !innerPort.isInput()) { _isOutsideBoundaryValue = false; } else { // CONCERN: The following only works if the port // is not both an input and output. throw new IllegalArgumentException( "A port that " + "is both an input and output can not be " + "properly dealt with by " + "PNQueueReceiver.isInsideBoundary"); } _outsideBoundaryCacheIsOn = true; return _isOutsideBoundaryValue; } _outsideBoundaryCacheIsOn = true; _isOutsideBoundaryValue = false; return _isOutsideBoundaryValue; } }
/** * Return the buffer size of a given channel (i.e, a given port and a given channel number). The * default value is 1. If the port is an output port, then the buffer size is obtained from the * inside receiver. If it is an input port, then it is obtained from the specified port. * * @param port The given port. * @param channelNumber The given channel number. * @return The buffer size of the given channel. * @exception IllegalActionException If the channel number is out of range or if the port is * neither an input nor an output. */ public int getBufferSize(IOPort port, int channelNumber) throws IllegalActionException { Receiver[][] receivers = null; if (port.isInput()) { receivers = port.getReceivers(); } else if (port.isOutput()) { receivers = port.getInsideReceivers(); } // else { // throw new IllegalActionException(port, // "Port is neither an input nor an output."); // } // try { int size = 0; for (int copy = 0; copy < receivers[channelNumber].length; copy++) { int copySize = ((SDFReceiver) receivers[channelNumber][copy]).getCapacity(); if (copySize > size) { size = copySize; } // When an output port of a composite actor is directly // connected to an input port of the same composite actor, // calling getCapacity() will return 0. Therefore we use // the rate to determine the buffer size. if (port.isOutput()) { copySize = DFUtilities.getRate(port); if (copySize > size) { size = copySize; } } } return size; // } // catch (ArrayIndexOutOfBoundsException ex) { // throw new IllegalActionException(port, "Channel out of bounds: " // + channelNumber); // } }
/** * Create a guarded communication with a send communication. This constructor allows actors which * are not CSPActors access to CSP functionality by providing their own * ConditionalBranchController. * * @param guard The guard for the guarded communication statement represented by this object. * @param port The IOPort containing the channel (and thus receiver) that this branch will try to * rendezvous with. * @param channel The channel in the IOPort that this branch is trying to rendezvous with. * @param branchID The identification number assigned to this branch upon creation by the * CSPActor. * @param token The token this branch is trying to send. * @param controller The controller that this branch uses. * @exception IllegalActionException If the channel has more than one receiver or if the receiver * is not of type CSPReceiver. */ public ConditionalSend( boolean guard, IOPort port, int channel, int branchID, Token token, ConditionalBranchController controller) throws IllegalActionException { super(guard, port, branchID, controller); _port = port; _channel = channel; try { port.workspace().getReadAccess(); if (!port.isOutput()) { throw new IllegalActionException( port, "ConditionalSend: " + "tokens only sent from an output port."); } if (channel >= port.getWidth() || channel < 0) { throw new IllegalActionException(port, "ConditionalSend: " + "channel index out of range."); } Receiver[][] receivers = port.getRemoteReceivers(); if (receivers == null || receivers[channel] == null) { throw new IllegalActionException( port, "ConditionalSend: " + "Trying to rendezvous with null receiver"); } if (!(receivers[channel][0] instanceof CSPReceiver)) { throw new IllegalActionException( port, "ConditionalSend: " + "channel " + channel + " does not have a receiver " + "of type CSPReceiver."); } _setReceivers(receivers[channel]); } finally { port.workspace().doneReading(); } _setToken(token); }
/** * Return true if the receiver containing this boundary detector is connected to the outside of an * output boundary port; return false otherwise. A boundary port is an opaque port that is * contained by a composite actor. If the receiver containing this boundary detector is contained * on the inside of a boundary port, then return false. This method is not synchronized so the * caller should be. * * @return True if the containing receiver is connected to the outside of a boundary port; return * false otherwise. * @exception IllegalActionException */ public boolean isConnectedToBoundaryOutside() throws IllegalActionException { if (_connectedOutsideOfBoundaryCacheIsOn) { return _isConnectedOutsideOfBoundaryValue; } else { IOPort contPort = _receiver.getContainer(); if (contPort == null) { _connectedOutsideOfBoundaryCacheIsOn = false; _isConnectedOutsideOfBoundaryValue = false; return _isConnectedOutsideOfBoundaryValue; } Iterator ports = contPort.connectedPortList().iterator(); while (ports.hasNext()) { IOPort connectedPort = (IOPort) ports.next(); ComponentEntity connectedEntity = (ComponentEntity) connectedPort.getContainer(); if (connectedPort.isOpaque() && !connectedEntity.isAtomic() && connectedPort.isOutput()) { // The port container of this receiver is // connected to the outside of a boundary port. // Now determine if this receiver's channel is // connected to the boundary port. Receiver[][] receivers = connectedPort.getRemoteReceivers(); for (int i = 0; i < receivers.length; i++) { for (int j = 0; j < receivers[i].length; j++) { if (_receiver == receivers[i][j]) { _connectedOutsideOfBoundaryCacheIsOn = true; _isConnectedOutsideOfBoundaryValue = true; return true; } } } } } _connectedOutsideOfBoundaryCacheIsOn = true; _isConnectedOutsideOfBoundaryValue = false; return _isConnectedOutsideOfBoundaryValue; } }
/** * Return the parameterized scheduling sequence. An exception will be thrown if the graph is not * schedulable. * * @return A schedule of the deeply contained opaque entities in the firing order. * @exception NotSchedulableException If a parameterized schedule cannot be derived for the model. * @exception IllegalActionException If the rate parameters of the model are not correct, or the * computed rates for external ports are not correct. */ @SuppressWarnings("unused") protected Schedule _getSchedule() throws NotSchedulableException, IllegalActionException { PSDFDirector director = (PSDFDirector) getContainer(); CompositeActor model = (CompositeActor) director.getContainer(); // Get the vectorization factor. String vectorizationFactorExpression = "1"; String vectorizationName = director.vectorizationFactor.getName(model); vectorizationFactorExpression = vectorizationName.replaceAll("\\.", "::"); if (vectorizationFactorExpression.indexOf(" ") != -1) { throw new InternalErrorException( "The vectorizationFactor " + "PSDFDirector parameter must " + "not have spaces in its value. The original value " + "was \"" + vectorizationName + "\". Try changing the name of " + "director."); } PSDFGraphReader graphReader = new PSDFGraphReader(); PSDFGraph graph = (PSDFGraph) graphReader.convert(model); _debug("PSDF graph = \n" + graph.toString()); if (_debugFlag) { graph.printEdgeRateExpressions(); } PSDFAPGANStrategy strategy = new PSDFAPGANStrategy(graph); ptolemy.graph.sched.Schedule graphSchedule = strategy.schedule(); _debug("P-APGAN schedule = \n" + graphSchedule.toString()); SymbolicScheduleElement resultSchedule = _expandAPGAN(graph, strategy.getClusterManager().getRootNode(), strategy); resultSchedule.setIterationCount(vectorizationFactorExpression); _debug("Final schedule = \n" + resultSchedule.toString()); if (_debugging) { _debug("The buffer size map:\n"); Iterator relations = _bufferSizeMap.keySet().iterator(); while (relations.hasNext()) { Relation relation = (Relation) relations.next(); _debug(relation.getName() + ": " + _bufferSizeMap.get(relation) + "\n"); } } _saveBufferSizes(_bufferSizeMap); // Crazy hack to infer firing counts for each actor. try { _inferFiringCounts(resultSchedule, null); } catch (NameDuplicationException ex) { throw new NotSchedulableException(new LinkedList(), ex, "Error recording firing counts"); } // Crazy hack to Infer port production: FIXME: This should be // done as part of the APGAN expansion where the rates of // external ports are unknown The reason is that it will make // rate information propagate from an actor input port to // another actors input port that are connected on the inside // to the same external input port. See // BaseSDFScheduler.setContainerRates. Iterator ports = model.portList().iterator(); while (ports.hasNext()) { IOPort port = (IOPort) ports.next(); if (_debugging && VERBOSE) { _debug("External Port " + port.getName()); } if (port.isInput() && port.isOutput()) { throw new NotSchedulableException( port, "External port is both an input and an output, " + "which is not allowed in SDF."); } else if (port.isInput()) { List sinks = port.insideSinkPortList(); if (sinks.size() > 0) { IOPort connectedPort = (IOPort) sinks.get(0); Entity entity = (Entity) connectedPort.getContainer(); String name = connectedPort.getName(model); String identifier = name.replaceAll("\\.", "::"); String sinkExpression; Variable sinkRateVariable = DFUtilities.getRateVariable(connectedPort, "tokenConsumptionRate"); if (sinkRateVariable == null) { sinkExpression = "1"; } else { sinkExpression = identifier + "::" + sinkRateVariable.getName(); } String expression = sinkExpression + " * " + entity.getName() + "::firingsPerIteration"; DFUtilities.setExpressionIfNotDefined(port, "tokenConsumptionRate", expression); if (_debugging && VERBOSE) { _debug("Setting tokenConsumptionRate to " + expression); } } } else if (port.isOutput()) { List sources = port.insideSourcePortList(); if (sources.size() > 0) { IOPort connectedPort = (IOPort) sources.get(0); Entity entity = (Entity) connectedPort.getContainer(); String name = connectedPort.getName(model); String identifier = name.replaceAll("\\.", "::"); Variable sourceRateVariable = DFUtilities.getRateVariable(connectedPort, "tokenProductionRate"); String sourceExpression; if (sourceRateVariable == null) { sourceExpression = "1"; } else { sourceExpression = identifier + "::" + sourceRateVariable.getName(); } String expression = sourceExpression + " * " + entity.getName() + "::firingsPerIteration"; DFUtilities.setExpressionIfNotDefined(port, "tokenProductionRate", expression); if (_debugging && VERBOSE) { _debug("Setting tokenProductionRate to " + expression); } } // Infer init production. // Note that this is a very simple type of inference... // However, in general, we don't want to try to // flatten this model... // Iterator connectedPorts = // port.insideSourcePortList().iterator(); // IOPort foundOutputPort = null; // int inferredRate = 0; // while (connectedPorts.hasNext()) { // IOPort connectedPort = (IOPort) connectedPorts.next(); // int newRate; // if (connectedPort.isOutput()) { // newRate = // DFUtilities.getTokenInitProduction(connectedPort); // } else { // newRate = 0; // } // // If we've already set the rate, then check that the // // rate for any other internal port is correct. // if (foundOutputPort != null && // newRate != inferredRate) { // throw new NotSchedulableException( // "External output port " + port // + " is connected on the inside to ports " // + "with different initial production: " // + foundOutputPort + " and " // + connectedPort); // } // foundOutputPort = connectedPort; // inferredRate = newRate; // } // DFUtilities._setIfNotDefined( // port, "tokenInitProduction", inferredRate); // if (_debugging && VERBOSE) { // _debug("Setting tokenInitProduction to " // + inferredRate); // } } else { throw new NotSchedulableException( port, "External port is neither an input and an output, " + "which is not allowed in SDF."); } } // Set the schedule to be valid. setValid(true); if (resultSchedule instanceof Schedule) { return (Schedule) resultSchedule; } else { // Must be ScheduleElement. Schedule schedule = new Schedule(); schedule.add((ScheduleElement) resultSchedule); return schedule; } }
/** * Interconnect all the remote actors in the same manner as the model's topology. In other words, * the connections defined by the model's topology are created virtually over the distributed * platform. For each actor, a portReceiverMap is created. A portReceiverMap is a data structure * representing for a given port the receivers it contains. In case the port is and input port it * consists of a set of receivers ID's i.e. (inputport, (ID1, ..., IDn). In case of an outputport, * it contains a map of services to receiver's IDs, i.e. (outputport, ((service1, (ID1, ..., IDi), * ..., (servicen, (IDj, ..., IDr))). This structure is sent over the network to the corresponding * service. The types of the port are also set on the remote actor. * * @exception IllegalActionException If the remote receivers can't be created. */ private void connectActors() throws IllegalActionException { if (VERBOSE) { System.out.println("Connecting Actors"); System.out.println(">> Creating Ports Receivers Map: "); } for (Iterator keysIterator = actorsThreadsMap.keySet().iterator(); keysIterator.hasNext(); ) { ComponentEntity actor = (ComponentEntity) keysIterator.next(); HashMap portsReceiversMap = new HashMap(); HashMap portTypes = new HashMap(); Iterator allPorts = actor.portList().iterator(); while (allPorts.hasNext()) { IOPort currentPort = (IOPort) allPorts.next(); Receiver[][] receivers = new Receiver[0][0]; if (currentPort.isOutput()) { receivers = currentPort.getRemoteReceivers(); } if (currentPort.isInput()) { receivers = currentPort.getReceivers(); } if (!currentPort.connectedPortList().isEmpty()) { portTypes.put(currentPort.getName(), ((TypedIOPort) currentPort).getType()); } if (receivers.length > 0) { if (VERBOSE) { System.out.print( "Port: " + currentPort.getFullName() + "\n" + DistributedUtilities.receiversArrayToString(receivers)); } if (currentPort.isOutput()) { portsReceiversMap.put(currentPort.getName(), createServicesReceiversMap(receivers)); } if (currentPort.isInput()) { portsReceiversMap.put( currentPort.getName(), DistributedUtilities.convertReceiversToIntegers(receivers)); } } } ServiceItem server = ((ClientThread) actorsThreadsMap.get(actor)).getService(); DistributedActor distributedActor = (DistributedActor) server.service; try { if (VERBOSE) { System.out.println( "Setting connections to: " + actor.getFullName() + " in: " + server.serviceID.toString()); System.out.println( "Setting port Types: " + actor.getFullName() + " in: " + server.serviceID.toString()); } distributedActor.setConnections(portsReceiversMap); distributedActor.setPortTypes(portTypes); } catch (RemoteException e) { KernelException.stackTraceToString(e); } } }