dol: initial dol commit
[jump.git] / dol / src / dol / visitor / cell / CellSPEVisitor.java
1 package dol.visitor.cell;
2
3 import java.io.File;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.OutputStream;
7 import java.io.PrintStream;
8 import java.util.ArrayList;
9 import java.util.StringTokenizer;
10 import java.util.Vector;
11
12 import dol.datamodel.pn.Channel;
13 import dol.datamodel.pn.Port;
14 import dol.datamodel.pn.Process;
15 import dol.datamodel.pn.ProcessNetwork;
16 import dol.visitor.PNVisitor;
17 import dol.util.CodePrintStream;
18
19 /**
20  * This class is a class for a visitor that is used to generate the the OS for
21  * the SPEs.
22  *
23  * @author lschor, 2009-03-24 * Revision: 2009-03-24: Created
24  */
25 public class CellSPEVisitor extends PNVisitor {
26
27     /**
28      * Constructor.
29      *
30      * @param dir
31      *            path of this file
32      */
33     public CellSPEVisitor(String dir, CellMapping mapping) {
34         _dir = dir;
35         _mapping = mapping;
36     }
37
38     /**
39      * Visit process network.
40      *
41      * @param x
42      *            process network that needs to be rendered
43      */
44     public void visitComponent(ProcessNetwork x) {
45         try {
46             // Create a directory where all SPU's are stored:
47             _spuDir = _dir + _delimiter + "spu";
48             File dir = new File(_spuDir);
49             dir.mkdirs();
50
51             // Copy the header file to this directory
52             // Some library files must be copied to the main directory
53             (new File(_dir + _delimiter + "lib" + _delimiter + "spu_os.h"))
54                     .renameTo(new File(dir.getPath() + _delimiter
55                             + "spu_os.h"));
56
57             ArrayList<Vector<Process>> spuList = _mapping.getSPUList();
58
59             int i = 0;
60             for (Vector<Process> spu : spuList) {
61                 createOSLayer(x, spu, i++);
62             }
63
64             createMakefileSPU();
65
66         } catch (Exception e) {
67             System.out.println("CellSPEVisitor: exception occured: "
68                     + e.getMessage());
69             e.printStackTrace();
70         }
71     }
72
73     /**
74      * Create the makefile for a SPU (so for the layer). Each SPU gets its own
75      * Makefile
76      *
77      * @param spu
78      *            SPU for which the Makefile should be used
79      */
80     protected void createMakefileSPU() {
81         try {
82             // Directory of the process
83             String spuDir = _dir + _delimiter + "spu";
84
85             // Create the filename for the new wrapper
86             String filename = spuDir + _delimiter + "Makefile";
87
88             OutputStream file = new FileOutputStream(filename);
89
90             PrintStream _makefilePS = new CodePrintStream(file);
91
92             _makefilePS.println("# Makefile for SPU OS");
93             _makefilePS.println("");
94             _makefilePS.println("src := $(wildcard ../lib/spu/*.cpp)");
95             _makefilePS.println("obj = $(src:.cpp=.o)");
96             _makefilePS.println("");
97
98             // The Makefile must include all o-Files of the processes needed
99             String dependency = "";
100
101             // Go through all possible processes
102             for (Process p : _mapping.getAllSpuBaseProcess()) {
103                 dependency += " .." + _delimiter + "spu_"
104                         + p.getBasename() + _delimiter + p.getBasename()
105                         + "Wrapper.o";
106             }
107
108             _makefilePS.println("all: ${obj}" + dependency);
109             for (int i = 0; i < _mapping.getNrSPE(); i++) {
110                 _makefilePS.println("\tspu-g++ -Wall -I .. -I ../lib -o "
111                         + "spu_os_" + i + " spu_os_" + i + ".cpp "
112                         + "../lib/spu/Fifo.o ../lib/spu/WindowedFifo.o "
113                         + "../lib/spu/dolSupport.o "
114                         + "../lib/spu/proc_wrapper.o ../lib/spu/common.o "
115                         + "../lib/spu/FastCommunication.o" + dependency
116                         + " -ftree-vectorize -lm -mtune=cell -O3"
117                         + " -fmodulo-sched -funroll-loops "
118                         + " -ffast-math -fno-rtti -ffunction-sections"
119                         + " -fdata-sections -Wl,--gc-sections");
120             }
121             _makefilePS.println();
122             _makefilePS.println("clean: ");
123             for (int i = 0; i < _mapping.getNrSPE(); i++) {
124                 _makefilePS.println("\trm spu_os_" + i);
125             }
126             _makefilePS.println();
127             _makefilePS.println("%.o : ");
128             _makefilePS.println("\tspu-g++ -c -o $(*D)/$(*F).o "
129                     + "$(*D)/$(*F).cpp -I .. -I"
130                     + " ../lib -ftree-vectorize -mtune=cell -O3"
131                     + " -fmodulo-sched -funroll-loops -ffast-math"
132                     + " -fno-rtti -ffunction-sections -fdata-sections");
133             _makefilePS.println();
134         } catch (FileNotFoundException e) {
135             System.out.println("CbeProcessVisitor - Makefile: exception "
136                     + "occured: " + e.getMessage());
137             e.printStackTrace();
138         }
139     }
140
141     /**
142      * Creates the OS layer for one SPU
143      *
144      * @param spu
145      *            List of all processes a SPU gets
146      * @param index
147      *            index of the SPU in the SPU list
148      */
149     protected void createOSLayer(ProcessNetwork x, Vector<Process> spu,
150             int index) {
151         try {
152             // Create the filename for the new layer
153             String filename = _spuDir + _delimiter + "spu_os_" + index
154                     + ".cpp";
155
156             // PrintStream for writing to the file
157             OutputStream file = new FileOutputStream(filename);
158             CodePrintStream _code = new CodePrintStream(file);
159
160             _code.println("/****************************************************************");
161             _code.println(" *   SPU OS file");
162             _code.println(" *   Description: OS for one SPU");
163             _code.println(" */");
164             _code.println();
165             _code.println("#include \"spu_os.h\"");
166
167             // Must include all possible wrappers
168             Vector<String> pList = new Vector<String>();
169             // Go through all possible processes
170             for (Process p : spu) {
171                 String basename = p.getBasename();
172                 if (!pList.contains(basename)) {
173                     pList.add(basename);
174                     _code.println("#include \".." + _delimiter + "spu_"
175                             + p.getBasename() + _delimiter
176                             + p.getBasename() + "Wrapper.h\"");
177                 }
178             }
179
180             _code.println("");
181             _code.println("// Main application");
182             _code.println("int main(int speid , uint64_t argp)");
183             _code.println("{");
184             _code.println("    // reserve DMA tag ID");
185             _code.println("    uint32_t tag_id;");
186             _code.println("    if((tag_id=mfc_tag_reserve())==MFC_TAG_INVALID){");
187             _code.println("        printf(\"SPE: ERROR - can't reserve a tag ID\"); return 1;");
188             _code.println("    }");
189             _code.println("    ");
190             _code.println("    // Get the context information for the whole system");
191             _code.println("    mfc_get((void*) &ctx_spu, argp, sizeof(ctx_spu), tag_id, 0, 0);");
192             _code.println("    mfc_write_tag_mask(1<<tag_id);");
193             _code.println("    mfc_read_tag_status_all();");
194             _code.println("    ");
195             _code.println("    // This is the number of processes of this SPE");
196             _code.println("    uint64_t nr_proc = ctx_spu.procContentsLen;");
197             _code.println("    ");
198             _code.println("    // Get the addresses of the contexts for the Processes");
199             _code.println("    uint64_t context_addr[nr_proc];");
200             _code.println("    mfc_get((void*)context_addr, ctx_spu.procContents, sizeof(uint64_t) * roundDMA(nr_proc), tag_id,0,0);");
201             _code.println("    ");
202             _code.println("    mfc_write_tag_mask(1<<tag_id);");
203             _code.println("    mfc_read_tag_status_all();");
204             _code.println("    ");
205             _code.println("    int32_t queueFromSPU[roundDMA(NUM_FIFO)] __attribute__ ((aligned(16)));");
206             _code.println("    int32_t queueOnSPU[roundDMA(NUM_FIFO)]  __attribute__ ((aligned(16)));");
207             _code.println("    uint64_t tailAddresses[roundDMA(NUM_FIFO)] __attribute__ ((aligned(16)));");
208             _code.println("    ");
209             _code.println("    mfc_get((void*)queueFromSPU, ctx_spu.queueFromSPU, sizeof(int32_t) * roundDMA(NUM_FIFO), tag_id,0,0);");
210             _code.println("    mfc_write_tag_mask(1<<tag_id);");
211             _code.println("    mfc_read_tag_status_all();");
212             _code.println("    ");
213             _code.println("    mfc_get((void*)queueOnSPU, ctx_spu.queueOnSPU, sizeof(int32_t) * roundDMA(NUM_FIFO), tag_id,0,0);");
214             _code.println("    mfc_write_tag_mask(1<<tag_id);");
215             _code.println("    mfc_read_tag_status_all();");
216             _code.println("");
217             _code.println("    // Get the base addresses");
218             _code.println("    uint64_t procContentsAll[roundDMA(NUM_SPES)] __attribute__ ((aligned(16)));");
219             _code.println("    ");
220             _code.println("    mfc_get((void*)procContentsAll, ctx_spu.procContentsAll, sizeof(uint64_t) * roundDMA(NUM_SPES), tag_id,0,0);");
221             _code.println("    mfc_write_tag_mask(1<<tag_id);");
222             _code.println("    mfc_read_tag_status_all();");
223             _code.println("    ");
224             _code.println("    // Read the base address");
225             _code.println("    uint64_t ea_base = ctx_spu.ea_base;");
226             _code.println("    ");
227
228             Vector<Channel> channelList = new Vector<Channel>();
229             int indx = 0;
230             // instantiate channels
231             for (Channel c : x.getChannelList()) {
232                 if (spu.contains(c.getOrigin())
233                         || spu.contains(c.getTarget())) {
234                     channelList.add(c);
235                     if (c.getType().equals("fifo")) {
236                         _code.printPrefixln("    Fifo " + c.getName() + "("
237                                 + "FIFO_SIZE[" + indx + "]);");
238                     } else if (c.getType().equals("wfifo")) {
239                         _code.printPrefixln("    WindowedFifo "
240                                 + c.getName() + "(" + "FIFO_SIZE[" + indx
241                                 + "]);");
242                     }
243                 }
244                 indx++;
245             }
246
247             _code.println();
248
249             // Go through all processes
250             for (Process p : spu) {
251                 // Create the process wrapper
252                 _code.println("    " + p.getBasename() + "Wrapper *" + p.getName() +";");
253                 _code.println("    try { "
254                         + p.getName() + " = new " + p.getBasename()
255                         + "Wrapper (context_addr[" + spu.indexOf(p)
256                         + "]); }");
257                 _code.println("    catch(std::bad_alloc &e) {");
258                 _code.println("        fprintf(stderr, \"[" + p.getBasename() +"Wrapper] Memory allocation failure\\n\");");
259                 _code.println("        exit(1);");
260                 _code.println("    }");
261
262                 // Create the port-mapping
263                 for (Port port : p.getPortList()) {
264                     if (port.getName().equals(port.getBasename())) {
265                         _code.printPrefixln("    " + p.getName() + "->_port"
266                                 + port.getName() + "Fifo = &"
267                                 + port.getPeerResource().getName() + ";");
268                     } else {
269                         _code.printPrefix("    " + p.getName() + "->_port"
270                                 + port.getBasename() + "Fifo");
271                         StringTokenizer tokenizer = new StringTokenizer(
272                                 port.getName().replaceFirst(
273                                         port.getBasename(), ""), "_");
274                         while (tokenizer.hasMoreTokens()) {
275                             _code.print("[" + tokenizer.nextToken() + "]");
276                         }
277                         _code.println(" = &"
278                                 + port.getPeerResource().getName() + ";");
279                     }
280                 }
281                 _code.println();
282             }
283
284             // Count the effected channels
285             int countChannels = 0;
286             for (Channel c : channelList) {
287                 if (spu.contains(c.getOrigin())
288                         && spu.contains(c.getTarget())) {
289                     continue;
290                 } else if (spu.contains(c.getOrigin()))
291                     countChannels++;
292                 else if (spu.contains(c.getTarget()))
293                     countChannels++;
294                 else
295                     System.out.println("ERROR! Channel Mapping is wrong.");
296             }
297
298             _code.println("    // inited all queues, now one has to know:");
299             _code.println("    // sends out the start addresses to the SPU (of all out channels)");
300
301             // Check all out queues on the SPU
302             _code.println("    uint32_t queuemessage;");
303             for (Channel c : channelList) {
304                 if (spu.contains(c.getOrigin()) && !spu.contains(c.getTarget())) {
305                     _code.println("    queuemessage = CREATEQUEUEMESSAGE(" + x.getChannelList().indexOf(c) + ", (uint32_t)" + c.getName() + ".getQueuePointer());");
306                     _code.println("    spu_write_out_mbox(queuemessage);");
307                 }
308             }
309
310             _code.println("    ");
311             _code.println("    // Wait until we get the okey to read the tail pointers");
312             _code.println("    uint32_t messageIn = spu_read_in_mbox();");
313             _code.println("");
314             _code.println("    mfc_get((void*)tailAddresses, ctx_spu.fifoTails, sizeof(uint64_t) * roundDMA(NUM_FIFO), tag_id,0,0);");
315             _code.println("    mfc_write_tag_mask(1<<tag_id);");
316             _code.println("    mfc_read_tag_status_all();");
317             _code.println("    FastCommunication * com;");
318             _code.println("    try {  com = new FastCommunication("
319                     + countChannels + ", ea_base, procContentsAll, queueFromSPU, queueOnSPU, tailAddresses); }");
320             _code.println("    catch(std::bad_alloc &e) {");
321             _code.println("        fprintf(stderr, \"[FastCommunication] Memory allocation failure\\n\");");
322             _code.println("        exit(1);");
323             _code.println("    }");
324
325             String channelTyp = "";
326             int i = 0;
327             for (Channel c : channelList) {
328                 if (spu.contains(c.getOrigin())
329                         && spu.contains(c.getTarget())) {
330                     // Local channels have no influence on external
331                     // communication (should be Windowed Fifos...)
332                     channelTyp = "local";
333                     continue;
334                 } else if (spu.contains(c.getOrigin()))
335                     channelTyp = "out";
336                 else if (spu.contains(c.getTarget()))
337                     channelTyp = "in";
338                 else
339                     System.out.println("ERROR! Channel Mapping is wrong.");
340
341                 if (c.getType().equals("fifo")) {
342                     _code.println("    com->addFifo(" + (i) + ", &"
343                         + c.getName() + ", com->" + channelTyp + ", "
344                         + x.getChannelList().indexOf(c) + ");");
345                 }
346                 else if (c.getType().equals("wfifo")) {
347                     _code.println("    com->addWFifo(" + (i) + ", &"
348                             + c.getName() + ", com->" + channelTyp + ", "
349                             + x.getChannelList().indexOf(c) + ");");
350                 }
351                 i++;
352             }
353
354             // The scheduler (yes, this could be optimized...)
355             _code.println("");
356             _code.println("    printf(\"SPU " + index + ": start to execute\\n\"); ");
357             _code.println("");
358             _code.println("    bool allBlocked = false;");
359             _code.println("    while (!allBlocked)");
360             _code.println("    {");
361             _code.println("        allBlocked = true;");
362             for (Process p : spu) {
363                 _code.println("        if (!" + p.getName()
364                         + "->isDetached())");
365                 _code.println("        {");
366                 _code.println("            " + p.getName() + "->fire();");
367                 _code.println("            allBlocked = false;");
368                 _code.println("        }");
369
370                 // communication only if this process needs some communication
371                 for (Channel c : channelList) {
372                     // the channel may go away
373                     if (!spu.contains(c.getOrigin()) || !spu.contains(c.getTarget())) {
374                         if (c.getOrigin().equals(p) || c.getTarget().equals(p)) {
375                             _code.println("        com->update();");
376                             break;
377                         }
378                     }
379                 }
380                 _code.println();
381             }
382             _code.println("    }");
383             _code.println();
384
385             // End --> wait until all communications are finished
386             _code
387                     .println("    // Are there any open communication requests?");
388             _code.println("    while (!com->empty())");
389             _code.println("    {");
390             _code.println("        com->update();");
391             _code.println("    }");
392
393             for (Process p : spu) {
394                 _code.println("    delete " + p.getName() + ";");
395             }
396
397             _code.println("    delete com;");
398             _code.println("    ");
399             _code.println("    // release tag ID before exiting");
400             _code.println("    mfc_tag_release(tag_id);");
401             _code.println("    ");
402             _code.println("    uint32_t message = CREATEFASTMESSAGE(SPE_COMPLETE, 0, 0);");
403             _code.println("    spu_write_out_mbox(message);");
404             _code.println("    ");
405             _code.println("    messageIn = spu_read_in_mbox();");
406             _code.println("}");
407         } catch (FileNotFoundException e) {
408             e.printStackTrace();
409         }
410     }
411
412     protected String _spuDir = null;
413     protected CodePrintStream _mainPS = null;
414     protected String _dir = null;
415     protected CellMapping _mapping = null;
416 }