/*********************************************************************/ /* pC++/Sage++ Copyright (C) 1994 */ /* Indiana University University of Oregon University of Rennes */ /*********************************************************************/ /* * tau_convert.c : convert software event traces to other formats * * (c) 1994 Jerry Manic Saftware * * Version 3.0 * Revision Jan 1998 Author Sameer Shende, (sameer@cs.uoregon.edu) */ # include # include # include # include #ifdef TAU_WINDOWS #include #else #include #include #define O_BINARY 0 #endif #ifdef TAU_LARGEFILE #define LARGEFILE_OPTION O_LARGEFILE #else #define LARGEFILE_OPTION 0 #endif #include #define TRACING_ON #include # ifndef TRUE # define FALSE 0 # define TRUE 1 # endif # define F_EXISTS 0 # define SEND_EVENT -7 # define RECV_EVENT -8 /* The following three decl apply to -vampir (multi-node, multi-threaded) */ # define TAU_MAX_NODES 32*1024 /* max nodes, within nodes are threads */ static int offset[TAU_MAX_NODES] = { 0 }; /* offset to calculate cpuid */ static int maxtid[TAU_MAX_NODES] = { 0 }; /* max tid encountered for a node */ static struct trcdescr { int fd; /* -- input file descriptor -- */ char *name; /* -- corresponding file name -- */ int overflows; /* -- clock overflows in that trace -- */ int numevent; /* -- number of event types -- */ int numproc; /* -- number of processors -- */ long numrec; /* -- number of event records already processed -- */ x_uint64 firsttime; /* -- timestamp of first event record -- */ x_uint64 lasttime; /* -- timestamp of previous event record -- */ /* TAU_EV *buffer; -- input buffer -- */ /* TAU_EV *erec; -- current event record -- */ /* TAU_EV *next; -- next available event record in buffer -- */ /* TAU_EV *last; -- last event record in buffer -- */ void *buffer; /* -- input buffer -- */ void *erec; /* -- current event record -- */ void *next; /* -- next available event record in buffer -- */ void *last; /* -- last event record in buffer -- */ int format; /* see above */ int eventSize; /* sizeof() the corresponding format struct */ } intrc; struct trcrecv { int fd; /* -- input file descriptor -- */ /* TAU_EV *buffer; /\* -- input buffer -- *\/ */ /* TAU_EV *erec; /\* -- current event record -- *\/ */ /* TAU_EV *prev; /\* -- prev available event record in buffer -- *\/ */ /* TAU_EV *first; /\* -- first event record in buffer -- *\/ */ void *buffer; /* -- input buffer -- */ void *erec; /* -- current event record -- */ void *prev; /* -- prev available event record in buffer -- */ void *first; /* -- first event record in buffer -- */ int format; /* see above */ int eventSize; /* sizeof() the corresponding format struct */ }; void *tmpbuffer; /* for threaded program */ static enum format_t { alog, SDDF, pv, dump, paraver } outFormat = pv; static enum pvmode_t { user, pvclass, all } pvMode = user; static int pvCompact = FALSE; static int pvComm = TRUE; static int threads = FALSE; static int pvLongSymbolBugFix = FALSE; /* if symbol name > 200 prepend id */ static int dynamictrace = FALSE; static char *barrin, *barrout; /* -- for barrier checking -- */ #ifdef __TAU__ static int numin, numout; /* -- for barrier checking -- */ #endif /* __TAU__ */ static struct stkitem { char *state; /* -- state name ---- */ int tag; /* -- activity tag -- */ } **statestk, /* -- state stacks -- */ **stkptr; /* -- stack pointers -- */ # define STACKSIZE 1024 /* -------------------------------------------------------------------------- */ /* -- event type descriptor handling -- */ /* -------------------------------------------------------------------------- */ typedef struct evdescr { int no; int id; int tag; int used; char *name; char *param; char *state; struct evdescr *next; } EVDESCR; static EVDESCR **evtable; static int evno; static int numEvent; static int numUsedEvent; /* copied from TAU_tf_decl.h */ #include "Profile/tau_types.h" #define FORMAT_NATIVE 0 /* as a fallback */ #define FORMAT_32 1 #define FORMAT_64 2 #define FORMAT_32_SWAP 3 #define FORMAT_64_SWAP 4 /* for 32 bit platforms */ typedef struct { x_int32 ev; /* -- event id -- */ x_uint16 nid; /* -- node id -- */ x_uint16 tid; /* -- thread id -- */ x_int64 par; /* -- event parameter -- */ x_uint64 ti; /* -- time [us]? -- */ } TAU_EV32; /* for 64 bit platforms */ typedef struct { x_int64 ev; /* -- event id -- */ x_uint16 nid; /* -- node id -- */ x_uint16 tid; /* -- thread id -- */ x_uint32 padding; /* space wasted for 8-byte aligning the next item */ x_int64 par; /* -- event parameter -- */ x_uint64 ti; /* -- time [us]? -- */ } TAU_EV64; typedef TAU_EV TAU_EV_NATIVE; #define swap16(A) ((((x_uint16)(A) & 0xff00) >> 8) | \ (((x_uint16)(A) & 0x00ff) << 8)) #define swap32(A) ((((x_uint32)(A) & 0xff000000) >> 24) | \ (((x_uint32)(A) & 0x00ff0000) >> 8) | \ (((x_uint32)(A) & 0x0000ff00) << 8) | \ (((x_uint32)(A) & 0x000000ff) << 24)) #define swap64(A) ((((x_uint64)(A) & 0xff00000000000000ull) >> 56) | \ (((x_uint64)(A) & 0x00ff000000000000ull) >> 40) | \ (((x_uint64)(A) & 0x0000ff0000000000ull) >> 24) | \ (((x_uint64)(A) & 0x000000ff00000000ull) >> 8) | \ (((x_uint64)(A) & 0x00000000ff000000ull) << 8) | \ (((x_uint64)(A) & 0x0000000000ff0000ull) << 24) | \ (((x_uint64)(A) & 0x000000000000ff00ull) << 40) | \ (((x_uint64)(A) & 0x00000000000000ffull) << 56)) /* copied from TAU_tf_decl.h */ x_int32 event_GetEv(struct trcdescr *tFile, void *event, int index) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; return nativeEvent[index].ev; case FORMAT_32: event32 = (TAU_EV32*) event; return event32[index].ev; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; return swap32(event32[index].ev); case FORMAT_64: event64 = (TAU_EV64*) event; return event64[index].ev; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; return swap64(event64[index].ev); } return 0; } void event_SetEv(struct trcdescr *tFile, void *event, int index, x_int32 value) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; x_int64 tmpValue; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; nativeEvent[index].ev = value; break; case FORMAT_32: event32 = (TAU_EV32*) event; event32[index].ev = value; break; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; event32[index].ev = swap32(value); break; case FORMAT_64: event64 = (TAU_EV64*) event; event64[index].ev = value; break; case FORMAT_64_SWAP: tmpValue = value; event64 = (TAU_EV64*) event; event64[index].ev = swap64(tmpValue); break; } return; } x_uint64 event_GetTi(struct trcdescr *tFile, void *event, int index) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; return nativeEvent[index].ti; case FORMAT_32: event32 = (TAU_EV32*) event; return event32[index].ti; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; return swap64(event32[index].ti); case FORMAT_64: event64 = (TAU_EV64*) event; return event64[index].ti; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; return swap64(event64[index].ti); } return 0; } void event_SetTi(struct trcdescr *tFile, void *event, int index, x_uint64 value) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; nativeEvent[index].ti = value; break; case FORMAT_32: event32 = (TAU_EV32*) event; event32[index].ti = value; break; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; event32[index].ti = swap64(value); break; case FORMAT_64: event64 = (TAU_EV64*) event; event64[index].ti = value; break; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; event64[index].ti = swap64(value); break; } return; } x_uint16 event_GetNid(struct trcdescr *tFile, void *event, int index) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; return nativeEvent[index].nid; case FORMAT_32: event32 = (TAU_EV32*) event; return event32[index].nid; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; return swap16(event32[index].nid); case FORMAT_64: event64 = (TAU_EV64*) event; return event64[index].nid; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; return swap16(event64[index].nid); } return 0; } void event_SetNid(struct trcdescr *tFile, void *event, int index, x_uint16 value) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; nativeEvent[index].nid = value; break; case FORMAT_32: event32 = (TAU_EV32*) event; event32[index].nid = value; break; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; event32[index].nid = swap16(value); break; case FORMAT_64: event64 = (TAU_EV64*) event; event64[index].nid = value; break; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; event64[index].nid = swap16(value); break; } return; } x_uint16 event_GetTid(struct trcdescr *tFile, void *event, int index) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; return nativeEvent[index].tid; case FORMAT_32: event32 = (TAU_EV32*) event; return event32[index].tid; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; return swap16(event32[index].tid); case FORMAT_64: event64 = (TAU_EV64*) event; return event64[index].tid; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; return swap16(event64[index].tid); } return 0; } x_uint64 event_GetPar(struct trcdescr *tFile, void *event, int index) { TAU_EV_NATIVE *nativeEvent; TAU_EV32 *event32; TAU_EV64 *event64; switch (tFile->format) { case FORMAT_NATIVE: nativeEvent = (TAU_EV_NATIVE*)event; return nativeEvent[index].par; case FORMAT_32: event32 = (TAU_EV32*) event; return event32[index].par; case FORMAT_32_SWAP: event32 = (TAU_EV32*) event; return swap64(event32[index].par); case FORMAT_64: event64 = (TAU_EV64*) event; return event64[index].par; case FORMAT_64_SWAP: event64 = (TAU_EV64*) event; return swap64(event64[index].par); } return 0; } void determineFormat(struct trcdescr *tdes) { int bytesRead; int formatFound; TAU_EV32 event32; TAU_EV64 event64; formatFound = 0; /* printf ("determining format!\n"); */ /* printf ("sizeof(TAU_EV32) = %d\n", sizeof(TAU_EV32)); */ /* printf ("sizeof(TAU_EV64) = %d\n", sizeof(TAU_EV64)); */ /* printf ("par32 : %d\n", (long)&event32.par - (long)&event32); */ /* printf ("par64 : %d\n", (long)&event64.par - (long)&event64); */ /* lseek(tdes->fd, 0, SEEK_SET); */ bytesRead = read(tdes->fd, &event32, sizeof(TAU_EV32)); lseek(tdes->fd, 0, SEEK_SET); bytesRead = read(tdes->fd, &event64, sizeof(TAU_EV64)); lseek(tdes->fd, 0, SEEK_SET); /* 32 bit regular */ if (event32.par == 3) { tdes->format = FORMAT_32; tdes->eventSize = sizeof(TAU_EV32); formatFound = 1; /* printf ("32 regular!\n"); */ } /* 32 bit swapped */ if (swap64(event32.par) == 3) { if (formatFound == 1) { /* shouldn't happen, if it does, go to native */ tdes->format = FORMAT_NATIVE; tdes->eventSize = sizeof(TAU_EV_NATIVE); return; } tdes->format = FORMAT_32_SWAP; tdes->eventSize = sizeof(TAU_EV32); formatFound = 1; /* printf ("32 swapped!\n"); */ } /* 64 bit regular */ if (event64.par == 3) { if (formatFound == 1) { /* shouldn't happen, if it does, go to native */ tdes->format = FORMAT_NATIVE; tdes->eventSize = sizeof(TAU_EV_NATIVE); return; } tdes->format = FORMAT_64; tdes->eventSize = sizeof(TAU_EV64); formatFound = 1; /* printf ("64 regular!\n"); */ } /* 64 bit swapped */ if (swap64(event64.par) == 3) { if (formatFound == 1) { /* shouldn't happen, if it does, go to native */ tdes->format = FORMAT_NATIVE; tdes->eventSize = sizeof(TAU_EV_NATIVE); return; } tdes->format = FORMAT_64_SWAP; tdes->eventSize = sizeof(TAU_EV64); formatFound = 1; /* printf ("64 swapped!\n"); */ } if (formatFound == 0) { fprintf (stderr, "Warning: couldn't determine format, using native!\n"); tdes->format = FORMAT_NATIVE; tdes->eventSize = sizeof(TAU_EV_NATIVE); } /* printf ("event32.par = 0x%x\n", event32.par); */ /* printf ("swap32(event32.par) = 0x%x\n", swap32(event32.par)); */ /* printf ("event64.par = 0x%x\n", event64.par); */ /* printf ("swap64(event64.par) = 0x%x\n", swap64(event64.par)); */ /* printf ("---------------\n"); */ /* printf ("event64.ev = 0x%llx\n", swap64(event64.ev)); */ /* printf ("event64.nid = 0x%x\n", swap64(event64.nid)); */ /* printf ("event64.tid = 0x%x\n", swap64(event64.tid)); */ /* printf ("event64.padding = 0x%x\n", swap64(event64.padding)); */ /* printf ("event64.par = 0x%x\n", swap64(event64.par)); */ /* printf ("event64.ti = 0x%llx\n", swap64(event64.ti)); */ /* printf ("---------------\n"); */ /* printf ("event32.ev = 0x%llx\n", swap32(event32.ev)); */ /* printf ("event32.nid = 0x%x\n", swap32(event32.nid)); */ /* printf ("event32.tid = 0x%x\n", swap32(event32.tid)); */ /* printf ("event32.par = 0x%x\n", swap32(event32.par)); */ /* printf ("event32.ti = 0x%llx\n", swap32(event32.ti)); */ /* printf ("---------------\n"); */ /* printf ("swap(event32.ev) = %lu\n", swap32(event32.ev)); */ /* printf ("swap(event32.nid) = %u\n", swap32(event32.nid)); */ /* printf ("swap(event32.tid) = %u\n", swap32(event32.tid)); */ /* printf ("swap(event32.par) = %u\n", swap32(event32.par)); */ /* printf ("swap(event32.ti) = %llu\n", swap64(event32.ti)); */ } void decodeParameter(x_uint64 xpar, int *otherNid, int *msgLen, int *msgTag, int *comm) { /* See RtsLayer::TraceSendMsg for documentation on the bit patterns of "parameter" */ *msgTag = ((xpar>>16) & 0x000000FF) | (((xpar >> 48) & 0xFF) << 8); *otherNid = ((xpar>>24) & 0x000000FF) | (((xpar >> 56) & 0xFF) << 8); *msgLen = xpar & 0x0000FFFF | (xpar << 22 >> 54 << 16); *comm = xpar << 16 >> 58; } int GetNodeId(struct trcdescr *trc, void *rec); static void InitEvent (int numev) { int i; evtable = (EVDESCR **) malloc (numev * sizeof(EVDESCR)); for (i=0; iid = id; newev->tag = tag; newev->no = evno++; newev->used = FALSE; newev->name = (char *) malloc (strlen(name) + 1); strcpy (newev->name, name); if ( *p && outFormat != pv ) { newev->param = (char *) malloc (strlen(p) + 5); if ( outFormat == alog ) { /* sprintf (newev->param, "%s: %%d", p); */ } else { sprintf (newev->param, "%s", p); } } else newev->param = ""; if ( state[0] != '-' ) { if ( tag > 0 && pvMode == all ) { newev->name[strlen(newev->name)-6] = '\0'; if ( (ptr = strchr(newev->name, ':')) == NULL ) ptr = newev->name; else ptr += 2; newev->state = (char *) malloc (strlen(ptr) + 1); strcpy (newev->state, ptr); newev->name[strlen(newev->name)] = '-'; } else { newev->state = (char *) malloc (strlen(state) + 1); strcpy (newev->state, state); } } else newev->state = ""; h = id % numEvent; newev->next = evtable[h]; evtable[h] = newev; } static void AddEventDynamic (int id, char *name, char *p, char *state, int tag) { int h; EVDESCR *newev; #ifdef DEBUG printf("Adding id %d name %s par %s state %s tag %d\n", id, name, p, state, tag); #endif /* DEBUG */ newev = (EVDESCR *) malloc (sizeof(EVDESCR)); if (newev == (EVDESCR *) NULL) { fprintf(stderr,"AddEventDynamic : out of memory malloc returns NULL\n"); exit(1); } newev->id = id; newev->tag = tag; newev->no = evno++; newev->used = FALSE; newev->name = (char *) malloc (strlen(name) + 10); /* add 10 not 1, so if we need to add an id to the name, there is space */ if (pvLongSymbolBugFix) /* For a long name, prepend its id to its name */ { if (strlen(name) > 200) sprintf(newev->name, "\"%d-%s", newev->no, &name[1]); else strcpy (newev->name, name); } else strcpy (newev->name, name); if ( *p && outFormat != pv ) { newev->param = (char *) malloc (strlen(p) + 5); if ( outFormat == alog ) sprintf (newev->param, "%s: %%d", p); else sprintf (newev->param, "%s", p); } else newev->param = ""; if ( state[0] != '-' ) { newev->state = (char *) malloc (strlen(state) + 1); strcpy (newev->state, state); } else newev->state = ""; h = id % numEvent; newev->next = evtable[h]; evtable[h] = newev; } static EVDESCR *GetEventStruct (int id) { int h; EVDESCR *ev; h = id % numEvent; ev = evtable[h]; while ( ev ) { if ( ev->id == id ) return (ev); ev = ev->next; } return (0); } static int GetEvent (int id) { int h; EVDESCR *ev; h = id % numEvent; ev = evtable[h]; while ( ev ) { if ( ev->id == id ) { if ( !ev->used ) { ev->used = TRUE; numUsedEvent++; } return (ev->no); } ev = ev->next; } return (0); } static char *GetEventName (int id, int *hasParam) { int h; EVDESCR *ev; h = id % numEvent; ev = evtable[h]; while ( ev ) { if ( ev->id == id ) { *hasParam = ev->param[0]; return (ev->name); } ev = ev->next; } *hasParam = FALSE; return (0); } static int IsDoubleParam(int id) { int h; EVDESCR *ev; /* TAU uses doubles for internal representation but for some reason writes 64-bit unsigned integers to traces I had added this IsDoubleParam and it is used below when I changed it to write doubles for the traces, but I never commited the changes since I didn't want to break compatibility */ /* comment this out if TAU stores user events as doubles */ return 0; h = id % numEvent; ev = evtable[h]; while ( ev ) { if ( ev->id == id ) { if (strncmp(ev->param,"TriggerValue",strlen("TriggerValue")) == 0) { return 1; } else { return 0; } } ev = ev->next; } return 0; } static void PrintEventDescr (FILE *out) { int i; EVDESCR *ev; for (i=0; iused ) { if ( outFormat == alog ) { fprintf (out, " -9 0 0 %10d 0 0 %s\n", ev->no, ev->name); fprintf (out, "-10 0 0 %10d 0 0 %s\n", ev->no, ev->param); } else if ( outFormat == SDDF ) { fprintf (out, "#%d:\n", ev->no); fprintf (out, "%s {\n", ev->name); fprintf (out, "\tunsigned long long\t\"Timestamp\";\n"); fprintf (out, "\tint\t\"Processor Number\";\n"); fprintf (out, "\tint\t\"Thread Id\";\n"); if ( ev->param[0] ) fprintf (out, "\tint\t\"%s\";\n", ev->param); /* OLD Code. Why have the name? There's no %s. */ /* fprintf (out, "};;\n\n", ev->name); */ fprintf (out, "};;\n\n"); } else if ( outFormat == pv ){ if (! dynamictrace) { if ( ev->tag > 0 || ev->tag < -9 ) { ev->name[strlen(ev->name)-6] = '\0'; /*fprintf (out, "SYMBOL %s %d %s\n", ev->state, ev->tag, ev->name);*/ fprintf (out, "SYMBOL %s %d %s\n", ev->state, ev->no, ev->name); ev->name[strlen(ev->name)] = '-'; } } else /* don't do anything special for dynamic trace */ { fprintf (out, "SYMBOL %s %d %s\n", ev->state, ev->no, ev->name); } } } ev = ev->next; } } } /* -------------------------------------------------------------------------- */ /* -- is it an INIT event ? -- */ /* -------------------------------------------------------------------------- */ int isInitEvent(struct trcdescr *trc, void *erecord) { char *eventName; int hasParam; eventName = GetEventName(event_GetEv(trc,erecord,0), &hasParam); if (dynamictrace) { if (strcmp(eventName, "\"EV_INIT\"") == 0) { return TRUE; } else { return FALSE; } } else { /* old traces use events determined by fixed #define nos. */ if ( (event_GetEv(trc,erecord,0) == TAU_EV_INIT) || (event_GetEv(trc,erecord,0) == TAU_EV_INITM) ) { return TRUE; } else { return FALSE; } } /* old format */ } /* -------------------------------------------------------------------------- */ /* -- get today's date -- */ /* -------------------------------------------------------------------------- */ # include static char tibuf[12]; static char *Months[12] = {"Jan","Feb","Mar","Apr","May","Jun","jul","Aug","Sep","Oct","Nov","Dec"}; static char *Today (void) { time_t t; struct tm *tm; t = time ((time_t *) 0); tm = localtime (&t); sprintf (tibuf, "%s-%02d-%02d", Months[tm->tm_mon], tm->tm_mday, 1900+tm->tm_year); return (tibuf); } /* -------------------------------------------------------------------------- */ /* -- input buffer handling -- */ /* -------------------------------------------------------------------------- */ # define INMAX BUFSIZ /* records */ static void *get_next_rec (struct trcdescr *tdes) { long no; if ( (tdes->last == NULL) || (tdes->next > tdes->last) ) { /* -- input buffer empty: read new records from file -------------------- */ if ( (no = read (tdes->fd, tdes->buffer, INMAX * tdes->eventSize)) != (INMAX * tdes->eventSize) ) { if ( no == 0 ) { /* no more records */ return NULL; } else if ( (no % tdes->eventSize) != 0 ) { /* -- read error: --------------------------------------------------- */ printf("Read error: %ld and %ld\n",no,tdes->eventSize); fprintf (stderr, "%s: read error\n", tdes->name); exit (1); } } /* -- we got some event records ----------------------------------------- */ tdes->next = tdes->buffer; tdes->last = (char*)tdes->buffer + no - tdes->eventSize; } tdes->erec = tdes->next; tdes->next = (void*)(((char*)tdes->next) + tdes->eventSize); return tdes->erec; } static void *get_prev_rec (struct trcrecv *tdes) { /* Before calling this the first time set first properly. */ long no; off_t last_position; last_position = lseek(tdes->fd, 0, SEEK_CUR); /* We reuse last and next to actually mean first and prev respectively */ /* i.e., before calling this the first time set tdes->last = tdes->buffer */ /* if prev < first, go fetch more records */ /* to debug: print each record */ if (( last_position == 0) || (tdes->prev < tdes->first)) { /* move the pointer 2*INMAX*sizeof(TAU_EV) earlier */ last_position -= 2*INMAX*tdes->eventSize; #ifdef DEBUG printf("last_position = %d\n", last_position); #endif /* DEBUG */ if (last_position < 0) return NULL; lseek(tdes->fd, last_position, SEEK_SET); /* -- input buffer empty: read new records from file -------------------- */ if ( (no = read (tdes->fd, tdes->buffer, INMAX * tdes->eventSize)) != (INMAX * tdes->eventSize) ) { if ( no == 0 ) { /* -- no more event record: ----------------------------------------- */ return NULL; } else if ( no % tdes->eventSize != 0 ) { /* -- read error: --------------------------------------------------- */ fprintf (stderr, "read error in get_prev_rec\n"); exit (1); } } /* -- we got some event records ----------------------------------------- */ tdes->prev = (char*)tdes->buffer + no - tdes->eventSize; tdes->first = tdes->buffer ; } tdes->erec = tdes->prev; tdes->prev = (void*)(((char*)tdes->prev) - tdes->eventSize); return tdes->erec; } int GetNodeId(struct trcdescr *trc, void *rec) { if (threads) { /* OLD return rec->tid; */ return offset[event_GetNid(trc,rec,0)] + event_GetTid(trc,rec,0); /* CPUID ranges from 0..N-1: N is sum(threads on all nodes ) */ } else { return event_GetNid(trc,rec,0); } } int GetMatchingRecv(struct trcdescr trcdes, int msgtag, int myid, int otherid, int msglen, int *other_tid, int *other_nodeid) /* parameters: trcdes: input trace file descriptor. msgtag: message tag that we're searching for msglen: message length that we're searching for myid: id encoded in the parameter. Not +1. otherid: rank of the other process other_tid: thread id of the matching ipc call other_nodeid: node id of the matching ipc call */ { off_t last_position; /* TAU_EV *curr_rec; */ void *curr_rec; EVDESCR *curr_ev; int curr_tag, curr_len, curr_nid, dummy, comm; trcdes.buffer = tmpbuffer; #ifdef DEBUG printf("GetMatchingRecv: SEND, tag=%d, len=%d, myid=%d, otherid=%d\n", msgtag, msglen, myid, otherid); #endif /* DEBUG */ /* get the current position from the trace file descriptor */ last_position = lseek(trcdes.fd, 0, SEEK_CUR); if (last_position < 0) { perror("lseek ERROR: GetMatchingRecv() routine that matches sends/receives"); exit(1); } #ifdef DEBUG printf("last_position = %d\n", last_position); #endif /* DEBUG */ /* now get the records one by one */ /* We've made a copy of intrc in the trcdes descriptor. So, even if this changes the state of intrc remains the same. We need to do an lseek with the original position, of course. */ while (( curr_rec = get_next_rec(&trcdes)) != NULL) { /* Get the event type for this record */ /* curr_ev = GetEventStruct (curr_rec->ev); */ curr_ev = GetEventStruct (event_GetEv(&trcdes,curr_rec,0)); /* Find the matching send and receive */ /* is the current record of the complementary IPC type? */ if (curr_ev->tag == RECV_EVENT) { /* possible match */ decodeParameter(event_GetPar(&trcdes,curr_rec,0), &dummy, &curr_len, &curr_tag, &comm); curr_nid = event_GetNid(&trcdes,curr_rec,0); #ifdef DEBUG printf("Possible match... tag=%d, len=%d, nid=%d\n", curr_tag, curr_len, curr_nid); #endif /* DEBUG */ if ((curr_tag == msgtag) && (curr_len == msglen) && (curr_nid == otherid )) { *other_tid = event_GetTid(&trcdes,curr_rec,0); *other_nodeid = event_GetNid(&trcdes,curr_rec,0); #ifdef DEBUG printf("PERFECT MATCH! other tid = %d, nid = %d\n", *other_tid, *other_nodeid); #endif /* DEBUG */ /* Reset trace file */ lseek(trcdes.fd, last_position, SEEK_SET); return 1; } /* This only applies to Send! */ } } /* EOF : didn't find the matching send. Reset and leave */ #ifdef DEBUG printf("Didn't find matching ipc...\n"); #endif /* DEBUG */ lseek(trcdes.fd, last_position, SEEK_SET); return 0; } int GetMatchingSend(struct trcdescr trcdes, int msgtag, int myid, int otherid, int msglen, int *other_tid, int *other_nodeid) /* parameters: trcdes: input trace file descriptor. msgtag: message tag that we're searching for msglen: message length that we're searching for myid: id encoded in the parameter. Not +1. otherid: rank of the other process other_tid: thread id of the matching ipc call other_nodeid: node id of the matching ipc call */ { off_t last_position; void *curr_rec; EVDESCR *curr_ev; int curr_tag, curr_len, curr_nid, dummy, comm; struct trcrecv rcvdes; struct trcrecv *ted; rcvdes.buffer = tmpbuffer; rcvdes.erec = trcdes.erec; rcvdes.fd = trcdes.fd; rcvdes.first = trcdes.buffer; rcvdes.prev = (char*)trcdes.erec - trcdes.eventSize; rcvdes.eventSize = trcdes.eventSize; /* initialize the first and prev pointers */ #ifdef DEBUG printf("GetMatchingSend: RECV, tag=%d, len=%d, myid=%d, otherid=%d\n", msgtag, msglen, myid, otherid); #endif /* DEBUG */ /* get the current position from the trace file descriptor */ last_position = lseek(rcvdes.fd, 0, SEEK_CUR); if (last_position < 0) { perror("lseek ERROR: GetMatchingSend() routine that matches sends/receives"); exit(1); } #ifdef DEBUG printf("last_position = %d\n", last_position); #endif /* DEBUG */ /* now get the records one by one */ /* We've made a copy of intrc in the trcdes descriptor. So, even if this changes the state of intrc remains the same. We need to do an lseek with the original position, of course. */ ted = &rcvdes; while (( curr_rec = get_prev_rec(&rcvdes)) != NULL) { /* Get the event type for this record */ curr_ev = GetEventStruct (event_GetEv(&trcdes,curr_rec,0)); /* Find the matching send and receive */ /* is the current record of the complementary IPC type? */ if (curr_ev->tag == SEND_EVENT) { /* possible match */ decodeParameter(event_GetPar(&trcdes,curr_rec,0), &dummy, &curr_len, &curr_tag, &comm); curr_nid = event_GetNid(&trcdes,curr_rec,0); #ifdef DEBUG printf("Possible match... tag=%d, len=%d, nid=%d\n", curr_tag, curr_len, curr_nid); #endif /* DEBUG */ if ((curr_tag == msgtag) && (curr_len == msglen) && (curr_nid == otherid )) { *other_tid = event_GetTid(&trcdes,curr_rec,0); *other_nodeid = event_GetNid(&trcdes,curr_rec,0); #ifdef DEBUG printf("PERFECT MATCH! other tid = %d, nid = %d\n", *other_tid, *other_nodeid); #endif /* DEBUG */ /* Reset trace file */ lseek(rcvdes.fd, last_position, SEEK_SET); return 1; } /* This only applies to Send! */ } } /* EOF : didn't find the matching send. Reset and leave */ #ifdef DEBUG printf("Didn't find matching ipc...\n"); #endif /* DEBUG */ lseek(trcdes.fd, last_position, SEEK_SET); return 0; } x_int64 GetMatchingRecvPRV(struct trcdescr trcdes, int msgtag, int myid, int otherid, int msglen, int *other_tid, int *other_nodeid) /* parameters: trcdes: input trace file descriptor. msgtag: message tag that we're searching for msglen: message length that we're searching for myid: id encoded in the parameter. Not +1. otherid: rank of the other process other_tid: thread id of the matching ipc call other_nodeid: node id of the matching ipc call */ { x_int64 phRecv = 0; off_t last_position; void *curr_rec; EVDESCR *curr_ev; int curr_tag, curr_len, curr_nid, dummy, comm; trcdes.buffer = tmpbuffer; #ifdef DEBUG printf("GetMatchingRecv: SEND, tag=%d, len=%d, myid=%d, otherid=%d\n", msgtag, msglen, myid, otherid); #endif /* DEBUG */ /* get the current position from the trace file descriptor */ last_position = lseek(trcdes.fd, 0, SEEK_CUR); if (last_position < 0) { perror("lseek ERROR: GetMatchingRecv() routine that matches sends/receives"); exit(1); } #ifdef DEBUG printf("last_position = %d\n", last_position); #endif /* DEBUG */ /* now get the records one by one */ /* We've made a copy of intrc in the trcdes descriptor. So, even if this changes the state of intrc remains the same. We need to do an lseek with the original position, of course. */ while (( curr_rec = get_next_rec(&trcdes)) != NULL) { /* Get the event type for this record */ curr_ev = GetEventStruct (event_GetEv(&trcdes,curr_rec,0)); /* Find the matching send and receive */ /* is the current record of the complementary IPC type? */ if (curr_ev->tag == RECV_EVENT) { /* possible match */ decodeParameter(event_GetPar(&trcdes,curr_rec,0), &dummy, &curr_len, &curr_tag, &comm); curr_nid = event_GetNid(&trcdes,curr_rec,0); #ifdef DEBUG printf("Possible match... tag=%d, len=%d, nid=%d\n", curr_tag, curr_len, curr_nid); #endif /* DEBUG */ if ((curr_tag == msgtag) && (curr_len == msglen) && (curr_nid == otherid )) { *other_tid = event_GetTid(&trcdes,curr_rec,0); *other_nodeid = event_GetNid(&trcdes,curr_rec,0); phRecv = event_GetTi(&trcdes,curr_rec,0) - intrc.firsttime; #ifdef DEBUG printf("PERFECT MATCH! other tid = %d, nid = %d\n", *other_tid, *other_nodeid); #endif /* DEBUG */ /* Reset trace file */ lseek(trcdes.fd, last_position, SEEK_SET); return phRecv; } /* This only applies to Send! */ } } /* EOF : didn't find the matching send. Reset and leave */ #ifdef DEBUG printf("Didn't find matching ipc...\n"); #endif /* DEBUG */ lseek(trcdes.fd, last_position, SEEK_SET); return phRecv; } /* -------------------------------------------------------------------------- */ /* -- TAU_CONVERT MAIN PROGRAM --------------------------------------------- */ /* -------------------------------------------------------------------------- */ # define LINEMAX 64*1024 int main (int argc, char *argv[]) { FILE *outfp, *inev,*pcffp; void *erec; int i,j,k,l; int nodeId, totalnodes = 0; int num; int tag; int myid, otherid, msglen, msgtag, comm; int other_tid, other_nodeid; /* for threaded programs */ int hasParam; int fileIdx; int *prvPCF; int numproc = 0; char name[LINEMAX], state[80], param[80], linebuf[LINEMAX]; char traceflag[32]; char *inFile, *edfFile, *outFile, *ptr,*pcfFile; EVDESCR *ev; struct trcrecv rcvdes; myid = 0; otherid = 0; msglen = 0; msgtag = 0; comm = 0; other_tid = 0; other_nodeid = 0; /* ------------------------------------------------------------------------ */ /* -- scan command line arguments -- */ /* ------------------------------------------------------------------------ */ if ( strcmp (argv[0]+strlen(argv[0])-4, "sddf") == 0 ) outFormat = SDDF; else if ( strcmp (argv[0]+strlen(argv[0])-4, "alog") == 0 ) outFormat = alog; else if ( strcmp (argv[0]+strlen(argv[0])-4, "dump") == 0 ) outFormat = dump; else if ( strcmp (argv[0]+strlen(argv[0])-2, "pv") == 0 ) outFormat = pv; else if ( strcmp (argv[0]+strlen(argv[0])-7, "paraver") == 0){ outFormat = paraver; } else if ( strcmp (argv[0]+strlen(argv[0])-6, "vampir") == 0 ) threads = TRUE; fileIdx = 1; if ( argc < 4 ) { fprintf (stderr, "usage: %s [-alog | -SDDF | -dump | -paraver [-t] |", argv[0]); fprintf (stderr, " -pv | -vampir [-longsymbolbugfix] [-compact] [-user|-class|-all] [-nocomm]]"); fprintf (stderr, " inputtrc edffile [outputtrc]\n"); fprintf (stderr, " Note: -vampir option assumes multiple threads/node\n"); fprintf (stderr, " Note: -t option used in conjunction with -paraver option assumes multiple threads/node\n"); exit (1); } else if ( strcmp (argv[1], "-alog") == 0 || strcmp (argv[1], "-a") == 0 ) { outFormat = alog; fileIdx = 2; } else if ( strcmp (argv[1], "-SDDF") == 0 || strcmp (argv[1], "-S") == 0 ) { outFormat = SDDF; fileIdx = 2; } else if ( strcmp (argv[1], "-pv") == 0 || strcmp (argv[1], "-p") == 0 ) { outFormat = pv; i = 2; while ( argv[i][0] == '-' ) { if ( strcmp (argv[i], "-longsymbolbugfix") == 0 ) pvLongSymbolBugFix = TRUE; else if ( strcmp (argv[i], "-compact") == 0 ) pvCompact = TRUE; else if ( strcmp (argv[i], "-user") == 0 ) pvMode = user; else if ( strcmp (argv[i], "-class") == 0 ) pvMode = pvclass; else if ( strcmp (argv[i], "-all") == 0 ) pvMode = all; else if ( strcmp (argv[i], "-nocomm") == 0 ) pvComm = FALSE; else break; i++; } fileIdx = i; } else if ( strcmp (argv[1], "-dump") == 0 || strcmp (argv[1], "-d") == 0 ) { outFormat = dump; fileIdx = 2; } else if ( strcmp (argv[1], "-paraver") == 0 || strcmp (argv[1], "-prv") == 0 ) { outFormat = paraver; i = 2; while( argv[i][0] == '-' ) { if( strcmp (argv[i], "-t") == 0 ){ threads = TRUE; } else break; i++; } fileIdx = i; } else if ( strcmp (argv[1], "-vampir") == 0 || strcmp (argv[1], "-v") == 0) { outFormat = pv; threads = TRUE; #ifdef DEBUG printf("Using Vampir with threads"); #endif i = 2; while ( argv[i][0] == '-' ) { if ( strcmp (argv[i], "-longsymbolbugfix") == 0 ) pvLongSymbolBugFix = TRUE; else if ( strcmp (argv[i], "-compact") == 0 ) pvCompact = TRUE; else if ( strcmp (argv[i], "-user") == 0 ) pvMode = user; else if ( strcmp (argv[i], "-class") == 0 ) pvMode = pvclass; else if ( strcmp (argv[i], "-all") == 0 ) pvMode = all; else if ( strcmp (argv[i], "-nocomm") == 0 ) pvComm = FALSE; else break; i++; } fileIdx = i; } #ifdef DEBUG if (pvLongSymbolBugFix) printf("LONG_SYMBOL_BUG_FIX is in effect ! \n"); #endif /* DEBUG */ inFile = argv[fileIdx]; edfFile = argv[fileIdx+1]; if ( (fileIdx+2) == argc ) outFile = (char *) NULL; else outFile = argv[fileIdx+2]; /* ------------------------------------------------------------------------ */ /* -- open input trace -- */ /* ------------------------------------------------------------------------ */ if ( (intrc.fd = open (inFile, O_RDONLY | O_BINARY | LARGEFILE_OPTION)) < 0 ) { perror (inFile); exit (1); } else { determineFormat(&intrc); intrc.name = inFile; intrc.buffer = malloc (INMAX * intrc.eventSize); intrc.erec = NULL; intrc.next = NULL; intrc.last = NULL; intrc.overflows = 0; if((threads) || (outFormat == paraver)) tmpbuffer = malloc (INMAX * intrc.eventSize); /* -- read first event record ------------------------------------------- */ if ( (erec = get_next_rec (&intrc)) == NULL ) { /* -- no event record: ------------------------------------------------ */ fprintf (stderr, "%s: warning: trace empty - ignored\n", intrc.name); intrc.numrec = 0L; } /* -- check first event record ------------------------------------------ */ /* Can't check this as isInitEvent requires event .edf file to be read in */ /* and at this stage the edf file has not been opened */ /* else if (!isInitEvent(erec)) { fprintf (stderr, "%s: no valid event trace\n", intrc.name); exit (1); } */ else { intrc.numrec = 1L; if (threads) { /* Don't call GetNodeId here as it uses offset, maxthreads */ intrc.numproc = event_GetNid(&intrc,erec,0); } else { /* No threads */ intrc.numproc = GetNodeId(&intrc,erec); } intrc.firsttime = event_GetTi(&intrc,erec,0); intrc.lasttime = event_GetTi(&intrc,erec,0); } } /* ------------------------------------------------------------------------ */ /* -- open output trace file -- */ /* ------------------------------------------------------------------------ */ if ( outFile ) { if ( access (outFile, F_EXISTS) == 0 && isatty(2) ) { fprintf (stderr, "%s exists; override [y]? ", outFile); if ( getchar() == 'n' ) exit (1); } if ( (outfp = fopen (outFile, "wb")) == NULL ) { perror (outFile); exit (1); } } else outfp = stdout; /* ------------------------------------------------------------------------ */ /* -- initialize event description database ------------------------------- */ /* ------------------------------------------------------------------------ */ /* -- read event descriptor file and write event descriptor part header --- */ if ( (inev = fopen (edfFile, "rb")) == NULL ) { perror (edfFile); exit (1); } fgets (linebuf, LINEMAX, inev); sscanf (linebuf, "%d %s", &intrc.numevent, traceflag); if (strcmp(traceflag, "dynamic_trace_events") == 0) { dynamictrace = TRUE; } InitEvent (intrc.numevent); for (i=0; i totalnodes ) totalnodes = event_GetNid(&intrc,erec,0); /* totalnodes has node id in the range 0..N-1 */ if ( maxtid[event_GetNid(&intrc,erec,0)] < event_GetTi(&intrc,erec,0) ) maxtid[event_GetNid(&intrc,erec,0)] = event_GetTi(&intrc,erec,0); /* Update the max thread id vector for this node for each record */ /* printf("maxtid[%d] = %d\n", totalnodes, maxtid[totalnodes]); */ } else { /* no threads */ if ( GetNodeId(&intrc,erec) > intrc.numproc ) intrc.numproc = GetNodeId(&intrc,erec); } } } while ( erec != NULL ); #ifdef DEBUG printf("After parsing the trace file...\n"); #endif /* DEBUG */ if (threads) { /* We've gone through the whole trace, now make the offset vector */ offset[0] = 0; for(nodeId = 1; nodeId <= totalnodes; nodeId++) { offset[nodeId] = offset[nodeId - 1] + maxtid[nodeId - 1] + 1; /* printf("offset[%d] = %d\n", nodeId, offset[nodeId]); */ /* So if node 0 has 2 threads, 1 has 3 and 2 has 3, then maxtid[0] = 1, maxtid[1] = 2, maxtid[2] = 2 and offset[0] = 0, offset[1] = 2, offset[2] = 5 */ } intrc.numproc = offset[totalnodes] + maxtid[totalnodes]; } /* printf("Done with offset! numproc = %d\n", intrc.numproc); */ /* ------------------------------------------------------------------------ */ /* -- write trace file header --------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* -- write fixed header -------------------------------------------------- */ if ( outFormat == alog ) { fprintf (outfp, " -2 0 0 %10ld 0 0\n", intrc.numrec); fprintf (outfp, " -3 0 0 %10d 0 0\n", intrc.numproc+1); fprintf (outfp, " -4 0 0 1 0 0\n"); fprintf (outfp, " -5 0 0 %10d 0 0\n", numUsedEvent); fprintf (outfp, " -6 0 0 0 0 %10llu\n", intrc.firsttime); fprintf (outfp, " -7 0 0 0 0 %10llu\n", intrc.lasttime); fprintf (outfp, " -8 0 0 %10d 0 0\n", intrc.overflows+1); fprintf (outfp, " -1 0 0 0 0 0 tau_convert -alog %s\n", Today()); fprintf (outfp, "-11 0 0 0 0 4294967295\n"); } else if ( outFormat == SDDF ) { fprintf (outfp, "/*\n"); fprintf (outfp, " * \"creation program\" \"tau_convert -SDDF\"\n"); fprintf (outfp, " * \"creation date\" \"%s\"\n", Today()); fprintf (outfp, " * \"number records\" \"%ld\"\n", intrc.numrec); fprintf (outfp, " * \"number processors\" \"%d\"\n", intrc.numproc+1); fprintf (outfp, " * \"first timestamp\" \"%llu\"\n", intrc.firsttime); fprintf (outfp, " * \"last timestamp\" \"%llu\"\n", intrc.lasttime); fprintf (outfp, " */\n\n"); } else if ( outFormat == pv ) { /* The time in the record comes from GetUSecD() converted to long - so it should be in microseconds. */ /* old fprintf (outfp, "CLKPERIOD 0.1000E-06\n"); */ fprintf (outfp, "CLKPERIOD 1.0E-06\n"); if (threads) { /* PUT CPUS HERE !*/ fprintf(outfp,"NCPUS"); for(l=0; l < totalnodes+1; l++) { fprintf(outfp," %d", maxtid[l]+1); } fprintf(outfp,"\n"); fprintf(outfp, "CPUNAMES"); for(l=0; l < totalnodes+1; l++) { fprintf(outfp," \"Node %d\"", l); } fprintf(outfp,"\n"); } else { /* just report number of processors */ fprintf (outfp, "NCPUS %d\n", intrc.numproc+1); } fprintf (outfp, "C CREATION PROGRAM tau_convert -pv\n"); fprintf (outfp, "C CREATION DATE %s\n", Today()); fprintf (outfp, "C NUMBER RECORDS %ld\n", intrc.numrec); fprintf (outfp, "C FIRST TIMESTAMP %llu\n", intrc.firsttime); fprintf (outfp, "C LAST TIMESTAMP %llu\n", intrc.lasttime); fprintf (outfp, "C\n"); /* -- initialize state stacks -- */ statestk = (struct stkitem **) malloc ((intrc.numproc+1)*sizeof(struct stkitem *)); stkptr = (struct stkitem **) malloc ((intrc.numproc+1)*sizeof(struct stkitem *)); for (i=0; i<=intrc.numproc; i++) { stkptr[i] = statestk[i] = (struct stkitem *) malloc (STACKSIZE * sizeof(struct stkitem)); stkptr[i]->state = "IDLE"; stkptr[i]->tag = -99; } } else if ( outFormat == dump ) { fprintf (outfp, "# creation program: tau_convert -dump\n"); fprintf (outfp, "# creation date: %s\n", Today()); fprintf (outfp, "# number records: %ld\n", intrc.numrec); fprintf (outfp, "# number processors: %d\n", numproc); fprintf (outfp, "# max processor num: %d\n", intrc.numproc); #ifdef TAU_WINDOWS fprintf (outfp, "# first timestamp: %I64u\n", intrc.firsttime); fprintf (outfp, "# last timestamp: %I64u\n\n", intrc.lasttime); #else fprintf (outfp, "# first timestamp: %llu\n", intrc.firsttime); fprintf (outfp, "# last timestamp: %llu\n\n", intrc.lasttime); #endif fprintf (outfp, "#=NO= =======================EVENT=="); fprintf (outfp, " ==TIME [us]= =NODE= =THRD= ==PARAMETER=\n"); } else if ( outFormat == paraver ){ char date[50]; #ifndef TAU_WINDOWS struct timeval tp; struct timezone tzp; time_t clock; struct tm *ptm; #endif int i; int j; int size; char *taskList; char *tempList; int myNodeNum = 0; /* The code from libseqparaver.c is used here */ /* Get the date in the form dd/mm/yy */ #ifdef TAU_WINDOWS sprintf (date, "Unsupported in Win32"); #else gettimeofday (&tp, &tzp); clock = tp.tv_sec; ptm = localtime (&clock); strftime (date, 50, "%d/%m/%y at %H:%M", ptm); #endif /*Allocate space for the taskList portion of the header /if using threads, then numCpus = totalnodes. Otherwise /use intrc.numproc.*/ if(threads){ myNodeNum = totalnodes + 1; } else{ myNodeNum = intrc.numproc + 1; } size = ((myNodeNum) * 5); taskList = (char*)malloc(size * sizeof (char)); tempList = (char*)malloc(size * sizeof (char)); if(taskList == (char*)NULL){ perror("Malloc error\n"); } if(tempList == (char*)NULL){ perror("Malloc error\n"); } taskList[0] = '\0'; /*Write the taskList portion of the header in the form / "numThreads:onCpuId n,numThreads:onCpuId n+1"*/ for(i = 0; i < myNodeNum; i++){ if(myNodeNum - i != 1){ if(tempList == (char*)NULL){ perror("Malloc error-Paraver Header Var. tempList"); } sprintf(tempList,"%d:%d,",maxtid[i]+1,i+1); if(taskList == (char*)NULL){ perror("Malloc error-Paraver Header Var. taskList"); } taskList = strcat(taskList,tempList); } else{ sprintf(tempList,"%d:%d",maxtid[i]+1,i+1); taskList = strcat(taskList,tempList); } } /* create the first part of the pcf File to be loaded automatically with the .prv file in paraver change the file extension of outFile from prv to pcf */ if(! outFile){ outfp = stdout; pcfFile = (char*)malloc(30 * sizeof(char)); strcpy(pcfFile,"config.pcf"); } else{ if(strlen(outFile) < 5){ printf("Outfile must be of form *.prv\n"); exit(1); } pcfFile = (char*)malloc((strlen(outFile)+1) * sizeof (char)); pcfFile = (strcpy(pcfFile,outFile)); pcfFile[strlen(outFile) - 3] = '\0'; pcfFile = (strcat(pcfFile,"pcf")); } if ( pcfFile ){ if ( access ("pcfFile", F_EXISTS) == 0 && isatty(2) ){ fprintf (stderr, "%s exists; override [y]? ", pcfFile); if ( getchar() == 'n' ) exit (1); } if ( (pcffp = fopen (pcfFile, "wb")) == NULL ){ perror (pcfFile); exit (1); } } else{ pcffp = stdout; } fprintf(pcffp,"DEFAULT_OPTIONS\n\n"); fprintf(pcffp,"LEVEL THREAD\n"); fprintf(pcffp,"UNITS MICROSEC\n"); fprintf(pcffp,"LOOK_BACK 100\n"); fprintf(pcffp,"SPEED 1\n"); fprintf(pcffp,"FLAG_ICONS ENABLED\n"); fprintf(pcffp,"NUM_OF_STATE_COLORS 1\n"); fprintf(pcffp,"YMAX_SCALE %d\n\n\n",intrc.numrec); fprintf(pcffp,"DEFAULT_SEMANTIC\n\n"); fprintf(pcffp,"COMPOSE1_FUNC As Is\n"); fprintf(pcffp,"THREAD_FUNC Last Evt Val\n\n\n"); fprintf(pcffp,"STATES\n"); fprintf(pcffp,"0 NOT USED\n"); fprintf(pcffp,"1 RUNNING\n"); fprintf(pcffp,"2 NOT USED\n"); fprintf(pcffp,"3 NOT USED\n"); fprintf(pcffp,"4 NOT USED\n"); fprintf(pcffp,"5 NOT USED\n"); fprintf(pcffp,"6 NOT USED\n"); fprintf(pcffp,"7 NOT USED\n"); fprintf(pcffp,"8 NOT USED\n"); fprintf(pcffp,"9 NOT USED\n"); fprintf(pcffp,"4 NOT USED\n"); fprintf(pcffp,"10 NOT USED\n"); fprintf(pcffp,"11 NOT USED\n"); fprintf(pcffp,"12 NOT USED\n"); fprintf(pcffp,"13 NOT USED\n\n"); fprintf(pcffp,"STATES_COLOR\n"); fprintf(pcffp,"1 {117,195,255}\n"); fprintf(pcffp,"EVENT_TYPE\n"); fprintf(pcffp,"0 5 METHOD entry/exit:\n"); fprintf(pcffp,"VALUES\n"); prvPCF = (int*)malloc(intrc.numevent * sizeof(int)); for(i = 0; i < intrc.numevent; i++){ prvPCF[i] = 0; } fprintf (outfp, "#Paraver (%s):%llu:%d:1:%d(%s)\n", date, (intrc.lasttime - intrc.firsttime),myNodeNum,myNodeNum,taskList); /*for each thread on each node write at the beginning of the / trace file a state record indicating "RUNNING" state*/ for(i = 0; i < myNodeNum; i++){ for(j = 0; j <= maxtid[i]; j++){ fprintf(outfp,"1:%d:1:%d:%d:0:%llu:1\n",i+1,i+1,j+1,(intrc.lasttime-intrc.firsttime)); } } /* -- initialize state stacks -- */ statestk = (struct stkitem **) malloc ((intrc.numproc+1)*sizeof(struct stkitem *)); stkptr = (struct stkitem **) malloc ((intrc.numproc+1)*sizeof(struct stkitem *)); for (i=0; i<=intrc.numproc; i++) { stkptr[i] = statestk[i] = (struct stkitem *) malloc (STACKSIZE * sizeof(struct stkitem)); stkptr[i]->state = "IDLE"; stkptr[i]->tag = -99; } } PrintEventDescr (outfp); if (outFormat == pv) { /* print idle records */ for (i=0; i<=intrc.numproc; i++) { fprintf (outfp, "0 EXCHANGE ON CPUID %d DOWNTO IDLE -99 CLUSTER 1\n", i+1); } } /* ------------------------------------------------------------------------ */ /* -- re-open input trace -- */ /* ------------------------------------------------------------------------ */ if ( (intrc.fd = open (inFile, O_RDONLY | O_BINARY | LARGEFILE_OPTION)) < 0 ) { perror (inFile); exit (1); } else { intrc.erec = (TAU_EV *) NULL; intrc.next = (TAU_EV *) NULL; intrc.last = (TAU_EV *) NULL; intrc.overflows = 0; intrc.numrec = 1; erec = get_next_rec (&intrc); intrc.firsttime = event_GetTi(&intrc,erec,0); intrc.lasttime = event_GetTi(&intrc,erec,0); } /* ------------------------------------------------------------------------ */ /* -- initialize barrier check variables ---------------------------------- */ /* ------------------------------------------------------------------------ */ #ifdef __TAU__ numin = 0; numout = numproc; #endif /* __TAU__ */ barrin = (char *) malloc (intrc.numproc + 1); barrout = (char *) malloc (intrc.numproc + 1); for (i=0; i<=intrc.numproc; i++) { barrin[i] = FALSE; barrout[i] = TRUE; } /* ------------------------------------------------------------------------ */ /* -- convert trace file -------------------------------------------------- */ /* ------------------------------------------------------------------------ */ do { # ifdef __TAU__ /* -- check barrier order ----------------------------------------------- */ if ( event_GetEv(&intrc,erec,0) == TAU_BARRIER_ENTER ) { if ( !barrout[GetNodeId(erec)] ) { fprintf (stderr, "%s:%d: [%d] not yet out of barrier\n", intrc.name, intrc.numrec, GetNodeId(erec)); } if ( barrin[GetNodeId(erec)] ) { fprintf (stderr, "%s:%d: [%d] already in barrier\n", intrc.name, intrc.numrec, GetNodeId(erec)); } else { barrin[GetNodeId(erec)] = TRUE; numin++; if ( numin == numproc ) { if ( numout != numproc ) { fprintf (stderr, "%s:%d: barrier event count error\n", intrc.name, intrc.numrec); } numin = numout = 0; for (i=0; i<=intrc.numproc; i++) barrin[i] = barrout[i] = FALSE; } } } else if ( event_GetEv(&intrc,erec,0) == TAU_BARRIER_EXIT ) { if ( barrin[GetNodeId(erec)] ) { fprintf (stderr, "%s:%d: [%d] not yet in barrier\n", intrc.name, intrc.numrec, GetNodeId(erec)); } if ( barrout[GetNodeId(erec)] ) { fprintf (stderr, "%s:%d: [%d] already out of barrier\n", intrc.name, intrc.numrec, GetNodeId(erec)); } else { barrout[GetNodeId(erec)] = TRUE; numout++; } } # endif if ( outFormat == alog ) { i = GetEvent (event_GetEv(&intrc,erec,0)); fprintf (outfp, "%3d %3d 0 %10lld %d %10llu\n", i, /* event type */ GetNodeId(&intrc,erec), /* process id */ event_GetPar(&intrc,erec,0), /* integer parameter */ intrc.overflows, /* clock cycle */ event_GetTi(&intrc,erec,0)); /* timestamp */ } else if ( outFormat == SDDF ) { ptr = GetEventName (event_GetEv(&intrc,erec,0), &hasParam); if ( hasParam ) fprintf (outfp, "%s { %llu, %d, %d, %lld };;\n\n", ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0), event_GetPar(&intrc,erec,0)); else fprintf (outfp, "%s { %llu, %d, %d };;\n\n", ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0)); } else if( outFormat == paraver ){ x_int64 phRecv = 0; ev = GetEventStruct (event_GetEv(&intrc,erec,0)); if ((ev->tag != 0) || (dynamictrace)) { if( (ev->tag == SEND_EVENT) && pvComm ) { myid = GetNodeId(&intrc,erec) + 1; decodeParameter(event_GetPar(&intrc,erec,0), &otherid, &msglen, &msgtag, &comm); otherid = otherid+1; phRecv = GetMatchingRecvPRV(intrc, msgtag, GetNodeId(&intrc,erec), otherid -1 , msglen, &other_tid, &other_nodeid); #ifdef DEBUG printf ("\n\n%llu SENDMSG %d FROM %d TO %d LEN %d\n\n\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, msgtag, myid , otherid , msglen); #endif /* DEBUG */ /*Print the record in the form: RecordType(3)for Communication:SendNodeId:SendPTaskID: SendTaskID:SendThreadID:logicalSendTime:PhysicalSendTime: RecvNodeID:RecvPTaskID:RecvTaskID:RecvThreadID: :LogicalRecvTime:PhysicalRecvTime:MessageLength:MessageTag */ /* fprintf(outfp,"3:%d:1:%d:%d:%llu:%llu:%d:1:%d:%d:%llu:%llu:%lld:%lld\n",myid,myid,event_GetTid(&intrc,erec,0)+1,event_GetTi(&intrc,erec,0)-intrc.firsttime,event_GetTi(&intrc,erec,0) - intrc.firsttime,otherid,otherid,other_tid+1,phRecv,phRecv,msglen,msgtag); */ fprintf(outfp,"3:%d:1:%d:%d:%llu:%llu:%d:1:%d:%d:%llu:%llu:%d:%d\n", myid, myid, event_GetTid(&intrc,erec,0), (x_uint64)(event_GetTi(&intrc,erec,0) - intrc.firsttime), (x_uint64)(event_GetTi(&intrc,erec,0) - intrc.firsttime), otherid, otherid, other_tid+1, phRecv, phRecv, msglen, msgtag); } else if ( (ev->tag == RECV_EVENT ) && pvComm ) { /* receive message */ /* In dynamic trace the format for par is 31 ..... 24 23 ......16 15..............0 other type length So, mynode is the receiver and its in GetNodeId(&intrc,erec) RECVMSG BY FROM LEN */ /* extract the information from the parameter */ myid = GetNodeId(&intrc,erec)+1; decodeParameter(event_GetPar(&intrc,erec,0), &otherid, &msglen, &msgtag, &comm); otherid = otherid+1; if (GetMatchingSend(intrc, msgtag, GetNodeId(&intrc,erec), otherid - 1 , msglen, &other_tid, &other_nodeid)) { /* call was successful, we've the other_tid and other_nodeid */ #ifdef DEBUG printf("Calculated senderid = %d\n", otherid); #endif /* DEBUG */ } #ifdef DEBUG printf ("%llu RECVMSG %d BY %d FROM %d LEN %d\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, msgtag, myid , otherid , msglen); #endif /* DEBUG */ } else if (( ev->tag == -9 ) || ( event_GetPar(&intrc,erec,0) == -1)) { /* In dynamic tracing, 1/-1 par values are for Entry/Exit resp. */ /* exit state */ /* PARVis needs time values relative to the start of the program! */ stkptr[GetNodeId(&intrc,erec)]--; if ( stkptr[GetNodeId(&intrc,erec)] < statestk[GetNodeId(&intrc,erec)] ) { fprintf (stderr, "ERROR: stack underflow on node %d\n", GetNodeId(&intrc,erec)); fprintf (stderr, " event %s at %llu\n", ev->name, event_GetTi(&intrc,erec,0)); exit (1); } /*Print the record in the form: RecordType(2)for event:NodeID:PTaskID:TaskID:ThreadID: :event time:eventType(5) for method entry/exit:event tag(to distinguish between events of the same type, 0 for exit and event_GetEv(&intrc,erec,0) for entry */ fprintf (outfp, "2:%d:1:%d:%d:%llu:5:0\n",(event_GetNid(&intrc,erec,0))+1,(event_GetNid(&intrc,erec,0))+1,event_GetTid(&intrc,erec,0)+1,event_GetTi(&intrc,erec,0)-intrc.firsttime); /*Upon exit of a method, write another record indicating entry into the previous method on the stack for that particular node and thread */ if(stkptr[GetNodeId(&intrc,erec)]->tag != -99) fprintf(outfp,"2:%d:1:%d:%d:%llu:5:%d\n",(event_GetNid(&intrc,erec,0))+1,(event_GetNid(&intrc,erec,0))+1,event_GetTid(&intrc,erec,0)+1,event_GetTi(&intrc,erec,0)-intrc.firsttime,stkptr[GetNodeId(&intrc,erec)]->tag); if(prvPCF[event_GetEv(&intrc,erec,0)-1] == 0){ fprintf(pcffp,"%d %s\n",event_GetEv(&intrc,erec,0),GetEventName(event_GetEv(&intrc,erec,0),&hasParam)); prvPCF[event_GetEv(&intrc,erec,0)-1] = 1; } } else if (event_GetPar(&intrc,erec,0) == 1) { /* enter new state */ stkptr[GetNodeId(&intrc,erec)]++; if ( stkptr[GetNodeId(&intrc,erec)] > (statestk[GetNodeId(&intrc,erec)] + STACKSIZE) ) { fprintf (stderr, "ERROR: stack overflow on node %d\n", GetNodeId(&intrc,erec)); fprintf (stderr, " event %s at %llu\n", ev->name, event_GetTi(&intrc,erec,0)); exit (1); } stkptr[GetNodeId(&intrc,erec)]->tag = event_GetEv(&intrc,erec,0); /*Print the record in the form: /RecordType(2)for event:NodeID:PTaskID:TaskID:ThreadID: :event time:eventType(5) for method entry/exit:event tag(to distinguish between events of the same type, 0 for exit and event_GetEv(&intrc,erec,0) for entry */ fprintf (outfp, "2:%d:1:%d:%d:%llu:5:%d\n",(event_GetNid(&intrc,erec,0))+1,(event_GetNid(&intrc,erec,0))+1,event_GetTid(&intrc,erec,0)+1,event_GetTi(&intrc,erec,0)-intrc.firsttime,event_GetEv(&intrc,erec,0)); if(prvPCF[event_GetEv(&intrc,erec,0)-1] == 0){ fprintf(pcffp,"%d %s\n",event_GetEv(&intrc,erec,0),GetEventName(event_GetEv(&intrc,erec,0),&hasParam)); prvPCF[event_GetEv(&intrc,erec,0)-1] = 1; } } } } else if ( outFormat == pv ) { ev = GetEventStruct (event_GetEv(&intrc,erec,0)); if ((ev!= 0) &&( ( ev->tag != 0 ) || (dynamictrace))) /* dynamic trace doesn't use tag*/ { if ( (ev->tag == SEND_EVENT) && pvComm ) { /* send message */ /* In dynamic trace the format for par is 31 ..... 24 23 ......16 15..............0 other type length So, mynode is the sender and its in GetNodeId(&intrc,erec) SENDMSG FROM TO LEN */ /* extract the information from the parameter */ myid = GetNodeId(&intrc,erec) + 1; decodeParameter(event_GetPar(&intrc,erec,0), &otherid, &msglen, &msgtag, &comm); otherid = otherid+1; if (threads) { if (GetMatchingRecv(intrc, msgtag, GetNodeId(&intrc,erec), otherid -1 , msglen, &other_tid, &other_nodeid)) { /* call was successful, we've the other_tid and other_nodeid */ otherid = offset[other_nodeid] + other_tid + 1; #ifdef DEBUG printf("Calculated otherid = %d\n", otherid); #endif /* DEBUG */ } else { /* call was unsuccessful, we couldn't locate a matching ipc call */ printf("Matching IPC call not found. Assumption in place...\n"); /* ASSUMPTION: Thread 4 in a node can comm with thread 4 on another node. True for MPI+JAVA. In future, do a matching algo. */ otherid = offset[otherid-1] + event_GetTid(&intrc,erec,0) + 1; /* THIS ABOVE IS TRUE ONLY WHEN SAME THREADS COMMUNICATE !! */ #ifdef DEBUG printf("ASSUMPTION: SAME THREADIDS ON DIFF NODES COMMUNICATE!!\n"); printf("SEND: OTHER %d, myid %d len %d tag %d: PAR: %lx\n", otherid, myid, msglen, msgtag, event_GetPar(&intrc,erec,0)); #endif /* DEBUG */ } } #ifdef DEBUG printf ("\n\n%llu SENDMSG %d FROM %d TO %d LEN %d\n\n\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, msgtag, myid , otherid , msglen); #endif /* DEBUG */ fprintf (outfp, "%llu SENDMSG %d FROM %d TO %d LEN %d\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, msgtag, myid , otherid , msglen); } else if ( (ev->tag == RECV_EVENT ) && pvComm ) { /* receive message */ /* In dynamic trace the format for par is 31 ..... 24 23 ......16 15..............0 other type length So, mynode is the receiver and its in GetNodeId(&intrc,erec) RECVMSG BY FROM LEN */ /* extract the information from the parameter */ myid = GetNodeId(&intrc,erec) + 1; decodeParameter(event_GetPar(&intrc,erec,0), &otherid, &msglen, &msgtag, &comm); otherid = otherid+1; if (threads) { if (GetMatchingSend(intrc, msgtag, GetNodeId(&intrc,erec), otherid - 1 , msglen, &other_tid, &other_nodeid)) { /* call was successful, we've the other_tid and other_nodeid */ otherid = offset[other_nodeid] + other_tid + 1; #ifdef DEBUG printf("Calculated senderid = %d\n", otherid); #endif /* DEBUG */ } else { /* call was unsuccessful, we couldn't locate a matching ipc call */ printf("Matching IPC call not found. Assumption in place...\n"); /* ASSUMPTION: Thread 4 in a node can comm with thread 4 on another node. True for MPI+JAVA. In future, do a matching algo. */ otherid = offset[otherid-1] + event_GetTid(&intrc,erec,0) + 1; /* THIS ABOVE IS TRUE ONLY WHEN SAME THREADS COMMUNICATE !! */ #ifdef DEBUG printf("ASSUMPTION: SAME THREADIDS ON DIFF NODES COMMUNICATE!!\n"); printf("RECV: OTHER %d, myid %d len %d tag %d: PAR: %lx\n", otherid, myid, msglen, msgtag, event_GetPar(&intrc,erec,0)); #endif /* DEBUG */ } } #ifdef DEBUG printf ("%llu RECVMSG %d BY %d FROM %d LEN %d\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, msgtag, myid , otherid , msglen); #endif /* DEBUG */ fprintf (outfp, "%llu RECVMSG %d BY %d FROM %d LEN %d\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, msgtag, myid , otherid , msglen); } else if (( ev->tag == -9 ) || ( event_GetPar(&intrc,erec,0) == -1)) { /* In dynamic tracing, 1/-1 par values are for Entry/Exit resp. */ /* exit state */ /* PARVis needs time values relative to the start of the program! */ stkptr[GetNodeId(&intrc,erec)]--; if ( stkptr[GetNodeId(&intrc,erec)] < statestk[GetNodeId(&intrc,erec)] ) { fprintf (stderr, "ERROR: stack underflow on node %d\n", GetNodeId(&intrc,erec)); fprintf (stderr, " event %s at %llu\n", ev->name, event_GetTi(&intrc,erec,0)); exit (1); } if ( pvCompact ) fprintf (outfp, "%llu EXCH %d 1 1 %s %d\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, GetNodeId(&intrc,erec)+1, stkptr[GetNodeId(&intrc,erec)]->state, stkptr[GetNodeId(&intrc,erec)]->tag); else fprintf (outfp, "%llu EXCHANGE ON CPUID %d UPTO %s %d CLUSTER 1\n", event_GetTi(&intrc,erec,0) - intrc.firsttime, GetNodeId(&intrc,erec)+1, stkptr[GetNodeId(&intrc,erec)]->state, stkptr[GetNodeId(&intrc,erec)]->tag); } else if (event_GetPar(&intrc,erec,0) == 1) { /* enter new state */ stkptr[GetNodeId(&intrc,erec)]++; if ( stkptr[GetNodeId(&intrc,erec)] > (statestk[GetNodeId(&intrc,erec)] + STACKSIZE) ) { fprintf (stderr, "ERROR: stack overflow on node %d\n", GetNodeId(&intrc,erec)); fprintf (stderr, " event %s at %llu\n", ev->name, event_GetTi(&intrc,erec,0)); exit (1); } if ( pvCompact ) fprintf (outfp, "%llu EXCH %d 1 1 %s %d\n", /*???event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec)+1, ev->state, ev->tag);*/ event_GetTi(&intrc,erec,0) - intrc.firsttime, GetNodeId(&intrc,erec)+1, ev->state, ev->no); else fprintf (outfp, "%llu EXCHANGE ON CPUID %d DOWNTO %s %d CLUSTER 1\n", /*???event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec)+1, ev->state, ev->tag);*/ event_GetTi(&intrc,erec,0) - intrc.firsttime, GetNodeId(&intrc,erec)+1, ev->state, ev->no); stkptr[GetNodeId(&intrc,erec)]->state = ev->state; /*???stkptr[GetNodeId(&intrc,erec)]->tag = ev->tag;*/ stkptr[GetNodeId(&intrc,erec)]->tag = ev->no; } } } else if ( outFormat == dump ) { ptr = GetEventName (event_GetEv(&intrc,erec,0), &hasParam); if ( hasParam ) { if (IsDoubleParam(event_GetEv(&intrc,erec,0))) { /* user events parameter is a double */ #ifdef TAU_WINDOWS fprintf (outfp, "%5ld %30.30s %12I64u %6d %6d %12G\n", intrc.numrec, ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0), event_GetPar(&intrc,erec,0)); #else fprintf (outfp, "%5ld %30.30s %12llu %6d %6d %12G\n", intrc.numrec, ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0), event_GetPar(&intrc,erec,0)); #endif } else { #ifdef TAU_WINDOWS fprintf (outfp, "%5ld %30.30s %12I64u %6d %6d %12I64d\n", intrc.numrec, ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0), event_GetPar(&intrc,erec,0)); #else fprintf (outfp, "%5ld %30.30s %12llu %6d %6d %12lld\n", intrc.numrec, ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0), event_GetPar(&intrc,erec,0)); #endif } } else { #ifdef TAU_WINDOWS fprintf (outfp, "%5ld %30.30s %12I64u %6d %6d\n", intrc.numrec, ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0)); #else fprintf (outfp, "%5ld %30.30s %12llu %6d %6d\n", intrc.numrec, ptr, event_GetTi(&intrc,erec,0), GetNodeId(&intrc,erec), event_GetTid(&intrc,erec,0)); #endif /* Changed 12lu to 12llu for unsigned long long time */ } } if ( (erec = get_next_rec (&intrc)) == NULL ) break; else { intrc.numrec++; /* -- check clock overflow ---------------------------------------- */ if ( event_GetTi(&intrc,erec,0) < intrc.lasttime ) intrc.overflows++; intrc.lasttime = event_GetTi(&intrc,erec,0); } } while ( erec != NULL ); if ( outFormat == pv ) { for (i=0; i<=intrc.numproc; i++) { if ( stkptr[i] != statestk[i] ) { fprintf (stderr, "ERROR: stack not empty on node %d\n", i); exit (1); } } } fclose (outfp); exit (0); }