dol: initial dol commit
[jump.git] / dol / src / dol / check / SanityCheck.java
diff --git a/dol/src/dol/check/SanityCheck.java b/dol/src/dol/check/SanityCheck.java
new file mode 100644 (file)
index 0000000..88f82db
--- /dev/null
@@ -0,0 +1,419 @@
+/* $Id: SanityCheck.java 1 2010-02-24 13:03:05Z haidw $ */
+package dol.check;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Vector;
+
+import dol.datamodel.architecture.ArchiResource;
+import dol.datamodel.architecture.Architecture;
+import dol.datamodel.architecture.Configuration;
+import dol.datamodel.architecture.Processor;
+import dol.datamodel.mapping.Mapping;
+import dol.datamodel.pn.Channel;
+import dol.datamodel.pn.Connection;
+import dol.datamodel.pn.Process;
+import dol.datamodel.pn.ProcessNetwork;
+import dol.datamodel.pn.Resource;
+
+/**
+ * Check semantic correctness of process network.
+ *
+ * This class checks
+ * <ul><li>whether it is a processnetwork</li>
+ * <li>a channel only has two ports</li>
+ * <li>each channel port has only one peer port of process</li>
+ * </ul>
+ */
+public class SanityCheck {
+    /**
+     * Return the singleton instance of this class;
+     *
+     * @return  the instance.
+     */
+    public final static SanityCheck getInstance() {
+        return _instance;
+    }
+
+    /**
+     * Check if the process network spec is correct
+     *
+     * @param pn processnetwork to check
+     */
+    public void checkPN(ProcessNetwork pn) {
+        try {
+            _checkNameConflict(pn);
+            _checkChannelPorts(pn);
+            _checkChannelConnection(pn);
+        }
+        catch (Exception e) {
+            System.out.println("err: " + e.getMessage());
+            //e.printStackTrace();
+            System.exit(-1);
+        }
+
+        try {
+            _checkProcessConnection(pn);
+        }
+        catch (Exception e) {
+            System.out.println("warning: " + e.getMessage());
+        }
+    }
+   
+    /**
+     * Check if the architecture spec is correct
+     *
+     * @param arch architecture to check
+     */
+    public void checkArch(Architecture arch)
+    {
+       try
+       {
+               _checkNameConflict(arch);
+               _checkNETSIM(arch);
+            _checkMaster(arch);
+       }
+       catch (Exception e)
+       {
+               System.out.println("err: " + e.getMessage());
+               System.exit(-1);
+       }
+    }
+
+    /**
+     * Check if the mapping spec is correct
+     *
+     * @param map mapping to check
+     */
+    public void checkMap(Mapping map)
+    {
+       try
+       {
+            _checkMultibind(map);
+            _checkProcessesBound(map);
+       }
+       catch (Exception e)
+       {
+               System.out.println("err: " + e.getMessage());
+               System.exit(-1);
+       }
+    }
+
+
+    /**
+     * Check name exclusiveness, including processes, channels, and
+     * connections.
+     *
+     * @param pn processnetwork to check
+     */
+    private void _checkNameConflict(ProcessNetwork pn) throws Exception {
+        System.out.println("APPL: Checking resource name ...");
+
+        Vector<Resource> n = new Vector<Resource>(pn.getChannelList());
+        n.addAll(pn.getProcessList());
+        n.addAll(pn.getConnectionList());
+
+        //sort resources in n by name
+        Collections.sort(n,
+          new Comparator<Resource>()
+          {
+            public int compare(Resource resource1, Resource resource2) {
+              return resource1.getName().compareTo(resource2.getName());
+            }
+          } );
+
+        //test adjacent resources in n for equal name
+        for (int k = 0; k < n.size() - 1; k++)
+        {
+          if (((Resource) n.elementAt(k)).getName().equals(
+              ((Resource) n.elementAt(k + 1)).getName())) {
+            throw new Exception("Name conflict: " +
+                                ((Resource)n.elementAt(k + 1)).getName() +
+                                " appears (at least) twice.");
+          }
+        }
+    }
+
+    /**
+     * Check number of ports for every channel.
+     *
+     * @param pn processnetwork to check
+     */
+    private void _checkChannelPorts(ProcessNetwork pn) throws Exception {
+        System.out.println("APPL: Checking channel ports ...");
+
+        for (Channel c : pn.getChannelList()) {
+            if (c.getPortList().size() < 2) {
+                throw new Exception("channel ports less than 2: " +
+                                    c.getName());
+            }
+        }
+    }
+
+    /**
+     * Check whether all processes are connected.
+     *
+     * @param pn processnetwork to check
+     */
+    private void _checkProcessConnection(ProcessNetwork pn)
+        throws Exception {
+        System.out.println("APPL: Checking Process connection ...");
+
+        String result = "";
+        boolean hasUnused = false;
+        for (Process r : pn.getProcessList()) {
+            boolean flag = false;
+            for (Connection c : pn.getConnectionList()) {
+                Resource origin = c.getOrigin();
+                Resource target = c.getTarget();
+                if (r.getName().equals(origin.getName())) {
+                    flag = true; break;
+                } else if (r.getName().equals(target.getName())) {
+                    flag = true; break;
+                }
+            }
+            if (flag == false) {
+                hasUnused = true;
+                result += " " + r.getName();
+            }
+        }
+
+        if (hasUnused == true)
+            throw new Exception("process(es) without connection to channels:" + result);
+    }
+
+    /**
+     * Check whether there are unused channels in the processnetwork.
+     *
+     * @param pn processnetwork to check
+     */
+    private void _checkChannelConnection(ProcessNetwork pn)
+        throws Exception {
+        System.out.println("APPL: Checking channel connection ...");
+
+        String result = "";
+        boolean hasUnused = false;
+        for (Channel r : pn.getChannelList()) {
+            boolean flag = false;
+            for (Connection c: pn.getConnectionList()) {
+                Resource origin = c.getOrigin();
+                Resource target = c.getTarget();
+                if (r.getName().equals(origin.getName())) {
+                    flag = true; break;
+                } else if (r.getName().equals(target.getName())) {
+                    flag = true; break;
+                }
+            }
+            if (flag == false) {
+                hasUnused = true;
+                result += " " + r.getName();
+            }
+        }
+
+        if (hasUnused == true)
+            throw new Exception("unused channel: " + result);
+    }
+
+    
+    /**
+     * Check name exclusiveness, including both processors and memories.
+     *
+     * @param arch architecture to check
+     */
+    private void _checkNameConflict(Architecture arch) throws Exception {
+        System.out.println("ARCH: Checking resource name ...");
+        Vector<ArchiResource> n = new Vector<ArchiResource>(arch.getProcessorList());
+        n.addAll(arch.getMemoryList());
+
+        //sort resources in n by name
+        Collections.sort(n,
+          new Comparator<ArchiResource>()
+          {
+            public int compare(ArchiResource resource1, ArchiResource resource2) {
+              return resource1.getName().compareTo(resource2.getName());
+            }
+          } );
+
+        //test adjacent resources in n for equal name
+        for (int k = 0; k < n.size() - 1; k++)
+        {
+          if (((ArchiResource) n.elementAt(k)).getName().equals(
+              ((ArchiResource) n.elementAt(k + 1)).getName())) {
+            throw new Exception("Name conflict: " +
+                                ((ArchiResource)n.elementAt(k + 1)).getName() +
+                                " appears (at least) twice.");
+          }
+        }
+    }
+    
+    /**
+     * every processor of type NETSIM must have a configuration tag with
+     * name "address" and one with name "port". these address-port pairs
+     * have to be unique
+     * @param arch
+     * @throws Exception
+     */
+    private void _checkNETSIM(Architecture arch) throws Exception
+    {
+        System.out.println("ARCH: Checking network simulators ...");
+        
+        Vector<Processor> sockets = new Vector<Processor>();
+        
+        for (Processor proc : arch.getProcessorList()) {
+               if ( proc.getType().equals("NETSIM") )
+               {
+                       if ( proc.getCfg("address") == null 
+                        || proc.getCfg("port") == null )
+                {
+                               throw new Exception("Processor " + proc.getName() + 
+                            " is of type NETSIM but address or port is missing");
+                }
+                if ( proc.getCfg("address").equals("") 
+                        || proc.getCfg("port").equals("") )
+                {
+                    throw new Exception("Processor " + proc.getName() + 
+                            " has empty address or port");
+                }
+                sockets.add(proc);  // add processor to socket list
+               }
+       }
+        
+        /* socket comperator */
+        Comparator<Processor> sockComp = new Comparator<Processor>()
+        {
+            public int compare(Processor proc1, Processor proc2)
+            {
+                String ad1, ad2;
+                ad1 = proc1.getCfg("address").getValue();
+                ad2 = proc2.getCfg("address").getValue();
+                
+                int comp = ad1.compareToIgnoreCase(ad2);
+                
+                if (comp != 0)
+                {
+                    return comp;
+                }
+                else
+                {
+                    String p1, p2;
+                    p1 = proc1.getCfg("port").getValue();
+                    p2 = proc2.getCfg("port").getValue();
+                    
+                    return p1.compareToIgnoreCase(p2);
+                }
+            }
+        };
+        
+        
+       /* sort sockets */
+        Collections.sort(sockets, sockComp);
+        
+        /* check for uniqueness */
+        Processor proc1 = null;
+        Processor proc2 = null;
+        if (!sockets.isEmpty())
+            proc1 = sockets.get(0);
+        for (int i=1; i<sockets.size(); i++)
+        {
+            proc2 = sockets.get(i);
+            if (sockComp.compare(proc1, proc2) == 0)
+            {
+                throw new Exception("multiple processors with hostname \"" +
+                        proc1.getCfg("address").getValue() +
+                        "\" and port " + proc1.getCfg("port").getValue() +
+                        " exist");
+            }
+            proc1 = proc2;
+        }
+    } // _checkNETSIM()
+    
+    
+    /**
+     * Checks that exactly one master simulator is defined if
+     * processors of type "NETSIM" exist.
+     * @param arch the architecture to check 
+     * @throws Exception
+     */
+    private void _checkMaster(Architecture arch) throws Exception
+    {
+        boolean hasMaster = false;
+        boolean hasHosts = false;
+        
+        for (Processor p : arch.getProcessorList()) {
+            if (p.getType().equals("NETSIM"))
+            {
+                hasHosts = true;
+                Configuration opt = p.getCfg("master");
+                if (opt != null && opt.getValue().equals("true"))
+                {
+                    if (hasMaster)
+                        throw new Exception("multiple master simulators"
+                                + "defined");
+                    else
+                        hasMaster = true;
+                
+                }
+            }
+        }
+        
+        if (hasHosts && !hasMaster)
+            throw new Exception("no master simulator defined");
+        
+    } // _checkMaster()
+    
+    /**
+     * Check that software resources bind only to one hardware resource. 
+     *
+     * @param map mapping to check
+     */
+    private void _checkMultibind(Mapping map) throws Exception {
+        System.out.println("MAP: Checking multiple bindings ...");
+        Vector<Process> processes = map.getProcessList();
+        
+        //sort processes in n by name
+        Collections.sort(processes,
+                new Comparator<Process>()
+                {
+                  public int compare(Process p1, Process p2) {
+                    return p1.getName().compareTo(p2.getName());
+                  }
+                } );
+
+        //test adjacent origins for equal name
+        String o1 = null;
+        String o2 = null;
+        if (!processes.isEmpty())
+            o1 = processes.get(0).getName();
+        for (int k = 1; k < processes.size(); k++)
+        {
+            o2 = processes.get(k).getName();
+            if (o1.equals(o2))
+            {
+                throw new Exception("sw resource \"" + o1 +
+                        "\" has multiple bindings");
+            }
+        }
+    }
+    
+    /**
+     * Checks that every process is bound to a processor.
+     * @param map the map to check
+     * @throws Exception if not all processes are bound to a processor
+     */
+    private void _checkProcessesBound(Mapping map) throws Exception
+    {
+        System.out.println("MAP: Checking that all processes have a binding ...");
+        Vector<Process> boundList = map.getProcessList();
+        Vector<Process> totalList = map.getPN().getProcessList();
+        
+        if (boundList.size() != totalList.size())
+        {
+            throw new Exception("some processes are not bound to a processor");
+        }
+    }
+    
+    /**
+     * singleton instance
+     */
+    private final static SanityCheck _instance = new SanityCheck();
+}