src/Profile/utils/tau_merge.c

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  * This program was prepared by PSI. 
00007  * All rights in the program are reserved by PSI.
00008  * Neither PSI nor the author(s)
00009  * makes any warranty, express or implied, or assumes any liability or
00010  * responsibility for the use of this software
00011  *
00012  * Visit http://www.acl.lanl.gov/POOMS for more details
00013  *
00014  ***************************************************************************/
00015 
00016 /*********************************************************************/
00017 /*                  pC++/Sage++  Copyright (C) 1994                  */
00018 /*  Indiana University  University of Oregon  University of Rennes   */
00019 /*********************************************************************/
00020 
00021 /*
00022  * pcxx_merge.c: merge local traces 
00023  *
00024  * (c) 1994 Jerry Manic Saftware
00025  *
00026  * Version 3.0
00027  */
00028 
00029 # include <stdio.h>
00030 # include <stdlib.h>
00031 # include <sys/types.h>
00032 # include <fcntl.h>
00033 # include <unistd.h>
00034 
00035 #ifndef NeXT
00036 # include <unistd.h>
00037 #endif
00038 
00039 # include <string.h>
00040 
00041 # define TRACING_ON
00042 # define PCXX_EVENT_SRC
00043 
00044 # ifdef __PCXX__
00045 #   include "Profile/pcxx_events_def.h"
00046 # else
00047 #   include "Profile/pcxx_events.h"
00048 # endif
00049 # include "Profile/pcxx_ansi.h"
00050 
00051 # ifndef TRUE
00052 #   define FALSE  0
00053 #   define TRUE   1
00054 # endif
00055 
00056 # define F_EXISTS    0
00057 
00058 # define CONTLEN  (sizeof(PCXX_EV) - sizeof(long int))
00059 
00060 # define STDOUT 1
00061 
00062 /* -- buffer sizes ------------------ */
00063 # define INMAX    BUFSIZ   /* records */
00064 # define OUTMAX   BUFSIZ   /* chars   */
00065 
00066 int dynamic = TRUE ; /* by default events.<node>.edf files exist */
00067 extern "C" {
00068   int open_edf_file(char *prefix, int nodeid);
00069   int parse_edf_file(int node);
00070   int store_merged_edffile(char *filename);
00071   int GID(int node, long localEventId); 
00072 }
00073 
00074 
00075 static struct trcdescr
00076 {
00077   int     fd;              /* -- input file descriptor                     -- */
00078   char   *name;            /* -- corresponding file name                   -- */
00079   int     nid;             /* -- corresponding PTX PID                     -- */
00080   int     overflows;       /* -- clock overflows in that trace             -- */
00081   int     contlen;         /* -- length of continuation event buffer       -- */
00082   long    numrec;          /* -- number of event records already processed -- */
00083   unsigned long lasttime;  /* -- timestamp of previous event record        -- */
00084   unsigned long offset;    /* -- offset of timestamp                       -- */
00085 
00086   PCXX_EV  *buffer;    /* -- input buffer                              -- */
00087   PCXX_EV  *erec;      /* -- current event record                      -- */
00088   PCXX_EV  *next;      /* -- next available event record in buffer     -- */
00089   PCXX_EV  *last;      /* -- last event record in buffer               -- */
00090 } *trcdes;
00091 
00092 /* -------------------------------------------------------------------------- */
00093 /* -- input buffer handling                                                -- */
00094 /* -------------------------------------------------------------------------- */
00095 
00096 static PCXX_EV *get_next_rec(struct trcdescr *tdes)
00097 {
00098   long no;
00099 
00100   if ( (tdes->last == NULL) || (tdes->next > tdes->last) )
00101   {
00102     /* -- input buffer empty: read new records from file -------------------- */
00103     if ( (no = read (tdes->fd, tdes->buffer, INMAX * sizeof(PCXX_EV)))
00104          != (INMAX * sizeof(PCXX_EV)) )
00105     {
00106       if ( no == 0 )
00107       {
00108         /* -- no more event record: ----------------------------------------- */
00109         close (tdes->fd);
00110         tdes->fd = -1;
00111         return (NULL);
00112       }
00113       else if ( (no % sizeof(PCXX_EV)) != 0 )
00114       {
00115         /* -- read error: --------------------------------------------------- */
00116         fprintf (stderr, "%s: read error\n", tdes->name);
00117         exit (1);
00118       }
00119     }
00120 
00121     /* -- we got some event records ----------------------------------------- */
00122     tdes->next = tdes->buffer;
00123     tdes->last = tdes->buffer + (no / sizeof(PCXX_EV)) - 1;
00124   }
00125   return (tdes->erec = tdes->next++);
00126 }
00127 
00128 /* -------------------------------------------------------------------------- */
00129 /* -- Routines Output*: Simple output buffering                            -- */
00130 /* -------------------------------------------------------------------------- */
00131 
00132 static char  outbuffer[OUTMAX];
00133 static int   outidx = 0;
00134 static char *outptr = outbuffer;
00135 
00136 static void output_flush(int fd)
00137 {
00138   if ( outidx > 0 )
00139   {
00140     if ( write (fd, outbuffer, outidx) != outidx )
00141     {
00142       perror ("write output");
00143       exit (1);
00144     }
00145     outidx = 0;
00146     outptr = outbuffer;
00147   }
00148 }
00149 
00150 static void output(int fd, char *data, size_t l)
00151 {
00152   if ( outidx + l >= BUFSIZ )
00153   {
00154     /* not enough space for data in output buffer: flush buffer */
00155     output_flush (fd);
00156   }
00157 
00158   memcpy (outptr, data, l);
00159   outptr += l;
00160   outidx += l;
00161 }
00162 
00163 /* -------------------------------------------------------------------------- */
00164 /* -- FILE DESCRIPTOR HANDLING ---------------------------------------------- */
00165 /* -------------------------------------------------------------------------- */
00166 
00167 #include <sys/time.h>
00168 #include <sys/resource.h>
00169 
00170 int cannot_get_enough_fd(int need)
00171 {
00172 # if defined(__hpux) || defined(sun)
00173   /* -- system supports get/setrlimit (RLIMIT_NOFILE) -- */
00174   struct rlimit rlp;
00175 
00176   getrlimit (RLIMIT_NOFILE, &rlp);
00177   if ( rlp.rlim_max < need )
00178     return (TRUE);
00179   else if ( rlp.rlim_cur < need )
00180   {
00181     rlp.rlim_cur = need;
00182     setrlimit (RLIMIT_NOFILE, &rlp);
00183   }
00184   return (FALSE);
00185 # else
00186 #   if defined(_SEQUENT_) || defined(sequent)
00187       /* -- system provides get/setdtablesize -- */
00188       int max = getdtablesize();
00189       return ( (max < need) && (setdtablesize (need) != need) );
00190 #   else
00191       /* -- system provides only getdtablesize -- */
00192       int max = getdtablesize();
00193       return ( max < need );
00194 #   endif
00195 # endif
00196 }
00197 
00198 /* -------------------------------------------------------------------------- */
00199 /* -- PCXX_MERGE MAIN PROGRAM ----------------------------------------------- */
00200 /* -------------------------------------------------------------------------- */
00201 
00202 extern char *optarg;
00203 extern int   optind;
00204 
00205 int main(int argc, char *argv[])
00206 {
00207   int i, active, numtrc, source, outfd, errflag, first;
00208   int adjust, min_over, reassembly;
00209   unsigned long min_time, first_time;
00210   long numrec;
00211   char *trcfile;
00212   PCXX_EV *erec;
00213 # ifdef __ksr__
00214   int *sequence;
00215   int last_pthread, num_pthreads;
00216 # endif
00217 # if defined(__ksr__) || defined(__CM5__)
00218   unsigned long last_time;
00219 # endif
00220 
00221   numtrc     = 0;
00222   numrec     = 0;
00223   errflag    = FALSE;
00224   adjust     = FALSE;
00225   reassembly = TRUE;
00226   first_time = 0L;
00227 
00228   while ( (i = getopt (argc, argv, "ar")) != EOF )
00229   {
00230     switch ( i )
00231     {
00232       case 'a': /* -- adjust first time to zero -- */
00233                 adjust = TRUE;
00234                 break;
00235 
00236       case 'r': /* -- do not reassemble long events -- */
00237                 reassembly = FALSE;
00238                 break;
00239 
00240       default : /* -- ERROR -- */
00241                 errflag = TRUE;
00242                 break;
00243     }
00244   }
00245 
00246   /* -- check whether enough file descriptors available: -------------------- */
00247   /* -- max-file-descriptors - 4 (stdin, stdout, stderr, output trace) ------ */
00248   active = argc - optind - 1;
00249   if ( cannot_get_enough_fd (active + 4) )
00250   {
00251       fprintf (stderr, "%s: too many input traces:\n", argv[0]);
00252       fprintf (stderr, "  1. merge half of the input traces\n");
00253       fprintf (stderr, "  2. merge other half and output of step 1\n");
00254       exit (1);
00255   }
00256   trcdes = (struct trcdescr *) malloc (active * sizeof(struct trcdescr));
00257 
00258   for (i=optind; i<argc-1; i++)
00259   {
00260     /* -- open input trace -------------------------------------------------- */
00261     if ( (trcdes[numtrc].fd = open (argv[i], O_RDONLY)) < 0 )
00262     {
00263       perror (argv[i]);
00264       errflag = TRUE;
00265     }
00266     else
00267     {
00268       trcdes[numtrc].name      = argv[i];
00269       trcdes[numtrc].buffer    = (PCXX_EV *) malloc (INMAX * sizeof(PCXX_EV));
00270       trcdes[numtrc].erec      = NULL;
00271       trcdes[numtrc].next      = NULL;
00272       trcdes[numtrc].last      = NULL;
00273       trcdes[numtrc].overflows = 0;
00274 
00275       /* -- read first event record ----------------------------------------- */
00276       if ( (erec = get_next_rec (trcdes + numtrc)) == NULL )
00277       {
00278         /* -- no event record: ---------------------------------------------- */
00279         fprintf (stderr, "%s: warning: trace empty - ignored\n",
00280                  trcdes[numtrc].name);
00281         trcdes[numtrc].numrec = 0L;
00282         active--;
00283       }
00284 
00285       /* -- check first event record ---------------------------------------- */
00286       else if ( (erec->ev != PCXX_EV_INIT) && (erec->ev != PCXX_EV_INITM) )
00287       {
00288         fprintf (stderr, "%s: no valid event trace\n", trcdes[numtrc].name);
00289         exit (1);
00290       }
00291       else
00292       {
00293         if ( erec->nid > PCXX_MAXPROCS )
00294           fprintf (stderr,
00295            "%s: warning: node id %d too big for this machine (max. %d nodes)\n",
00296            trcdes[numtrc].name, erec->nid, PCXX_MAXPROCS);
00297 
00298         trcdes[numtrc].numrec = 1L;
00299         if ( erec->ev == PCXX_EV_INIT )
00300         {
00301           if (!dynamic) { /* for dynamic trace, don't change this to INITM */
00302             erec->ev = PCXX_EV_INITM;
00303           }
00304           trcdes[numtrc].nid = erec->nid;
00305         }
00306         else
00307           trcdes[numtrc].nid = -1;
00308 
00309         trcdes[numtrc].lasttime = erec->ti;
00310         trcdes[numtrc].offset   = 0L;
00311 
00312         if(dynamic)
00313         {
00314         /* parse edf file for this trace */
00315           open_edf_file("events", trcdes[numtrc].nid);
00316           parse_edf_file(trcdes[numtrc].nid);
00317         }
00318         numtrc++;
00319       }
00320     }
00321   }
00322   if (dynamic)
00323   {
00324     /* all edf files have been parsed now - store the final edf merged file */
00325     store_merged_edffile("tau.edf");
00326   }
00327 
00328   if ( (numtrc < 1) || errflag )
00329   {
00330     fprintf (stderr,
00331              "usage: %s [-a] [-r] inputtraces* (outputtrace|-)\n", argv[0]);
00332     fprintf(stderr,
00333     "Note: %s assumes edf files are named events.<nodeid>.edf and \n", argv[0]);
00334     fprintf(stderr,"      generates a merged edf file tau.edf\n");
00335 
00336     exit (1);
00337   }
00338 
00339   /* -- output trace file --------------------------------------------------- */
00340   if ( strcmp ((argv[argc-1]), "-") == 0 )
00341   {
00342     outfd = STDOUT;
00343   }
00344   else
00345   {
00346     trcfile = (char *) malloc ((strlen(argv[argc-1])+5) * sizeof(char));
00347     if ( strcmp ((argv[argc-1])+strlen(argv[argc-1])-4, ".trc") == 0 )
00348       strcpy (trcfile, argv[argc-1]);
00349     else
00350       sprintf (trcfile, "%s.trc", argv[argc-1]);
00351 
00352     if ( access (trcfile, F_EXISTS) == 0 && isatty(2) )
00353     {
00354       fprintf (stderr, "%s exists; override [y]? ", trcfile);
00355       if ( getchar() == 'n' ) exit (1);
00356     }
00357     if ( (outfd = open (trcfile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0 )
00358     {
00359       perror (trcfile);
00360       exit (1);
00361     }
00362   }
00363 
00364 # if defined(__ksr__) && defined(__PCXX__)
00365   /* ------------------------------------------------------------------------ */
00366   /* -- determine clock offset for KSR-1 ------------------------------------ */
00367   /* -- NB: really need a better algorithm here ----------------------------- */
00368   /* ------------------------------------------------------------------------ */
00369 # define timestamp(i) \
00370                      (trcdes[sequence[i]].erec->ti + trcdes[sequence[i]].offset)
00371 # define STEP 1
00372 
00373   sequence     = (int *) malloc (numtrc * sizeof(int));
00374   last_time    = 0L;
00375   num_pthreads = numtrc;
00376   last_pthread = numtrc - 1;
00377 
00378   do
00379   {
00380     /* -- search for next "in_barrier" event in each trace and -------------- */
00381     /* -- store sequence number --------------------------------------------- */
00382     for (i=0; i<numtrc; i++)
00383     {
00384       if ( trcdes[i].nid == (PCXX_MAXPROCS-1) )  /* master */
00385       {
00386         num_pthreads = numtrc - 1;
00387         last_pthread = numtrc - 2;
00388       }
00389       else
00390       {
00391         do
00392         {
00393           erec = get_next_rec (trcdes + i);
00394         }
00395         while ( (erec != NULL) && (erec->ev != PCXX_IN_BARRIER) );
00396 
00397         if ( erec == NULL )
00398           break;
00399         else
00400           sequence[erec->par] = i;
00401       }
00402     }
00403 
00404     if ( erec != NULL )
00405     {
00406       /* -- the first at this barrier must at least arrived later than the -- */
00407       /* -- last at the last barrier ---------------------------------------- */
00408       if ( timestamp(0) <= last_time )
00409       {
00410         trcdes[sequence[0]].offset += last_time - timestamp(0) + STEP;
00411       }
00412 
00413       for (i=1; i<num_pthreads; i++)
00414       {
00415         if ( timestamp(i) <= timestamp(i-1) )
00416         {
00417           trcdes[sequence[i]].offset += timestamp(i-1) - timestamp(i) + STEP;
00418         }
00419       }
00420       last_time = timestamp(last_pthread);
00421     }
00422   }
00423   while ( erec != NULL );
00424 
00425   /* -- only on the first worker pthread trace we should run into EndOfTrace  */
00426   /* -- This is normally trace 0 unless trace 0 is the master pthread trace - */
00427   if ( i > (0 + (trcdes[0].nid == (PCXX_MAXPROCS - 1))) )
00428   {
00429     fprintf (stderr, "%s: missing barrier\n", trcdes[i].name);
00430     exit (1);
00431   }
00432 
00433   /* -- report offset found and re-open/re-initialize all traces ------------ */
00434   for (i=0; i<numtrc; i++)
00435   {
00436     if ( trcdes[i].offset )
00437       printf ("%s: offset %ld\n", trcdes[i].name, trcdes[i].offset);
00438 
00439     /* -- if file was closed during the search for barriers, re-open it ----- */
00440     if ( trcdes[i].fd = -1 )
00441     {
00442       if ( (trcdes[i].fd = open (trcdes[i].name, O_RDONLY)) < 0 )
00443       {
00444         perror (argv[i]);
00445         exit (1);
00446       }
00447     }
00448     /* -- otherwise reset file offset --------------------------------------- */
00449     else if ( lseek (trcdes[i].fd, 0, SEEK_SET) == -1 )
00450     {
00451       fprintf (stderr, "%s: cannot reset trace\n", trcdes[i].name);
00452       exit (1);
00453     }
00454     trcdes[i].erec = NULL;
00455     trcdes[i].next = NULL;
00456     trcdes[i].last = NULL;
00457 
00458     erec = get_next_rec (trcdes + i);
00459     trcdes[i].numrec = 1L;
00460     if ( erec->ev == PCXX_EV_INIT )
00461     {
00462       if (!dynamic) { /* don't change this for dynamic */
00463         erec->ev = PCXX_EV_INITM;
00464       }
00465       trcdes[i].nid = erec->nid;
00466     }
00467     else
00468       trcdes[i].nid = -1;
00469 
00470     trcdes[i].lasttime = erec->ti = erec->ti + trcdes[i].offset;
00471   }
00472   printf ("\n");
00473 # else
00474 #   if defined(__CM5__) && defined(__PCXX__)
00475     /* ---------------------------------------------------------------------- */
00476     /* -- determine clock offset for TMC CM-5 ------------------------------- */
00477     /* ---------------------------------------------------------------------- */
00478 
00479     /* -- search for sync marker in all traces ------------------------------ */
00480     /* -- and determine highest clock value --------------------------------- */
00481     last_time = 0L;
00482     for (i=0; i<numtrc; i++)
00483     {
00484       do
00485       {
00486         erec = get_next_rec (trcdes + i);
00487       }
00488       while ( (erec != NULL) && (erec->ev != PCXX_SYNC_MARK) );
00489 
00490       if ( erec == NULL )
00491       {
00492         fprintf (stderr, "%s: cannot find sync marker\n", trcdes[i].name);
00493         exit (1);
00494       }
00495 
00496       if ( erec->ti > last_time ) last_time = erec->ti;
00497     }
00498 
00499     /* -- compute and report offset found and re-initialize all traces ------ */
00500     for (i=0; i<numtrc; i++)
00501     {
00502       trcdes[i].offset = last_time - trcdes[i].erec->ti;
00503       printf ("%s: offset %ld\n", trcdes[i].name, trcdes[i].offset);
00504 
00505       /* -- reset file offset ----------------------------------------------- */
00506       if ( lseek (trcdes[i].fd, 0, SEEK_SET) == -1 )
00507       {
00508         fprintf (stderr, "%s: cannot reset trace\n", trcdes[i].name);
00509         exit (1);
00510       }
00511       trcdes[i].erec = NULL;
00512       trcdes[i].next = NULL;
00513       trcdes[i].last = NULL;
00514 
00515       erec = get_next_rec (trcdes + i);
00516       trcdes[i].numrec = 1L;
00517       if ( erec->ev == PCXX_EV_INIT )
00518       {
00519         erec->ev = PCXX_EV_INITM;
00520         trcdes[i].nid = erec->nid;
00521       }
00522       else
00523         trcdes[i].nid = -1;
00524 
00525       trcdes[i].lasttime = erec->ti = erec->ti + trcdes[i].offset;
00526     }
00527     printf ("\n");
00528 #   endif
00529 # endif
00530 
00531   /* ------------------------------------------------------------------------ */
00532   /* -- merge files --------------------------------------------------------- */
00533   /* ------------------------------------------------------------------------ */
00534   source = 0;
00535 
00536   do
00537   {
00538     /* -- compute minimum of all timestamps and store the index of the ------ */
00539     /* -- corresponding trace in source ------------------------------------- */
00540     first = TRUE;
00541     for (i=0; i<numtrc; i++)
00542     {
00543       if ( trcdes[i].fd != -1 )
00544       {
00545         if ( first )
00546         {
00547           min_time = trcdes[i].lasttime;
00548           min_over = trcdes[i].overflows;
00549           source = i;
00550           first  = FALSE;
00551         }
00552         else if ( trcdes[i].overflows < min_over )
00553         {
00554           min_time = trcdes[i].lasttime;
00555           min_over = trcdes[i].overflows;
00556           source = i;
00557         }
00558         else if ( (trcdes[i].overflows == min_over) &&
00559                   (trcdes[i].lasttime < min_time) )
00560         {
00561           min_time = trcdes[i].lasttime;
00562           source = i;
00563         }
00564       }
00565     }
00566 
00567     if ( adjust )
00568     {
00569       if ( numrec == 0 ) first_time = trcdes[source].erec->ti;
00570       trcdes[source].erec->ti -= first_time;
00571     }
00572     /* -- correct event id to be global event id ---------------------------- */
00573 #ifdef DEBUG 
00574     printf("Before conv event %ld ", trcdes[source].erec->ev);
00575 #endif /* DEBUG */
00576 
00577     trcdes[source].erec->ev = GID(trcdes[source].nid, trcdes[source].erec->ev);
00578 
00579 #ifdef DEBUG
00580     printf("Output: node %d event %d\n", source, trcdes[source].erec->ev);
00581 #endif /* DEBUG */
00582 
00583     output (outfd, (char *) trcdes[source].erec, sizeof(PCXX_EV));
00584     numrec++;
00585 
00586 # if defined(__ksr__) && defined(__PCXX__)
00587     erec = trcdes[source].erec;
00588     if ( erec->ev == PCXX_IN_BARRIER )
00589     {
00590       if ( ((last_pthread + 1) % num_pthreads) != erec->par )
00591         fprintf (stderr, "pcxx_Barrier sequence error at %ld (%d -> %d)\n",
00592                  erec->ti, last_pthread, erec->par);
00593       last_pthread = erec->par;
00594     }
00595 # endif
00596 
00597     /* -- get next event record(s) from same trace -------------------------- */
00598     do
00599     {
00600       if ( (erec = get_next_rec (trcdes + source)) == NULL )
00601       {
00602         active--;
00603         break;
00604       }
00605       else
00606       {
00607         trcdes[source].numrec++;
00608 
00609         if ( erec->ev == PCXX_EV_CONT_EVENT )
00610         {
00611           /* -- continuation event: output immediately ---------------------- */
00612           /* -- dynamic traces, correct event id to global event id --------- */
00613           erec->ev = GID(trcdes[source].nid, erec->ev);
00614           if ( reassembly )
00615           {
00616             output (outfd, ((char *) erec) + sizeof(short unsigned int),
00617                     trcdes[source].contlen < CONTLEN ?
00618                     trcdes[source].contlen : CONTLEN);
00619             trcdes[source].contlen -= CONTLEN;
00620           }
00621           else
00622             output (outfd, (char *) erec, sizeof(PCXX_EV));
00623           numrec++;
00624         }
00625         else
00626         {
00627           /* -- correct nid event field (only the first time) --------------- */
00628           if ( trcdes[source].nid != -1 ) erec->nid = trcdes[source].nid;
00629 
00630           /* -- correct clock ----------------------------------------------- */
00631           erec->ti += trcdes[source].offset;
00632 
00633           /* -- check clock overflow ---------------------------------------- */
00634           if ( erec->ti < trcdes[source].lasttime ) trcdes[source].overflows++;
00635           trcdes[source].lasttime = erec->ti;
00636 
00637           /* -- remember continuation event length -------------------------- */
00638           trcdes[source].contlen = erec->par;
00639 
00640         }
00641       }
00642     }
00643     while ( erec->ev == PCXX_EV_CONT_EVENT );
00644   }
00645   while ( active > 0 );
00646   for (i=0; i<numtrc; i++)
00647   { 
00648     if (outfd != STDOUT) 
00649     {
00650       fprintf (stderr, "%s: %ld records read.\n",
00651              trcdes[i].name, trcdes[i].numrec);
00652     }
00653   }
00654 
00655   output_flush (outfd);
00656   close (outfd);
00657   exit (0);
00658 }
00659 
00660 /***************************************************************************
00661  * $RCSfile: addheaderfooter,v $   $Author: adelmann $
00662  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:17 $
00663  * IPPL_VERSION_ID: $Id: addheaderfooter,v 1.1.1.1 2003/01/23 07:40:17 adelmann Exp $ 
00664  ***************************************************************************/
00665 

Generated on Mon Jan 16 13:23:55 2006 for IPPL by  doxygen 1.4.6