dol: initial dol commit
[jump.git] / dol / src / dol / check / SanityCheck.java
1 /* $Id: SanityCheck.java 1 2010-02-24 13:03:05Z haidw $ */
2 package dol.check;
3
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.Vector;
7
8 import dol.datamodel.architecture.ArchiResource;
9 import dol.datamodel.architecture.Architecture;
10 import dol.datamodel.architecture.Configuration;
11 import dol.datamodel.architecture.Processor;
12 import dol.datamodel.mapping.Mapping;
13 import dol.datamodel.pn.Channel;
14 import dol.datamodel.pn.Connection;
15 import dol.datamodel.pn.Process;
16 import dol.datamodel.pn.ProcessNetwork;
17 import dol.datamodel.pn.Resource;
18
19 /**
20  * Check semantic correctness of process network.
21  *
22  * This class checks
23  * <ul><li>whether it is a processnetwork</li>
24  * <li>a channel only has two ports</li>
25  * <li>each channel port has only one peer port of process</li>
26  * </ul>
27  */
28 public class SanityCheck {
29     /**
30      * Return the singleton instance of this class;
31      *
32      * @return  the instance.
33      */
34     public final static SanityCheck getInstance() {
35         return _instance;
36     }
37
38     /**
39      * Check if the process network spec is correct
40      *
41      * @param pn processnetwork to check
42      */
43     public void checkPN(ProcessNetwork pn) {
44         try {
45             _checkNameConflict(pn);
46             _checkChannelPorts(pn);
47             _checkChannelConnection(pn);
48         }
49         catch (Exception e) {
50             System.out.println("err: " + e.getMessage());
51             //e.printStackTrace();
52             System.exit(-1);
53         }
54
55         try {
56             _checkProcessConnection(pn);
57         }
58         catch (Exception e) {
59             System.out.println("warning: " + e.getMessage());
60         }
61     }
62    
63     /**
64      * Check if the architecture spec is correct
65      *
66      * @param arch architecture to check
67      */
68     public void checkArch(Architecture arch)
69     {
70         try
71         {
72                 _checkNameConflict(arch);
73                 _checkNETSIM(arch);
74             _checkMaster(arch);
75         }
76         catch (Exception e)
77         {
78                 System.out.println("err: " + e.getMessage());
79                 System.exit(-1);
80         }
81     }
82
83     /**
84      * Check if the mapping spec is correct
85      *
86      * @param map mapping to check
87      */
88     public void checkMap(Mapping map)
89     {
90         try
91         {
92             _checkMultibind(map);
93             _checkProcessesBound(map);
94         }
95         catch (Exception e)
96         {
97                 System.out.println("err: " + e.getMessage());
98                 System.exit(-1);
99         }
100     }
101
102
103     /**
104      * Check name exclusiveness, including processes, channels, and
105      * connections.
106      *
107      * @param pn processnetwork to check
108      */
109     private void _checkNameConflict(ProcessNetwork pn) throws Exception {
110         System.out.println("APPL: Checking resource name ...");
111
112         Vector<Resource> n = new Vector<Resource>(pn.getChannelList());
113         n.addAll(pn.getProcessList());
114         n.addAll(pn.getConnectionList());
115
116         //sort resources in n by name
117         Collections.sort(n,
118           new Comparator<Resource>()
119           {
120             public int compare(Resource resource1, Resource resource2) {
121               return resource1.getName().compareTo(resource2.getName());
122             }
123           } );
124
125         //test adjacent resources in n for equal name
126         for (int k = 0; k < n.size() - 1; k++)
127         {
128           if (((Resource) n.elementAt(k)).getName().equals(
129               ((Resource) n.elementAt(k + 1)).getName())) {
130             throw new Exception("Name conflict: " +
131                                 ((Resource)n.elementAt(k + 1)).getName() +
132                                 " appears (at least) twice.");
133           }
134         }
135     }
136
137     /**
138      * Check number of ports for every channel.
139      *
140      * @param pn processnetwork to check
141      */
142     private void _checkChannelPorts(ProcessNetwork pn) throws Exception {
143         System.out.println("APPL: Checking channel ports ...");
144
145         for (Channel c : pn.getChannelList()) {
146             if (c.getPortList().size() < 2) {
147                 throw new Exception("channel ports less than 2: " +
148                                     c.getName());
149             }
150         }
151     }
152
153     /**
154      * Check whether all processes are connected.
155      *
156      * @param pn processnetwork to check
157      */
158     private void _checkProcessConnection(ProcessNetwork pn)
159         throws Exception {
160         System.out.println("APPL: Checking Process connection ...");
161
162         String result = "";
163         boolean hasUnused = false;
164         for (Process r : pn.getProcessList()) {
165             boolean flag = false;
166             for (Connection c : pn.getConnectionList()) {
167                 Resource origin = c.getOrigin();
168                 Resource target = c.getTarget();
169                 if (r.getName().equals(origin.getName())) {
170                     flag = true; break;
171                 } else if (r.getName().equals(target.getName())) {
172                     flag = true; break;
173                 }
174             }
175             if (flag == false) {
176                 hasUnused = true;
177                 result += " " + r.getName();
178             }
179         }
180
181         if (hasUnused == true)
182             throw new Exception("process(es) without connection to channels:" + result);
183     }
184
185     /**
186      * Check whether there are unused channels in the processnetwork.
187      *
188      * @param pn processnetwork to check
189      */
190     private void _checkChannelConnection(ProcessNetwork pn)
191         throws Exception {
192         System.out.println("APPL: Checking channel connection ...");
193
194         String result = "";
195         boolean hasUnused = false;
196         for (Channel r : pn.getChannelList()) {
197             boolean flag = false;
198             for (Connection c: pn.getConnectionList()) {
199                 Resource origin = c.getOrigin();
200                 Resource target = c.getTarget();
201                 if (r.getName().equals(origin.getName())) {
202                     flag = true; break;
203                 } else if (r.getName().equals(target.getName())) {
204                     flag = true; break;
205                 }
206             }
207             if (flag == false) {
208                 hasUnused = true;
209                 result += " " + r.getName();
210             }
211         }
212
213         if (hasUnused == true)
214             throw new Exception("unused channel: " + result);
215     }
216
217     
218     /**
219      * Check name exclusiveness, including both processors and memories.
220      *
221      * @param arch architecture to check
222      */
223     private void _checkNameConflict(Architecture arch) throws Exception {
224         System.out.println("ARCH: Checking resource name ...");
225         Vector<ArchiResource> n = new Vector<ArchiResource>(arch.getProcessorList());
226         n.addAll(arch.getMemoryList());
227
228         //sort resources in n by name
229         Collections.sort(n,
230           new Comparator<ArchiResource>()
231           {
232             public int compare(ArchiResource resource1, ArchiResource resource2) {
233               return resource1.getName().compareTo(resource2.getName());
234             }
235           } );
236
237         //test adjacent resources in n for equal name
238         for (int k = 0; k < n.size() - 1; k++)
239         {
240           if (((ArchiResource) n.elementAt(k)).getName().equals(
241               ((ArchiResource) n.elementAt(k + 1)).getName())) {
242             throw new Exception("Name conflict: " +
243                                 ((ArchiResource)n.elementAt(k + 1)).getName() +
244                                 " appears (at least) twice.");
245           }
246         }
247     }
248     
249     /**
250      * every processor of type NETSIM must have a configuration tag with
251      * name "address" and one with name "port". these address-port pairs
252      * have to be unique
253      * @param arch
254      * @throws Exception
255      */
256     private void _checkNETSIM(Architecture arch) throws Exception
257     {
258         System.out.println("ARCH: Checking network simulators ...");
259         
260         Vector<Processor> sockets = new Vector<Processor>();
261         
262         for (Processor proc : arch.getProcessorList()) {
263                 if ( proc.getType().equals("NETSIM") )
264                 {
265                         if ( proc.getCfg("address") == null 
266                         || proc.getCfg("port") == null )
267                 {
268                                 throw new Exception("Processor " + proc.getName() + 
269                             " is of type NETSIM but address or port is missing");
270                 }
271                 if ( proc.getCfg("address").equals("") 
272                         || proc.getCfg("port").equals("") )
273                 {
274                     throw new Exception("Processor " + proc.getName() + 
275                             " has empty address or port");
276                 }
277                 sockets.add(proc);  // add processor to socket list
278                 }
279         }
280         
281         /* socket comperator */
282         Comparator<Processor> sockComp = new Comparator<Processor>()
283         {
284             public int compare(Processor proc1, Processor proc2)
285             {
286                 String ad1, ad2;
287                 ad1 = proc1.getCfg("address").getValue();
288                 ad2 = proc2.getCfg("address").getValue();
289                 
290                 int comp = ad1.compareToIgnoreCase(ad2);
291                 
292                 if (comp != 0)
293                 {
294                     return comp;
295                 }
296                 else
297                 {
298                     String p1, p2;
299                     p1 = proc1.getCfg("port").getValue();
300                     p2 = proc2.getCfg("port").getValue();
301                     
302                     return p1.compareToIgnoreCase(p2);
303                 }
304             }
305         };
306         
307         
308         /* sort sockets */
309         Collections.sort(sockets, sockComp);
310         
311         /* check for uniqueness */
312         Processor proc1 = null;
313         Processor proc2 = null;
314         if (!sockets.isEmpty())
315             proc1 = sockets.get(0);
316         for (int i=1; i<sockets.size(); i++)
317         {
318             proc2 = sockets.get(i);
319             if (sockComp.compare(proc1, proc2) == 0)
320             {
321                 throw new Exception("multiple processors with hostname \"" +
322                         proc1.getCfg("address").getValue() +
323                         "\" and port " + proc1.getCfg("port").getValue() +
324                         " exist");
325             }
326             proc1 = proc2;
327         }
328     } // _checkNETSIM()
329     
330     
331     /**
332      * Checks that exactly one master simulator is defined if
333      * processors of type "NETSIM" exist.
334      * @param arch the architecture to check 
335      * @throws Exception
336      */
337     private void _checkMaster(Architecture arch) throws Exception
338     {
339         boolean hasMaster = false;
340         boolean hasHosts = false;
341         
342         for (Processor p : arch.getProcessorList()) {
343             if (p.getType().equals("NETSIM"))
344             {
345                 hasHosts = true;
346                 Configuration opt = p.getCfg("master");
347                 if (opt != null && opt.getValue().equals("true"))
348                 {
349                     if (hasMaster)
350                         throw new Exception("multiple master simulators"
351                                 + "defined");
352                     else
353                         hasMaster = true;
354                 
355                 }
356             }
357         }
358         
359         if (hasHosts && !hasMaster)
360             throw new Exception("no master simulator defined");
361         
362     } // _checkMaster()
363     
364     /**
365      * Check that software resources bind only to one hardware resource. 
366      *
367      * @param map mapping to check
368      */
369     private void _checkMultibind(Mapping map) throws Exception {
370         System.out.println("MAP: Checking multiple bindings ...");
371         Vector<Process> processes = map.getProcessList();
372         
373         //sort processes in n by name
374         Collections.sort(processes,
375                 new Comparator<Process>()
376                 {
377                   public int compare(Process p1, Process p2) {
378                     return p1.getName().compareTo(p2.getName());
379                   }
380                 } );
381
382         //test adjacent origins for equal name
383         String o1 = null;
384         String o2 = null;
385         if (!processes.isEmpty())
386             o1 = processes.get(0).getName();
387         for (int k = 1; k < processes.size(); k++)
388         {
389             o2 = processes.get(k).getName();
390             if (o1.equals(o2))
391             {
392                 throw new Exception("sw resource \"" + o1 +
393                         "\" has multiple bindings");
394             }
395         }
396     }
397     
398     /**
399      * Checks that every process is bound to a processor.
400      * @param map the map to check
401      * @throws Exception if not all processes are bound to a processor
402      */
403     private void _checkProcessesBound(Mapping map) throws Exception
404     {
405         System.out.println("MAP: Checking that all processes have a binding ...");
406         Vector<Process> boundList = map.getProcessList();
407         Vector<Process> totalList = map.getPN().getProcessList();
408         
409         if (boundList.size() != totalList.size())
410         {
411             throw new Exception("some processes are not bound to a processor");
412         }
413     }
414     
415     /**
416      * singleton instance
417      */
418     private final static SanityCheck _instance = new SanityCheck();
419 }