dol: initial dol commit
[jump.git] / dol / src / dol / visitor / cell / CellPPEVisitor.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.StringTokenizer;
9 import java.util.Vector;
10
11 import dol.datamodel.pn.Channel;
12 import dol.datamodel.pn.Port;
13 import dol.datamodel.pn.Process;
14 import dol.datamodel.pn.ProcessNetwork;
15 import dol.util.CodePrintStream;
16 import dol.visitor.PNVisitor;
17
18 public class CellPPEVisitor extends PNVisitor {
19     /**
20      * Constructor.
21      *
22      * @param dir
23      *            path of this file
24      */
25     public CellPPEVisitor(String dir, CellMapping mapping) {
26         _dir = dir;
27         _mapping = mapping;
28     }
29
30     /**
31      * Visit process network.
32      *
33      * @param x
34      *            process network that needs to be rendered
35      */
36     public void visitComponent(ProcessNetwork x) {
37         try {
38             // Create a directory for the OS Layer:
39             _ppuDir = _dir + _delimiter + "ppu";
40             File dir = new File(_ppuDir);
41             dir.mkdirs();
42
43             // Copy the header file to this directory
44             // Some library files must be copied to the main directory
45             (new File(_dir + _delimiter + "lib" + _delimiter + "ppu_os.h"))
46                     .renameTo(new File(dir.getPath() + _delimiter
47                             + "spu_os.h"));
48
49             createOSLayer(x, _mapping.getPPU());
50
51             createMakefilePPU();
52         } catch (Exception e) {
53             System.out.println("CellPPEVisitor: exception occured: "
54                     + e.getMessage());
55             e.printStackTrace();
56         }
57     }
58
59     /**
60      * Creates the OS layer for one SPU
61      *
62      * @param spu
63      *            List of all processes a SPU gets
64      * @param index
65      *            index of the SPU in the SPU list
66      */
67     protected void createOSLayer(ProcessNetwork x, Vector<Process> ppu) {
68         try {
69             // Create the filename for the new layer
70             String filename = _ppuDir + _delimiter + "ppu_os.cpp";
71
72             // PrintStream for writing to the file
73             OutputStream file = new FileOutputStream(filename);
74             CodePrintStream _code = new CodePrintStream(file);
75
76             _code = new CodePrintStream(file);
77
78             _code.printPrefixln("#include \"pt.h\"");
79             _code.printPrefixln("#include \"Fifo.h\"");
80             _code.printPrefixln("#include \"WindowedFifo.h\"");
81             _code.printPrefixln("#include \"FastCommunication.h\"");
82             _code.printPrefixln("#include \"common_ppu.h\"");
83             _code.printPrefixln("#include \"common.h\"");
84             for (Process p : ppu) {
85                 _code.printPrefixln("#include \".." + _delimiter + "ppu_"
86                         + p.getBasename() + _delimiter + p.getBasename()
87                         + "Wrapper.h\"");
88             }
89
90             _code.println();
91             _code.printPrefixln("void *ppu( void *ptr )");
92             _code.printLeftBracket();
93
94             // instantiate channels
95             Vector<Channel> channelList = new Vector<Channel>();
96             int indx = 0;
97             for (Channel c : x.getChannelList()) {
98                 if (ppu.contains(c.getOrigin())
99                         || ppu.contains(c.getTarget())) {
100                     channelList.add(c);
101
102                     if (c.getType().equals("fifo")) {
103                         // This is a IN-Channel --> Add an additional Factor to increase the speed
104                         if (ppu.contains(c.getTarget()) && !ppu.contains(c.getOrigin())) {
105                             _code.printPrefixln("Fifo " + c.getName()
106                                     + "(FIFO_SIZE[" + indx +"] * FIFO_SIZE_FACTOR);");
107                         // OUT-Channel --> Do not add any factor as we like to stall sometimes
108                         } else {
109                             _code.printPrefixln("Fifo " + c.getName()
110                                 + "(FIFO_SIZE[" + indx + "]);");
111                         }
112                     } else if (c.getType().equals("wfifo")) {
113                         _code.printPrefixln("WindowedFifo " + c.getName()
114                                 + "(FIFO_SIZE[" + indx + "]);");
115                     }
116                 }
117                 indx++;
118             }
119             _code.println();
120
121             // instantiate processes
122             for (Process p : ppu) {
123                 _code.printPrefix("int " + p.getName() + "Indices[] = { ");
124                 Vector<Integer> iteratorIndex = p.getIteratorIndices();
125                 if (iteratorIndex.size() < 4) {
126                     while (iteratorIndex.size() < 4) {
127                         iteratorIndex.add(-1);
128                     }
129                 } else if (iteratorIndex.size() > 4) {
130                     new RuntimeException("Error: Currently not more than "
131                             + "4 iterator dimensions are supported."
132                             + "Consider revising " + p.getBasename() + ".");
133                 }
134                 for (int i = 0; i < 4; i++) {
135                     if (i < 3) {
136                         _code.print(iteratorIndex.elementAt(i) + ", ");
137                     } else {
138                         _code.println(iteratorIndex.elementAt(i) + " };");
139                     }
140                 }
141                 _code.println();
142                 _code.printPrefixln(p.getBasename() + "Wrapper *" + p.getName() + ";");
143                 _code.printPrefixln("try { " 
144                         + p.getName() + " = new " + p.getBasename()
145                         + "Wrapper(\"" + p.getName() + "\", "
146                         + p.getName() + "Indices); }");
147                 _code.println("    catch(std::bad_alloc &e) {");
148                 _code.println("        fprintf(stderr, \"[" + p.getBasename() +"Wrapper] Memory allocation failure\\n\");");
149                 _code.println("        exit(1);");
150                 _code.println("    }");
151             }
152             _code.println();
153
154             // connect the network
155             for (Process p : ppu) {
156                 for (Port port : p.getPortList()) {
157                     if (port.getName().equals(port.getBasename())) {
158                         _code.printPrefixln(p.getName() + "->_port"
159                                 + port.getName() + "Fifo = &"
160                                 + port.getPeerResource().getName() + ";");
161                     } else {
162                         _code.printPrefix(p.getName() + "->_port"
163                                 + port.getBasename() + "Fifo");
164                         StringTokenizer tokenizer = new StringTokenizer(
165                                 port.getName().replaceFirst(
166                                         port.getBasename(), ""), "_");
167                         while (tokenizer.hasMoreTokens()) {
168                             _code.print("[" + tokenizer.nextToken() + "]");
169                         }
170                         _code.println(" = &"
171                                 + port.getPeerResource().getName() + ";");
172                     }
173                 }
174             }
175             _code.println();
176
177             /**************************************************************************/
178             // This is the synchronisation code
179             _code.println("    for (int i = 0; i < NUM_FIFO; i++)");
180             _code.println("        ((ProcessData *)ptr)->fifoTails[i] = 0;");
181             _code.println("    ");
182
183             int outQueues = 0;
184
185             // Check all out queues on the SPU
186             for (Channel c : x.getChannelList()) {
187
188                 // Check all SPUs
189                 for (Vector<Process> spu : _mapping.getSPUList()) {
190                     if (spu.contains(c.getOrigin()) && !spu.contains(c.getTarget())) {
191                         outQueues++;
192                     }
193                 }
194
195                 // Check the PPU
196                 if (ppu.contains(c.getOrigin()) && !ppu.contains(c.getTarget())) {
197                     outQueues++;
198                 }
199             }
200
201             // On how much queues we have to wait
202             _code.println("    uint32_t nrOutQueues = NUM_FIFO;");
203             _code.println("    uint32_t countOutQueues = 0;");
204             _code.println("    uint32_t processNr = 0;");
205             _code.println("    uint32_t message;");
206             _code.println("");
207
208             // Add all out queues of the PPE
209
210             for (Channel c : channelList) {
211                 if (ppu.contains(c.getOrigin()) && !ppu.contains(c.getTarget())) {
212                     _code.println("    ((ProcessData *)ptr)->fifoTails[" + x.getChannelList().indexOf(c) + "] = (uint64_t) " + c.getName() + ".getQueuePointer();");
213                     _code.println("    countOutQueues++;");
214                 }
215             }
216
217             // Check to get all messages back
218             _code.println("    ");
219             _code.println("    // Get the offset of the queues");
220             _code.println("    while (countOutQueues < nrOutQueues) {");
221             _code.println("        for (processNr = 0; processNr < NUM_SPES; processNr++) {");
222             _code.println("            if (!spe_out_mbox_status((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr])) continue;");
223             _code.println("            ");
224             _code.println("            spe_out_mbox_read((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr], &message, 1);");
225             _code.println("            ");
226             _code.println("            uint32_t queue = ((message >> 24) & 0xFF);");
227             _code.println("            uint32_t offset = ((message >> 0) & 0xFFFFFF);");
228             _code.println("            ");
229             _code.println("            if (((ProcessData *)ptr)->queueOnSPU[queue] < 0)");
230             _code.println("                ((ProcessData *)ptr)->fifoTails[queue] = offset;  // Only the offset if the PPE needs to access the data");
231             _code.println("            else");
232             _code.println("                ((ProcessData *)ptr)->fifoTails[queue] = offset + ((ProcessData *)ptr)->ea_ls_base[processNr];");
233             _code.println("            countOutQueues++;");
234             _code.println("        }");
235             _code.println("    }");
236             _code.println("    ");
237
238             // Send a message that each SPE knows that he can access the list
239             _code.println("    // Send the Okay to all SPEs for that they can start reading the tail pointers of the fifos");
240             _code.println("    message = MSG_OK;");
241             _code.println("    for (processNr = 0; processNr < NUM_SPES; processNr++) {");
242             _code.println("        spe_in_mbox_write((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr], (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING);");
243             _code.println("    }");
244
245             /**************************************************************************/
246
247             // initialize processes
248             for (Process p : ppu) {
249                 _code.printPrefixln(p.getName() + "->init();");
250             }
251             _code.println();
252
253             // Count the effected channels
254             int countChannels = 0;
255             for (Channel c : channelList) {
256                 if (ppu.contains(c.getOrigin())
257                         && ppu.contains(c.getTarget())) {
258                     continue;
259                 } else if (ppu.contains(c.getOrigin()))
260                     countChannels++;
261                 else if (ppu.contains(c.getTarget()))
262                     countChannels++;
263                 else
264                     System.out.println("ERROR! Channel Mapping is wrong.");
265             }
266
267
268             _code.println("    FastCommunication * com;");
269             _code
270                     .println("    try { com = new FastCommunication("
271                             + countChannels
272                             + ", ((ProcessData *)ptr)->procContentsAll, ((ProcessData *)ptr)->ea_ls_base, ((ProcessData *)ptr)->queueFromSPU, ((ProcessData *)ptr)->queueOnSPU, ((ProcessData *)ptr)->fifoTails); }");
273             _code.println("    catch(std::bad_alloc &e) {");
274             _code.println("        fprintf(stderr, \"[FastCommunication] Memory allocation failure\\n\");");
275             _code.println("        exit(1);");
276             _code.println("    }");
277
278             String channelTyp = "";
279             int i = 0;
280             for (Channel c : channelList) {
281                 if (ppu.contains(c.getOrigin())
282                         && ppu.contains(c.getTarget())) {
283                     // Local channels have no influence on external
284                     // communication (should be Windowed Fifos...)
285                     channelTyp = "local";
286                     continue;
287                 } else if (ppu.contains(c.getOrigin())) {
288                     channelTyp = "out";
289                 } else if (ppu.contains(c.getTarget())) {
290                     channelTyp = "in";
291                 } else {
292                     System.out.println("ERROR! Channel Mapping is wrong.");
293                 }
294
295                 if (c.getType().equals("fifo")) {
296                     _code.println("    com->addFifo(" + (i) + ", &"
297                             + c.getName() + ", com->" + channelTyp + ", "
298                             + x.getChannelList().indexOf(c) + ");");
299                 } else if (c.getType().equals("wfifo")) {
300                     _code.println("    com->addWFifo(" + (i) + ", &"
301                             + c.getName() + ", com->" + channelTyp + ", "
302                             + x.getChannelList().indexOf(c) + ");");
303                 }
304                 i++;
305             }
306
307             _code.printPrefixln("bool allBlocked = false;");
308             _code.printPrefixln("while(!allBlocked)");
309             _code.printLeftBracket();
310             _code.printPrefixln("allBlocked = true;");
311             for (Process p : ppu) {
312                 _code.printPrefixln("if (!" + p.getName()
313                         + "->isDetached()) {");
314                 _code.printPrefixln("    " + p.getName() + "->fire();");
315                 _code.printPrefixln("    allBlocked = false;");
316                 _code.printPrefixln("}");
317                 _code.printPrefixln("");
318
319
320
321                 // Communication only if this process needs some communication
322                 for (Channel c : channelList) {
323                     // The channel may goes away
324                     if (!ppu.contains(c.getOrigin()) || !ppu.contains(c.getTarget())) {
325                         if (c.getOrigin().equals(p) || c.getTarget().equals(p)) {
326                             _code.printPrefixln("com->update();");
327                             _code.printPrefixln("");
328                             break;
329                         }
330                     }
331                 }
332
333             }
334             _code.printRightBracket();
335             _code.println();
336
337             _code.println();
338             _code.println("    // Are there any open communication requests?");
339             _code.println("    while (!com->empty())");
340             _code.println("    {");
341             _code.println("        com->update();");
342             _code.println("    }");
343             _code.println("    ");
344             _code.println("    // Send all SPUs the complete message");
345             _code.println("    message = MSG_OK;");
346             _code.println("    for (processNr = 0; processNr < NUM_SPES; processNr++) {");
347             _code.println("        spe_in_mbox_write((spe_context*)((ProcessData *)ptr)->procContentsAll[processNr], (uint32_t*)&message, 1, SPE_MBOX_ANY_NONBLOCKING);");
348             _code.println("    }");
349             _code.println("");
350             for (Process p : ppu) {
351                 _code.printPrefixln("delete " + p.getName() + ";");
352             }
353             _code.printPrefixln("delete com;");
354             _code.println();
355             _code.printPrefixln("pthread_exit(NULL);");
356             _code.printRightBracket();
357         } catch (Exception e) {
358             System.out.println("ProtothreadModuleVisitor: "
359                     + "exception occured: " + e.getMessage());
360             e.printStackTrace();
361         }
362     }
363
364     /**
365      *
366      */
367     protected void createMakefilePPU() {
368         try {
369             // Directory of the process
370             String ppuDir = _dir + _delimiter + "ppu";
371
372             // Create the filename for the new wrapper
373             String filename = ppuDir + _delimiter + "Makefile";
374
375             OutputStream file = new FileOutputStream(filename);
376
377             PrintStream _makefilePS = new CodePrintStream(file);
378
379             _makefilePS.println("# Makefile for PPU OS");
380             _makefilePS.println("");
381             _makefilePS.println("src := $(wildcard ../lib/ppu/*.cpp)");
382             _makefilePS.println("obj = $(src:.cpp=.o)");
383             _makefilePS.println("");
384
385             // The Makefile must include all o-Files of the processes needed
386             String dependency = "";
387
388             // Go through all possible processes
389             for (Process p : _mapping.getAllPPUBaseProcess()) {
390                 dependency += " .." + _delimiter + "ppu_"
391                         + p.getBasename() + _delimiter + p.getBasename()
392                         + "Wrapper.o";
393             }
394
395             _makefilePS.println("all: ${obj}");
396             _makefilePS
397                     .println("\tppu-g++ -c -I .. -I ../lib -I ../lib/pt -I ../lib/ppu -o ppu_os.o ppu_os.cpp -ftree-vectorize -lm -mtune=cell -O3 -fmodulo-sched -funroll-loops -ffast-math");
398
399             _makefilePS.println();
400             _makefilePS.println("clean: ");
401             _makefilePS.println("\trm ppu_os");
402
403             _makefilePS.println();
404             _makefilePS.println("%.o : ");
405             _makefilePS
406                     .println("\tppu-g++ -c -o $(*D)/$(*F).o $(*D)/$(*F).cpp -I .. -I ../lib -I ../lib/pt -I ../lib/ppu  -ftree-vectorize -lm -mtune=cell -O3 -fmodulo-sched -funroll-loops -ffast-math");
407             _makefilePS.println();
408
409         } catch (FileNotFoundException e) {
410             System.out.println("CbeProcessVisitor - Makefile: exception "
411                     + "occured: " + e.getMessage());
412             e.printStackTrace();
413         }
414     }
415
416     protected String _ppuDir = null;
417     protected CodePrintStream _mainPS = null;
418     protected String _dir = null;
419     protected CellMapping _mapping = null;
420
421 }