package net.sf.orcc.tools.mapping; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import net.sf.orcc.df.Actor; import net.sf.orcc.df.Connection; import net.sf.orcc.df.Instance; import net.sf.orcc.df.Network; import net.sf.orcc.df.Port; import net.sf.orcc.df.transform.NetworkFlattener; import net.sf.orcc.df.util.DfVisitor; import net.sf.orcc.ir.util.ValueUtil; import net.sf.orcc.util.OrccLogger; import net.sf.orcc.util.OrccUtil; /** * This class defines an XML buffer size configuration loader and importer. In * works only for flattened networks (ref. to {@link NetworkFlattener} * transformation). The xml file format is basically the following: * * <pre> * <bxdf network="qualifiedName" default-size="value"> * <connection source-actor="name" source-port="name" target-actor="name" target-port="name" size="value"/> * <connection source-actor="name" source-port="name" target-actor="name" target-port="name" size="value"/> * </bxdf> * </pre> * * @author Simone Casale Brunet * @author Endri Bezati * */ public class XmlBufferSizeConfiguration { private class BufferSizeAttributeReader extends DfVisitor<Void> { @Override public Void caseConnection(Connection connection) { if (connection.getSource() instanceof Actor && connection.getTarget() instanceof Actor && connection.getSize() != null) { String sourceActor = ((Actor) connection.getSource()).getName(); String sourcePort = connection.getSourcePort().getName(); String targetActor = ((Actor) connection.getTarget()).getName(); String targetPort = connection.getTargetPort().getName(); int size = connection.getSize(); XmlConnection xmlConnection = new XmlConnection(sourceActor, sourcePort, targetActor, targetPort, size); connections.add(xmlConnection); } return null; } } private class BufferSizeAttributeWriter extends DfVisitor<Void> { @Override public Void caseConnection(Connection connection) { int size = defaultSize; for (XmlConnection c : connections) { if (c.equal(connection)) { size = c.size; if (forcePow2 && !ValueUtil.isPowerOfTwo(size)) { OrccLogger.warnln("Buffer size of " + connection + " is not pow of two. It will be rounded"); size = roundPow2(size); } break; } } connection.setSize(size); return null; } public Void caseNetwork(Network network) { super.caseNetwork(network); if (brodcast) { Map<Port, List<Connection>> portsMap = new HashMap<Port, List<Connection>>(); for (Connection c : network.getConnections()) { Port port = c.getSourcePort(); List<Connection> pConns = portsMap.get(port); if (pConns == null) { pConns = new ArrayList<Connection>(); portsMap.put(port, pConns); } pConns.add(c); } for (List<Connection> portConns : portsMap.values()) { if (portConns.size() > 1) { // compute the maximal size int maxSize = 0; for (Connection c : portConns) { Integer value = c.getSize(); if (value != null) { maxSize = Math.max(maxSize, value.intValue()); } } if (maxSize != 0) { for (Connection c : portConns) { c.setSize(maxSize); } } } } } return null; } } private class XmlConnection implements Comparable<XmlConnection> { private final String sourceActor; private final String sourcePort; private final String targetActor; private final String targetPort; private final int size; private XmlConnection(String sourceActor, String sourcePort, String targetActor, String targetPort, int size) { this.sourceActor = sourceActor; this.sourcePort = sourcePort; this.targetActor = targetActor; this.targetPort = targetPort; this.size = size; } @Override public int compareTo(XmlConnection o) { return o != null ? toString().compareTo(o.toString()) : -1; } private boolean equal(Connection connection) { if (connection.getSourcePort().getName().equals(sourcePort) && connection.getTargetPort().getName().equals(targetPort)) { if (connection.getSource() instanceof Actor && connection.getTarget() instanceof Actor) { return ((Actor) connection.getSource()).getName().equals(sourceActor) && ((Actor) connection.getTarget()).getName().equals(targetActor); } else if ((connection.getSource() instanceof Instance && connection.getTarget() instanceof Instance)) { return ((Instance) connection.getSource()).getName().equals(sourceActor) && ((Instance) connection.getTarget()).getName().equals(targetActor); } } return false; } @Override public String toString() { StringBuffer b = new StringBuffer(); b.append(sourceActor != null ? sourceActor : ""); b.append(","); b.append(sourcePort != null ? sourcePort : ""); b.append(","); b.append(targetActor != null ? targetActor : ""); b.append(","); b.append(targetPort != null ? targetPort : ""); return b.toString(); } } private static final String XML_BXDF = "bxdf"; private static final String XML_NETWORK = "network"; private static final String XML_DEFAULT_SIZE = "default-size"; private static final String XML_CONNECTION = "connection"; private static final String XML_SOURCE_ACTOR = "source-actor"; private static final String XML_TARGET_ACTOR = "target-actor"; private static final String XML_SOURCE_PORT = "source-port"; private static final String XML_TARGET_PORT = "target-port"; private static final String XML_SIZE = "size"; private final boolean forcePow2, brodcast; private List<XmlConnection> connections; private int defaultSize; private String networkName; /** * Create a new loader * * @param forcePow2 * <code>true</code> if all the sizes should be with a pow of 2 * size. When parsing, if the value is not a pow of 2, then the * value is rounded to the next biggest pow of 2 value * @param broadcast * <code>true</code> if for broadcast ports (with 1:N * connections) the size should be different. In this case the * biggest will be used for all the outgoing connections of an * output port */ public XmlBufferSizeConfiguration(boolean forcePow2, boolean broadcast) { this.forcePow2 = forcePow2; this.brodcast = broadcast; } /** * Load the buffer size configuration contained in this file. If there are * no buffer size defined for a {@link Connection}, than the * <code>default-size</code> defined in the file will be used. After loading * the file you can retrieve the connection size using * {@link Connection#getSize()}. * * @param file * @param network */ public void load(File file, Network network) { connections = new ArrayList<XmlConnection>(); networkName = OrccUtil.getQualifiedName(network.getFile()); loadXmlConnections(file); new BufferSizeAttributeWriter().doSwitch(network); } private void loadXmlConnections(File file) { try { // parse the input file InputStream stream = new FileInputStream(file); stream = new BufferedInputStream(stream); XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); XMLStreamReader reader = xmlFactory.createXMLStreamReader(stream); while (reader.hasNext()) { reader.next(); if (reader.getEventType() == XMLStreamReader.START_ELEMENT) { if (reader.getLocalName().equals(XML_CONNECTION)) { try { String source = reader.getAttributeValue("", XML_SOURCE_ACTOR); String target = reader.getAttributeValue("", XML_TARGET_ACTOR); String sourcePort = reader.getAttributeValue("", XML_SOURCE_PORT); String targetPort = reader.getAttributeValue("", XML_TARGET_PORT); String size = reader.getAttributeValue("", XML_SIZE); if (source != null && target != null && sourcePort != null && targetPort != null && OrccUtil.isNumeric(size)) { // it seams ok: add it to the list XmlConnection c = new XmlConnection(source, sourcePort, target, targetPort, Integer.parseInt(size)); connections.add(c); } } catch (Exception e) { // FIXME add a warning? e.printStackTrace(); } } else if (reader.getLocalName().equals(XML_BXDF)) { String name = reader.getAttributeValue("", XML_NETWORK); if (name == null || !name.equals(networkName)) { OrccLogger.warn( "The network name of the configuration does not match with the network you are using"); } String size = reader.getAttributeValue("", XML_DEFAULT_SIZE); if (!OrccUtil.isNumeric(size)) { OrccLogger.warn( "The default buffer size value is not valid: 512 will be assigned by default"); defaultSize = 512; } else { defaultSize = Integer.parseInt(size); if (forcePow2 && !ValueUtil.isPowerOfTwo(defaultSize)) { OrccLogger.warn( "The default buffer size value is not a pow of two value. It will be rounded"); defaultSize = roundPow2(defaultSize); } } } } else if (reader.getEventType() == XMLStreamReader.END_ELEMENT && reader.getLocalName().equals(XML_BXDF)) { break; } } } catch (FileNotFoundException e) { OrccLogger.severeln("Buffer size configuration file not found: " + e.getMessage()); } catch (Exception e) { OrccLogger.severeln("Error parsing the buffer size configuration file: " + e.getMessage()); } } private int roundPow2(int value) { double tmp = Math.log(value) / Math.log(2.0); return (int) Math.pow(2, Math.ceil(tmp)); } /** * Write the xml configuration for the given network and the given default * buffer size. Note that only buffers that have the size attribute defined * will be exported. * * @param file * @param network * @param defaultSize */ public void write(File file, Network network, int defaultSize) { this.defaultSize = defaultSize; networkName = OrccUtil.getQualifiedName(network.getFile()); connections = new ArrayList<XmlConnection>(); new BufferSizeAttributeReader().doSwitch(network); writeXmlConnections(file); } private void writeXmlConnections(File file) { try { OutputStream stream = new FileOutputStream(file); stream = new BufferedOutputStream(stream); XMLOutputFactory factory = XMLOutputFactory.newInstance(); XMLStreamWriter writer = factory.createXMLStreamWriter(stream); writer.writeStartDocument(); writer.writeStartElement(XML_BXDF); writer.writeAttribute(XML_NETWORK, networkName); writer.writeAttribute(XML_DEFAULT_SIZE, Integer.toString(defaultSize)); // sort the xml connections Collections.sort(connections); // write all the registered connections for (XmlConnection c : connections) { writer.writeEmptyElement(XML_CONNECTION); writer.writeAttribute(XML_SOURCE_ACTOR, c.sourceActor); writer.writeAttribute(XML_SOURCE_PORT, c.sourcePort); writer.writeAttribute(XML_TARGET_ACTOR, c.targetActor); writer.writeAttribute(XML_TARGET_PORT, c.targetPort); writer.writeAttribute(XML_SIZE, Integer.toString(c.size)); } writer.writeEndElement(); // end bxdf writer.writeEndDocument(); writer.close(); stream.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (XMLStreamException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }