Added text2log tool for converting log#.txt files in ASCII format to bgTrace binary...
[charm.git] / examples / bigsim / tools / text2log / text2log.C
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <math.h>
4 #include "bigsim_logs.h"
5
6 // these should be plenty
7 #define MAX_MESSAGES 1000000
8 #define LINE_SIZE 1024
9
10 // pair of ints, used to keep track of forward dependencies
11 struct IntPair {
12   int one, two;
13   IntPair() {}
14   IntPair(int unused) {}  // for remove function in CkVec
15   inline void pup(PUP::er &p) {
16     p|one; p|two;
17   }
18 };
19
20
21 // all the info needed for a message send
22 struct MsgSend {
23   int msgID, dstNode, tid, size, group;
24   double sent, recvtime;
25   MsgSend() {}
26   MsgSend(int unused) {}  // for remove function in CkVec
27   inline void pup(PUP::er &p) {
28     p|msgID; p|dstNode; p|tid; p|size;
29     p|group; p|sent; p|recvtime;
30   }
31 };
32
33
34 int main(int argc, char* argv[]) {
35
36   int numPEs, numNodes, numXNodes, numYNodes, numZNodes, numWth, numTraces;
37
38   /************* Read in command-line parameters *************/
39   if ((argc > 1) && (strcmp(argv[1], "-help") == 0)) {
40     printf("\n");
41     printf("Usage: ./text2log <# log files> <X dim nodes> <Y dim nodes> <Z dim nodes> <# cores/node> [<# emulating procs>]\n");
42     printf("\n");
43     printf("<# log files>  - Integer that specifies the number of log#.txt files to read.\n");
44     printf("                 Each log file must contain exactly one time line.\n");
45     printf("<X dim nodes>  - Integer that specifies the number of simulated nodes in the X dimension.\n");
46     printf("<Y dim nodes>  - Integer that specifies the number of simulated nodes in the Y dimension.\n");
47     printf("<Z dim nodes>  - Integer that specifies the number of simulated nodes in the Z dimension.\n");
48     printf("<# cores/node> - Integer that specifies the number of cores (worker threads) on each simulated node.\n");
49     printf("                 There must be a log#.txt file for every core, and <# nodes> * <# cores/node> must equal the number of log#.txt files.\n");
50     printf("<# emulating procs> - Optional integer that specifies the number of bgTrace files to create.\n");
51     printf("                      If not specified, this number defaults to the number of specified log.txt files.\n");
52     printf("\n");
53     printf("All logs must be of the following format:\n");
54     printf("\n");
55     printf("[<eventNum>] name:<eventName> (srcpe:<srcpe> msgID:<msgID>) ep:<ep> charm_ep:<charm_ep>\n");
56     printf("startTime:<startTime> endTime:<endTime>\n");
57     printf("-msgID:<msgID> sent:<sendTime> recvtime:<recvTime> dstNode:<dstNode> tid:<tid> size:<size> group:<group>\n");
58     printf("forward: <optional list of ints enclosed in []s>\n");
59     printf("\n");
60     printf("Where the message send lines ('-msgID: ...') are optional.  See the examples.tgz tarball for examples.\n");
61     printf("\n");
62     printf("For messages:\n");
63     printf("\n");
64     printf("destNode destTID Behavior\n");
65     printf("======== ======= ==============================================\n");
66     printf("   -1      -1    Broadcast to ALL worker threads of ALL nodes\n");
67     printf("   -2      -1    Multicast to all nodes given by the pe list in the task msg\n");
68     printf("   -1       K    Invalid\n");
69     printf("    N      -1    Send to ALL worker threads of node N\n");
70     printf("    N       K    Send to worker thread K of node N\n");
71     printf(" -100-N    -1    Broadcast to all worker threads of all nodes except for N (no worker threads of N receive)\n");
72     printf(" -100-N     K    Broadcast to all worker threads of all nodes except worker K of node N\n");
73     printf("\n");
74
75     exit(0);
76   }
77
78   if ((argc < 6) || (argc > 7)) {
79     printf("ERROR: there should be 6 or 7 arguments.  Usage: ./text2log <# log files> <X dim nodes> <Y dim nodes> <Z dim nodes> <# cores/node> [<# emulating procs>]\n");
80     printf("Running with -help will provide detailed info on the parameters.\n");
81     exit(-1);
82   }
83
84   numPEs = atoi(argv[1]);
85   numXNodes = atoi(argv[2]);
86   numYNodes = atoi(argv[3]);
87   numZNodes = atoi(argv[4]);
88   numNodes = numXNodes * numYNodes * numZNodes;
89   numWth = atoi(argv[5]);
90   if (argc == 7) {
91     numTraces = atoi(argv[6]);
92   } else {
93     numTraces = numPEs;
94   }
95
96   // command-line parameter sanity checks
97   if (numPEs <= 0) {
98     printf("ERROR: the number of specified log files (%d) must be > 0\n", numPEs);
99     exit(-1);
100   }
101   if (numTraces <= 0) {
102     printf("ERROR: the number of emulating procs (%d) must be > 0\n", numTraces);
103     exit(-1);
104   }
105   if ((numNodes * numWth) != numPEs) {
106     printf("ERROR: the number of nodes * the number of cores per node (%d) must equal the number of specifed log files (%d)\n", 
107            numNodes * numWth, numPEs);
108     exit(-1);
109   }
110   if (numTraces > numNodes) {
111     printf("ERROR: the number of emulating procs (%d) must be <= the number of nodes (%d)\n", numTraces, numNodes);
112     exit(-1);
113   }
114
115   // turn on log generation
116   BgGenerateLogs();
117
118   /************* Read in the log#.txt files and convert them to bgTrace files *************/
119   BgTimeLineRec tlinerecs[numPEs];  // time lines
120   char fileName[20], line[LINE_SIZE];
121   FILE *filePtr;
122   int lineNum, eventCount;
123   BgTimeLog *newLog;
124   BgMsgEntry *newMsg;
125   double lastEndTime;
126   int msgIDsFree[MAX_MESSAGES];
127
128   // event fields
129   int eventNum, srcpe, msgID, ep, charm_ep;
130   char eventName[20];
131   double startTime, endTime;
132
133   CkVec<IntPair> dependencies;
134   CkVec<MsgSend> eventMessages;
135
136   /************* Loop through all log files *************/
137   for (int logNum = 0; logNum < numPEs; logNum++) {
138
139     sprintf(fileName, "log%d.txt", logNum);
140     filePtr = fopen(fileName, "r");
141     if (!filePtr) {
142       printf("Cannot open file %s... exiting.\n", fileName);
143       exit(-1);
144     }
145     printf("Reading file %s...\n", fileName);
146
147     // make msgIDsFree ready to use
148     for (int i = 0; i < MAX_MESSAGES; i++) {
149       msgIDsFree[i] = 1;
150     }
151
152     // clear the dependencies
153     dependencies.clear();
154
155     // read events from the file, one line at a time
156     lineNum = 0;
157     eventNum = 0;
158     eventCount = 0;
159     lastEndTime = 0.0;
160     while (fgets(line, LINE_SIZE, filePtr)) {
161
162       // ignore empty lines
163       if (strcmp(line, "\n") == 0) {
164         lineNum++;
165         continue;
166       }
167
168       // look for the first line of an event, then read the entire event
169       if (line[0] == '[') {
170
171         // first line of event
172         if (sscanf(line, "[%d] name:%s (srcpe:%d msgID:%d) ep:%d charm_ep:%d\n", 
173                    &eventNum, &eventName, &srcpe, &msgID, &ep, &charm_ep) != 6) {
174           printf("ERROR: line %d of file %s not read in properly\n", lineNum, fileName);
175           printf("line=%s\n", line);
176           printf("Looking for the first line of an event with the following format:\n");
177           printf("[<eventNum>] name:<eventName> (srcpe:<srcpe> msgID:<msgID>) ep:<ep> charm_ep:<charm_ep>\n");
178           printf("Where eventNum, srcpe, msgID, ep, and charm_ep are ints, and where eventName is a string no longer than 20 characters\n");
179           exit(-1);
180         }
181         if (eventNum != eventCount) {
182           printf("ERROR: event numbered incorrectly.  Event %d in file %s should be event %d.\n", eventNum, fileName, eventCount);
183           exit(-1);
184         }
185         lineNum++;
186
187         // second line of event
188         if (!fgets(line, LINE_SIZE, filePtr)) {
189           printf("ERROR: line %d of file %s was not read in properly\n", lineNum, fileName);
190           printf("line=%s\n", line);
191           printf("If this line doesn't exist in the file, then please add a 'starTime...' line or delete this event\n");
192           exit(-1);
193         }
194         if (sscanf(line, "startTime:%lf endTime:%lf\n", &startTime, &endTime) != 2) {
195           printf("ERROR: line %d of file %s not read in properly\n", lineNum, fileName);
196           printf("line=%s\n", line);
197           printf("Looking for the second line of an event with the following format:\n");
198           printf("startTime:<startTime> endTime:<endTime>\n");
199           printf("Where startTime and endTime are doubles in seconds\n");
200           exit(-1);
201         }
202         lineNum++;
203
204         // read in messages; skip if they don't exist
205         eventMessages.removeAll();
206         while (fgets(line, LINE_SIZE, filePtr)) {
207           if (line[0] == '-') {
208             MsgSend ms;
209             if (sscanf(line, "-msgID:%d sent:%lf recvtime:%lf dstNode:%d tid:%d size:%d group:%d\n", 
210                        &ms.msgID, &ms.sent, &ms.recvtime, &ms.dstNode, &ms.tid, &ms.size, &ms.group) != 7) {
211               printf("ERROR: line %d of file %s not read in properly\n", lineNum, fileName);
212               printf("line=%s\n", line);
213               printf("Looking for a message send line starting with the following format:\n");
214               printf("-msgID:<msgID> sent:<sendTime> recvtime:<recvTime> dstNode:<dstNode> tid:<tid> size:<size> group:<group>\n");
215               printf("Where msgID, dstNode, tid, size, and group are ints, and sendTime and recvTime are doubles in seconds\n");
216               exit(-1);
217             }
218             eventMessages.insertAtEnd(ms);
219             lineNum++;
220           } else {
221             // no messages left to read, so break out of loop
222             break;
223           }
224         }
225
226         // last line of the event has already been read in
227         if (strncmp(line, "forward:", strlen("forward:")) != 0) {
228           printf("ERROR: line %d of file %s not read in properly\n", lineNum, fileName);
229           printf("line=%s\n", line);
230           printf("Looking for the last line of an event with the following format:\n");
231           printf("forward: <optional list of ints enclosed in []s>\n");
232           printf("For example: 'forward: [4] [13] [27]'\n");
233           exit(-1);
234         }
235         // extract forward dependencies
236         char tempLine[LINE_SIZE];
237         strcpy(tempLine, line + strlen("forward:"));
238         char *token = strtok(tempLine, " []\n");
239         while (token != NULL) {
240           IntPair ip;
241           ip.one = eventNum;
242           ip.two = atoi(token);
243           // ensure forward dependents aren't negative
244           if (ip.two < 0) {
245             printf("ERROR: line %d of file %s contains a negative forward dependent (%d)\n", lineNum, fileName, ip.two);
246             exit(-1);
247           }
248           // ensure forward dependents don't point to their own event
249           if (ip.two == eventNum) {
250             printf("ERROR: event %d at line %d of file %s contains a forward dependent (%d) that points to its own event\n", 
251                    eventNum, lineNum, fileName, ip.two);
252             exit(-1);
253           }
254           dependencies.insertAtEnd(ip);
255           token = strtok(NULL, " []\n");
256         }
257         lineNum++;
258
259       } else {
260         printf("ERROR: Bad log format at line %d of file %s:\n", lineNum, fileName);
261         printf("line=%s\n", line);
262         printf("An event needs to begin with a line with the following format:\n");
263         printf("[<eventNum>] name:<eventName> (srcpe:<srcpe> msgID:<msgID>) ep:<ep> charm_ep:<charm_ep>\n");
264         printf("Where eventNum, srcpe, msgID, ep, and charm_ep are ints, and where eventName is a string no longer than 20 characters\n");
265         exit(-1);
266       }
267
268       /************* Sanity checks *************/
269       // check srcpe and msgID
270       if ((srcpe < -1) || (srcpe > numPEs)) {
271         printf("ERROR: [file %s, event %d] srcpe (%d) must be between -1 and %d, inclusive\n", fileName, eventNum, srcpe, numPEs - 1);
272         exit(-1);
273       }
274       if (msgID < -1) {
275         printf("ERROR: [file %s, event %d] msgID (%d) must be -1 or greater\n", fileName, eventNum, msgID);
276         exit(-1);
277       }
278       if (((srcpe == -1) && (msgID != -1)) || ((msgID == -1) && (srcpe != -1))) {
279         printf("ERROR: [file %s, event %d] if either srcpe (%d) or msgID (%d) is -1, the other must also be -1\n", fileName, eventNum, srcpe, msgID);
280         exit(-1);
281       }
282
283       // check name
284       if ((srcpe >= 0) && (strcmp(eventName, "msgep") != 0)) {
285         printf("WARNING: [file %s, event %d] because the event looks like a message receive, its name should be 'msgep' instead of '%s'\n", 
286                fileName, eventNum, eventName);
287       }
288
289       // check ep and charm_ep
290       if (ep < -1) {
291         printf("ERROR: [file %s, event %d] ep (%d) must be -1 or greater\n", fileName, eventNum, ep);
292           exit(-1);
293       }
294       if (charm_ep < -1) {
295         printf("ERROR: [file %s, event %d] charm_ep (%d) must be -1 or greater\n", fileName, eventNum, charm_ep);
296           exit(-1);
297       }
298
299       // check startTime and endTime
300       if (startTime < lastEndTime) {
301         printf("ERROR: [file %s, event %d] startTime (%lf) must be >= the end time of the last event (%lf)\n", fileName, eventNum, startTime, lastEndTime);
302           exit(-1);
303       }
304       if (endTime < startTime) {
305         printf("ERROR: [file %s, event %d] endTime (%lf) must be >= the startTime of this event (%lf)\n", fileName, eventNum, endTime, startTime);
306           exit(-1);
307       }
308
309       // check each message
310       for (int i = 0; i < eventMessages.length(); i++) {
311         // check the msgID and group
312         if (eventMessages[i].msgID < 0) {
313           printf("ERROR: [file %s, event %d] msgID of message send (%d) must be >= 0\n", fileName, eventNum, eventMessages[i].msgID);
314           exit(-1);
315         }
316         if (eventMessages[i].msgID >= MAX_MESSAGES) {
317           printf("ERROR: [file %s, event %d] msgID of message send (%d) is greater than the max message ID number (%d)\n", 
318                  fileName, eventNum, eventMessages[i].msgID, MAX_MESSAGES);
319           exit(-1);
320         }
321         if (eventMessages[i].group < -1) {
322           printf("ERROR: [file %s, event %d] group (%d) of msgID %d must be >= -1 (and only == -1 for multicasts)\n", 
323                  fileName, eventNum, eventMessages[i].group, eventMessages[i].msgID);
324           exit(-1);
325         }
326         // check that the msgID hasn't been used yet; account for
327         // multicasts, in which it's used more than once
328         if (msgIDsFree[eventMessages[i].msgID] > 0) {  // not used yet
329           if (eventMessages[i].group < 1) {  // group == -1 should only happen in successive multicast messages
330             printf("ERROR: [file %s, event %d] group (%d) of msgID %d must be >= 1 (and only > 1 for multicasts) because this doesn't look like part of a multicast\n", 
331                    fileName, eventNum, eventMessages[i].group, eventMessages[i].msgID);
332             exit(-1);
333           } else if (eventMessages[i].group == 1) {  // normal unicast or broadcast
334             msgIDsFree[eventMessages[i].msgID] = 0;
335           } else {  // multicast
336             msgIDsFree[eventMessages[i].msgID] = 1 - eventMessages[i].group;
337           }
338         } else if (msgIDsFree[eventMessages[i].msgID] == 0) {  // used too many times
339           printf("ERROR: [file %s, event %d] msgID (%d) has already been used (or used too many times for a multicast)\n", 
340                  fileName, eventNum, eventMessages[i].msgID);
341           exit(-1);
342         } else {  // part of a multicast
343           if (eventMessages[i].group != -1) {
344             printf("ERROR: [file %s, event %d] group (%d) of msgID %d must be -1 because its supposedly part of a multicast\n", 
345                    fileName, eventNum, eventMessages[i].group, eventMessages[i].msgID);
346             exit(-1);
347           } else {
348             msgIDsFree[eventMessages[i].msgID]++;
349           }
350         }
351         // check message send and receive times
352         if ((eventMessages[i].sent < startTime) || (eventMessages[i].sent > endTime)) {
353           printf("ERROR: [file %s, event %d] send time (%lf) of msgID %d must be between the startTime (%lf) and endTime (%lf) of the event, inclusive\n", 
354                  fileName, eventNum, eventMessages[i].sent, eventMessages[i].msgID, startTime, endTime);
355           exit(-1);
356         }
357         if (eventMessages[i].recvtime < eventMessages[i].sent) {
358           printf("ERROR: [file %s, event %d] recvtime (%lf) of msgID %d must be >= the message send time (%lf)\n", 
359                  fileName, eventNum, eventMessages[i].recvtime, eventMessages[i].msgID, eventMessages[i].sent);
360           exit(-1);
361         }
362         // check the destination node
363         if ((eventMessages[i].dstNode <= -100 - numNodes) || 
364             ((eventMessages[i].dstNode < -1) && (eventMessages[i].dstNode > -100)) || 
365             (eventMessages[i].dstNode >= numNodes)) {
366           printf("ERROR: [file %s, event %d] dstNode (%d) of msgID %d must be:\n", 
367                  fileName, eventNum, eventMessages[i].dstNode, eventMessages[i].msgID);
368           printf("          between -100 and %d, inclusive, for a broadcast-all-except\n", -100 - numNodes + 1);
369           printf("          -1 for a boadcast-all\n");
370           printf("          between 0 and %d, inclusive, for a normal unicast or multicast send\n", numNodes - 1);
371           exit(-1);
372         }
373         // check the destination thread ID
374         if ((eventMessages[i].tid < -1) || (eventMessages[i].tid >= numWth)) {
375           printf("ERROR: [file %s, event %d] tid (%d) of msgID %d must be:\n", 
376                  fileName, eventNum, eventMessages[i].tid, eventMessages[i].msgID);
377           printf("          -1 for a broadcast to all cores in the node\n");
378           printf("          between 0 and %d, inclusive, for a normal unicast or multicast send to one core of the node\n", numWth - 1);
379           exit(-1);
380         }
381         // check the message size
382         if (eventMessages[i].size < 1) {
383           printf("ERROR: [file %s, event %d] the size (%d) of msgID %d must be at least 1 byte\n", 
384                  fileName, eventNum, eventMessages[i].size, eventMessages[i].msgID);
385           exit(-1);
386         }
387       }
388       // ensure the first event in time line 0 isn't a stand-alone event
389       if ((logNum == 0) && (eventNum == 0) && (strcmp(eventName, "addMsg") == 0)) {
390         printf("ERROR: the first simulation event (event 0 of file %s) should not be a stand-alone event (i.e., named 'addMsg')\n", fileName);
391         exit(-1);
392       }
393       // ensure some of the stand-alone event criteria
394       if ((strcmp(eventName, "addMsg") == 0) && ((srcpe != -1) || (msgID != -1))) {
395         printf("ERROR: [file %s, event %d] stand-alone event (with event name 'addMsg') must have both srcpe (%d) and msgID (%d) set to -1\n", 
396                fileName, eventNum, srcpe, msgID);
397         exit(-1);
398       }
399
400       /************* Create the BgTimeLog and insert into time line *************/
401       newLog = new BgTimeLog(BgMsgID(srcpe, msgID));
402       newLog->setName(eventName);
403       newLog->setEP(ep);
404       newLog->setCharmEP((short)charm_ep);
405       newLog->setTime(startTime, endTime);
406       // set receive time for first event of each time line to 0
407       if (eventNum == 0) {
408         newLog->recvTime = 0.0;
409       }
410       // set recvTime of stand-alone events to startTime
411       if (strcmp(eventName, "addMsg") == 0) {
412         newLog->recvTime = newLog->startTime;
413       }
414
415       for (int i = 0; i < eventMessages.length(); i++) {
416         newMsg = new BgMsgEntry(eventMessages[i].msgID, eventMessages[i].size, eventMessages[i].sent, 
417                                 eventMessages[i].recvtime, eventMessages[i].dstNode, eventMessages[i].tid);
418         newMsg->group = eventMessages[i].group;
419         newLog->addMsg(newMsg);
420       }
421
422       tlinerecs[logNum].logEntryInsert(newLog);
423
424       lastEndTime = endTime;
425       eventCount++;
426     }
427
428     /************* Connect all dependencies in this time line *************/
429     for (int i = 0; i < dependencies.length(); i++) {
430       if (dependencies[i].two >= eventCount) {
431         printf("ERROR: [file %s, event %d] event has a forward dependent (%d) that is out of range (must be between 0 and %d, inclusive)\n", 
432                fileName, dependencies[i].one, dependencies[i].two, eventCount - 1);
433         exit(-1);
434       }
435       tlinerecs[logNum][dependencies[i].two]->addBackwardDep(tlinerecs[logNum][dependencies[i].one]);
436     }
437
438   }
439
440   /************* Ensure all messages are received *************/
441   for (int pe = 0; pe < numPEs; pe++) {
442     for (int event = 0; event < tlinerecs[pe].length(); event++) {
443       for (int msg = 0; msg < tlinerecs[pe][event]->msgs.length(); msg++) {
444         int destNode = tlinerecs[pe][event]->msgs[msg]->dstNode;
445         int found = 0;
446
447         if (destNode <= -100) {  // broadcast except
448           int nodeException = -100 - destNode;
449           int peException = -1;
450           if (tlinerecs[pe][event]->msgs[msg]->tID >= 0) {
451             peException = (nodeException * numWth) + tlinerecs[pe][event]->msgs[msg]->tID;
452           }
453           for (int destPE = 0; destPE < numPEs; destPE++) {
454             found = 0;
455             for (int destEvent = 0; destEvent < tlinerecs[destPE].length(); destEvent++) {
456               if ((tlinerecs[destPE][destEvent]->msgId.pe() == pe) && 
457                   (tlinerecs[destPE][destEvent]->msgId.msgID() == tlinerecs[pe][event]->msgs[msg]->msgID)) {
458                 found++;
459                 // update event receive time based on message receive time
460                 tlinerecs[destPE][destEvent]->recvTime = tlinerecs[pe][event]->msgs[msg]->recvTime;
461                 // ensure the event startTime is not before the message receive time
462                 if (tlinerecs[destPE][destEvent]->startTime < tlinerecs[destPE][destEvent]->recvTime) {
463                   printf("ERROR: event %d in time line %d has a startTime (%lf) that is before its recvTime (%lf)\n", 
464                          destEvent, destPE, tlinerecs[destPE][destEvent]->startTime, tlinerecs[destPE][destEvent]->recvTime);
465                   exit(-1);
466                 }
467               }
468             }
469             if ((destPE == peException) || ((peException == -1) && ((destPE / numWth) == nodeException))) {
470               // this is an exempt destPE, so it shouldn't have been found here
471               if (found > 0) {
472                 printf("ERROR: broadcast-except message with msgID %d sent from event %d in time line %d is received by PE %d (it should not be)\n", 
473                        msg, event, pe, destPE);
474                 exit(-1);
475               }
476             } else {
477               // it should only be found once
478               if (found > 1) {
479                 printf("ERROR: broadcast-except message with msgID %d sent from event %d in time line %d is received %d times by PE %d (should be 1 time)\n", 
480                        msg, event, pe, found, destPE);
481                 exit(-1);
482               } else if (found < 1) {
483                 printf("ERROR: broadcast-except message with msgID %d sent from event %d in time line %d is never received by PE %d\n", 
484                        msg, event, pe, destPE);
485                 exit(-1);
486               }
487             }
488           }
489         } else if (destNode == -1) {  // broadcast all
490           for (int destPE = 0; destPE < numPEs; destPE++) {
491             found = 0;
492             for (int destEvent = 0; destEvent < tlinerecs[destPE].length(); destEvent++) {
493               if ((tlinerecs[destPE][destEvent]->msgId.pe() == pe) && 
494                   (tlinerecs[destPE][destEvent]->msgId.msgID() == tlinerecs[pe][event]->msgs[msg]->msgID)) {
495                 found++;
496                 // update event receive time based on message receive time
497                 tlinerecs[destPE][destEvent]->recvTime = tlinerecs[pe][event]->msgs[msg]->recvTime;
498                 // ensure the event startTime is not before the message receive time
499                 if (tlinerecs[destPE][destEvent]->startTime < tlinerecs[destPE][destEvent]->recvTime) {
500                   printf("ERROR: event %d in time line %d has a startTime (%lf) that is before its recvTime (%lf)\n", 
501                          destEvent, destPE, tlinerecs[destPE][destEvent]->startTime, tlinerecs[destPE][destEvent]->recvTime);
502                   exit(-1);
503                 }
504               }
505             }
506             // it should only be found once
507             if (found > 1) {
508               printf("ERROR: broadcast-all message with msgID %d sent from event %d in time line %d is received %d times by PE %d (should be 1 time)\n", 
509                      msg, event, pe, found, destPE);
510               exit(-1);
511             } else if (found < 1) {
512               printf("ERROR: broadcast-all message with msgID %d sent from event %d in time line %d is never received by PE %d\n", 
513                      msg, event, pe, destPE);
514               exit(-1);
515             }
516           }
517         } else {  // unicast
518           int destPE = (tlinerecs[pe][event]->msgs[msg]->dstNode * numWth) + tlinerecs[pe][event]->msgs[msg]->tID;
519           for (int destEvent = 0; destEvent < tlinerecs[destPE].length(); destEvent++) {
520             if ((tlinerecs[destPE][destEvent]->msgId.pe() == pe) && 
521                 (tlinerecs[destPE][destEvent]->msgId.msgID() == tlinerecs[pe][event]->msgs[msg]->msgID)) {
522               found++;
523               // update event receive time based on message receive time
524               tlinerecs[destPE][destEvent]->recvTime = tlinerecs[pe][event]->msgs[msg]->recvTime;
525               // ensure the event startTime is not before the message receive time
526               if (tlinerecs[destPE][destEvent]->startTime < tlinerecs[destPE][destEvent]->recvTime) {
527                 printf("ERROR: event %d in time line %d has a startTime (%lf) that is before its recvTime (%lf)\n", 
528                        destEvent, destPE, tlinerecs[destPE][destEvent]->startTime, tlinerecs[destPE][destEvent]->recvTime);
529                 exit(-1);
530               }
531             }
532           }
533           // it should only be found once
534           if (found > 1) {
535             printf("ERROR: unicast message with msgID %d sent from event %d in time line %d is received %d times by PE %d (should be 1 time)\n", 
536                    msg, event, pe, found, destPE);
537             exit(-1);
538           } else if (found < 1) {
539             printf("ERROR: unicast message with msgID %d sent from event %d in time line %d is never received by PE %d\n", 
540                    msg, event, pe, destPE);
541             exit(-1);
542           }
543         }
544       }
545     }
546   }
547
548   /************* Ensure all message receives have a sender and no backward dependents *************/
549   for (int pe = 0; pe < numPEs; pe++) {
550     for (int event = 0; event < tlinerecs[pe].length(); event++) {
551       if (tlinerecs[pe][event]->msgId.pe() >= 0) {
552         // ensure no backward dependents
553         if (tlinerecs[pe][event]->backwardDeps.length() > 0) {
554           printf("ERROR: event %d in time line %d has %d backward dependent(s); it should have 0 because it looks like a message receive event\n", 
555                  event, pe, tlinerecs[pe][event]->backwardDeps.length());
556           exit(-1);
557         }
558         // ensure it has a sender
559         srcpe = tlinerecs[pe][event]->msgId.pe();
560         msgID = tlinerecs[pe][event]->msgId.msgID();
561         bool found = false;
562         for (int srcEvent = 0; srcEvent < tlinerecs[srcpe].length(); srcEvent++) {
563           for (int msg = 0; msg < tlinerecs[srcpe][srcEvent]->msgs.length(); msg++) {
564             if (tlinerecs[srcpe][srcEvent]->msgs[msg]->msgID == msgID) {
565               found = true;
566               break;
567             }
568           }
569           if (found) break;
570         }
571         if (!found) {
572           printf("ERROR: event %d in time line %d does not have a corresponding message sent from time line %d\n", event, pe, srcpe);
573           exit(-1);
574         }
575       }
576     }
577   }
578
579   /************* Write time lines to bgTrace files *************/
580   // write trace summary file
581   BgWriteTraceSummary(numTraces, numXNodes, numYNodes, numZNodes, numWth, 1, NULL, NULL);
582
583   // Write trace files in round-robin fashion by node.
584   // NOTE: The worker threads (i.e., cores) on each node must be kept
585   // together.  For example:
586   //
587   //    8 target PEs, 2 emulating procs (2 trace files), numWth = 1
588   //       tlinerecs = [0 1 2 3 4 5 6 7]
589   //       bgTrace0 (tlinetemp[0]) = [0 2 4 6]
590   //       bgTrace1 (tlinetemp[1]) = [1 3 5 7]
591   //
592   //    Same as above but with numWth = 2 -> the time lines must be
593   //    grouped in 2s (01, 23, 45, 67)
594   //       tlinerecs = [0 1 2 3 4 5 6 7]
595   //       bgTrace0 (tlinetemp[0]) = [01 45] = [0 1 4 5]
596   //       bgTrace1 (tlinetemp[1]) = [23 67] = [2 3 6 7]
597   for (int trace = 0; trace < numTraces; trace++) {
598     int numProcs;
599     if (trace < (numPEs % numTraces)) {
600       numProcs = (numPEs / numTraces) + 1;
601     } else {
602       numProcs = numPEs / numTraces;
603     }
604     BgTimeLineRec **tlinetemp = new BgTimeLineRec*[numProcs];
605     for (int node = 0; node < (numProcs / numWth); node++) {
606       for (int proc = 0; proc < numWth; proc++) {
607         tlinetemp[(node*numWth)+proc] = &tlinerecs[(numTraces*node+trace)*numWth+proc];
608       }
609     }
610     BgWriteTimelines(trace, tlinetemp, numProcs);
611     delete [] tlinetemp;
612   }
613 }