src/Profile/utils/pprof.cpp

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 // -*- C++ -*-
00017 /***************************************************************************
00018  *
00019  * The IPPL Framework
00020  * 
00021  * This program was prepared by PSI. 
00022  * All rights in the program are reserved by PSI.
00023  * Neither PSI nor the author(s)
00024  * makes any warranty, express or implied, or assumes any liability or
00025  * responsibility for the use of this software
00026  *
00027  * Visit http://www.acl.lanl.gov/POOMS for more details
00028  *
00029  ***************************************************************************/
00030 
00031 /*********************************************************************/
00032 /*                  pC++/Sage++  Copyright (C) 1993,1995             */
00033 /*  Indiana University  University of Oregon  University of Rennes   */
00034 /*********************************************************************/
00035 
00036 
00037 /*
00038  * pprof.c : parallel profile data files printer
00039  * Modified by Sameer Shende (sameer@cs.uoregon.edu)
00040  * (c) 1993 Jerry Manic Saftware
00041  *
00042  * Version 1.0
00043  * Version 2.0  added collection profiling
00044  * Version 2.1  added summary printing
00045  * Version 2.2  added collection name and types
00046  * Version 2.3  machine-independent profile data file format
00047  * Version 2.4  racy support (dump format)
00048  * Version 2.5  switched to ASCII files to be really portable
00049  * Version 2.6  Added support for HPC+++ (n,c,t) , aggregates
00050  * Version 2.7  Added support for Dynamic profiling 
00051  * Version 2.8  Added no. of subroutines data 
00052  */
00053 
00054 # include <stdio.h>
00055 # include <stdlib.h>
00056 
00057 # include <math.h>
00058 # include <errno.h>
00059 # include <string.h>
00060 # include <iostream.h>
00061 # include <stdlib.h>
00062 # include <unistd.h>
00063 # include <string.h>
00064 # include <fcntl.h>
00065 # include <map.h>
00066 
00067 #ifdef IPPL_TFLOP
00068 extern "C" int getopt(int, char *const *, const char *);
00069 extern char *optarg;
00070 extern int optind, opterr, optopt;
00071 #endif
00072 
00073 
00074 
00075 # ifndef TRUE
00076 #   define FALSE 0
00077 #   define TRUE  1
00078 # endif
00079 
00080 # if defined(ultrix) || defined(sequent) || defined(butterfly)
00081 double fmod (double x, double y)
00082 {
00083   return ( x - floor(x/y) * y );
00084 }
00085 # endif
00086 
00087 static struct p_func_descr {
00088 #ifdef USE_LONG
00089     long     numcalls;
00090     long     numsubrs;
00091 #else // DEFAULT double 
00092     double     numcalls;
00093     double     numsubrs;
00094 #endif // USE_LONG
00095     double  usec;
00096     double  cumusec;
00097     double  stddeviation;
00098 } *p_func_list = 0;    /* -- function profile data -- */
00099 
00100 static struct p_prof_elem {
00101     char   *name;
00102     int     tag;
00103 #ifdef USE_LONG
00104     long     numcalls;
00105     long     numsubrs;
00106 #else // DEFAULT double 
00107     double     numcalls;
00108     double     numsubrs;
00109 #endif //USE_LONG 
00110     double  usec;
00111     double  cumusec;
00112     double  stddeviation;
00113 } *p_prof_tbl  = 0,    /* -- function profile data table -- */
00114   *p_min_tbl = 0,      /* -- minimal summary function profile data table -- */
00115   *p_max_tbl = 0,      /* -- maximal summary function profile data table -- */
00116   *p_total_tbl = 0;    /* -- summary function profile data table -- */
00117 
00118 /* MIMD extension to identify top level function in each thread */
00119 int top_level_function; /* id for the top level function */
00120 double max_thread_cumusec = 0.0; 
00121 static struct p_coll_descr {
00122     int numelem;
00123     int dim;
00124     int size;
00125     int localacs;
00126     int remoteacs;
00127     char *collname;
00128     char *elemname;
00129     char *varname;
00130 } *p_coll_list = 0,    /* -- collection profile data table -- */
00131   *p_coll_tbl  = 0;    /* -- summary collection profile data table -- */
00132 
00133 #define MAX_COUNTERS  1024      /* -- HPC++ object profiling */
00134 #define SIZE_OF_LINE  64*1024   /* Big line to accomodate long function names */
00135 #define SIZE_OF_FILENAME 1024   /* Include full path. */
00136 
00137 static struct p_aggr_descr {
00138     int numelem;
00139     int dim;
00140     int size;
00141     long counters[MAX_COUNTERS];
00142     long total_events; /* sum of counters */
00143     char *container_name;
00144     char *container_type;
00145     char *var_name;
00146 } *p_aggr_list = 0,    /* -- aggregate profile data table -- */
00147   *p_aggr_tbl  = 0;    /* -- summary aggregate profile data table -- */
00148 
00149 static int numfunc;          /* -- number of functions   -- */
00150 static int filledDBThr, filledDBCtx = 0;     /* flag  for iterating over no,ctx,thr */
00151 static char *depfile;        /* -- corresponding .dep file -- */
00152 static char proffile[256];   /* -- profile data file     -- */
00153 static char **funcnamebuf;   /* -- function name table   -- */
00154 static int *functagbuf;      /* -- function tag table    -- */
00155 static int numcoll;          /* -- number of collections -- */
00156 static char **eventnamebuf = 0;  /* -- event name table     -- */
00157 static int numevents;         /* -- total counters used  -- */
00158 static int numaggr;          /* -- number of aggregates  -- */
00159 static double total_total;   /* -- total time overall    -- */
00160 static double min_total;
00161 static double max_total;
00162 static int nodeprint = TRUE;
00163 static int dump = FALSE;
00164 static int dumpminmax = FALSE;
00165 static int list = FALSE;
00166 static char lbuf[256];        /* -- temporary line buffer for reads -- */
00167 static char sbuf[128];        /* -- temporary string buffer -- */
00168 static int  hpcxx_flag = FALSE;
00169 static int  hwcounters = false;
00170 static int  profilestats = false; /* for SumExclSqr */
00171 static int  files_processed = 0; /* -- used for printing summary -- */
00172 
00173 /************** Function Declarations *********************************/
00174 
00175 int FunctionSummaryInfo(int no, int ctx, int thr, int max); 
00176 static char *strsave (const char *s); /* defined later */
00177 static int MsecCmp (const void *left, const void *right);
00178 static int CumMsecCmp (const void *left, const void *right);
00179 static int StdDevCmp (const void *left, const void *right);
00180 static int CallCmp (const void *left, const void *right);
00181 static void DumpFuncTab (struct p_prof_elem *tab, char *id_str, double total,
00182                          int max, char *order); 
00183 static void PrintFuncTab (struct p_prof_elem *tab, double total, int max);
00184 /**************** static var ******************************************/
00185 static int (* compar)(const void *, const void *) = CumMsecCmp;
00186 /********************** Dynamic Profiling Data Structures **************/
00187 
00188 struct ltstr
00189 {
00190   bool operator()(const char* s1, const char* s2) const
00191   {
00192     return strcmp(s1, s2) < 0;
00193   }
00194 };
00195 
00196 class FunctionData {
00197   public :
00198 #ifdef USE_LONG 
00199     long numcalls;
00200     long numsubrs;
00201 #else // DEFAULT double 
00202     double     numcalls;
00203     double     numsubrs;
00204 #endif // USE_LONG
00205     double excl;
00206     double incl;
00207     double stddeviation;
00208 #ifdef USE_LONG 
00209   FunctionData(long nc, long ns, double ex, double in, double sigma) 
00210     : numcalls(nc), numsubrs(ns),  excl(ex), incl(in), stddeviation(sigma) { }
00211 #else // DEFAULT double
00212   FunctionData(double nc, double ns, double ex, double in, double sigma) 
00213     : numcalls(nc), numsubrs(ns),  excl(ex), incl(in), stddeviation(sigma) { }
00214 #endif // USE_LONG 
00215   FunctionData() {
00216     numcalls = numsubrs = 0;
00217     excl = incl = stddeviation = 0;
00218   }
00219   FunctionData(const FunctionData& X) {
00220     numcalls = X.numcalls;
00221     numsubrs = X.numsubrs;
00222     excl  = X.excl;
00223     incl  = X.incl;
00224     stddeviation = X.stddeviation; 
00225   }
00226   FunctionData& operator= (const FunctionData& X) {
00227     numcalls = X.numcalls;
00228     numsubrs = X.numsubrs;
00229     excl = X.excl;
00230     incl = X.incl;
00231     stddeviation = X.stddeviation;
00232     return *this;
00233   }
00234   FunctionData& operator+= (const FunctionData& X) {
00235     numcalls += X.numcalls;
00236     numsubrs += X.numsubrs;
00237     excl += X.excl;
00238     incl += X.incl;
00239     stddeviation += X.stddeviation;
00240     return *this;
00241   }
00242  ~FunctionData() { }
00243 };
00244 /* GLOBAL database of function names */
00245 map<const char*, FunctionData, ltstr> funcDB;
00246 
00247 bool IsDynamicProfiling(char *filename) 
00248 {
00249   FILE *fp;
00250   char error_msg[SIZE_OF_FILENAME], version[64];
00251   int numberOfFunctions;
00252  
00253   if ((fp = fopen(filename, "r")) == NULL) {
00254     sprintf(error_msg,"Error: Could not open %s",filename);
00255     perror(error_msg);
00256     return false;
00257   }
00258   if (fscanf(fp, "%d %s",&numberOfFunctions, version) == EOF) {
00259     printf("Error: fscanf returns EOF file %s", filename);
00260     return false;
00261   }
00262   fclose(fp); // thats all we wanted to read 
00263 
00264   if (strcmp(version,"templated_functions") == 0) { // correct version
00265     hwcounters = false; // Timing data is in the profile files  
00266     return true;
00267   }
00268   else  { 
00269     if (strcmp(version,"templated_functions_hw_counters") == 0) {
00270       hwcounters  = true; // Counters - do not use time string formatting   
00271       return true; // It is dynamic profiling   
00272     } 
00273     else // Neither  - static profiling 
00274       return false;
00275   }
00276 }
00277 
00278   
00279 int InitFuncNameBuf(void)
00280 {
00281   int i;
00282   map<const char*, FunctionData, ltstr>::iterator it;
00283 
00284   funcnamebuf = (char **) malloc (numfunc * sizeof(char *));
00285   if (funcnamebuf == NULL) 
00286   {  
00287     perror("Error: Out of Memory : malloc returns NULL ");
00288     exit (1);
00289   }
00290   functagbuf  = (int *) malloc (numfunc * sizeof(int));
00291   if (functagbuf == NULL) 
00292   {  
00293     perror("Error: Out of Memory : malloc returns NULL ");
00294     exit (1);
00295   }
00296 
00297   for(it=funcDB.begin(), i = 0; it!=funcDB.end(); it++, i++)
00298   {
00299     funcnamebuf[i] = strsave((*it).first);
00300     functagbuf[i]  = i; /* Default - give tags that are 0 to numfunc - 1 */
00301     /* This is because we don't have a dep file in dynamic profiling */
00302   }
00303 
00304   return TRUE;
00305 }
00306   
00307 
00308 
00309 int FillFunctionDB(int node, int ctx, int thr, char *prefix)
00310 {
00311   char line[SIZE_OF_LINE]; // In case function name is *really* long - templ. args
00312   char func[SIZE_OF_LINE]; // - do - 
00313   char version[64],filename[SIZE_OF_FILENAME]; // double check?
00314   int numberOfFunctions, i, j, k;
00315   char header[256], trailer[256]; // Format string 
00316   int hlen, tlen; 
00317 #ifdef USE_LONG 
00318   long numcalls,numsubrs,numinvocations;
00319 #else // DEFAULT double 
00320     double     numcalls;
00321     double     numsubrs;
00322     double     numinvocations; 
00323 #endif // USE_LONG
00324   double excl, incl, exclthiscall, inclthiscall, sumexclsqr;
00325   bool dontread = false;
00326   FILE *fp;
00327   char *functionName; //need a separate string otherwise it stores only one ptr.
00328   map<const char*, FunctionData, ltstr>::iterator it;
00329 
00330 
00331   
00332   sprintf(filename,"%s.%d.%d.%d",prefix, node, ctx, thr);
00333 
00334 #ifdef DEBUG
00335   printf("Inside FillFunctionDB : Filename %s\n",filename);
00336 #endif /* DEBUG */
00337 
00338   if ((fp = fopen(filename, "r")) == NULL) {
00339     /* comment this line later */
00340 #ifdef DEBUG /* In sweeping through n,c,t tree its ok if a file is not found */
00341     sprintf(line,"Error: Could not open file %s", filename);
00342     perror(line);
00343 #endif /* DEBUG */
00344     return 0;
00345   }
00346   
00347 #ifdef DEBUG 
00348   cout << "Inside FillFunctionDB  n " << node << " c " << ctx << " thr " << thr << endl;
00349 #endif /* DEBUG */
00350   filledDBThr++; /* Set flag to indicate that some work was done */
00351   filledDBCtx++; /* Set flag to indicate that some work was done */
00352   
00353   if (fgets(line, sizeof(line), fp) == NULL) { 
00354     perror("Error: fgets returns NULL ");
00355     return 0;
00356   }
00357   sscanf(line,"%d %s", &numberOfFunctions, version);
00358   // double check - just to be sure 
00359   if (strncmp(version,"templated_functions",strlen("templated_functions")) != 0 ) { 
00360    // Neither templated_functions nor templated_functions_hw_counters
00361     printf("Incorrect version in file %s : %s", filename, version);
00362     return 0;
00363   }
00364 
00365   // New Data format contains a string like 
00366   // "# Name Calls Subrs Excl Incl SumExclSqr ProfileCalls"
00367   if (fgets(line, sizeof(line), fp) == NULL) {
00368     perror("Error: fgets returns NULL in format string ");
00369     return 0;
00370   }
00371   if (line[0] == '#') { // new data format 
00372     sprintf(header,"# Name Calls Subrs Excl Incl ");
00373     hlen = strlen(header);
00374     if (strncmp(line, header, hlen) != 0) {
00375       printf("Error in reading Format String : Expected %s Got %s\n", 
00376         header, line);
00377       exit(1);
00378     } else { // Format string parsed correctly. See if PROFILE_STATS is on
00379       sprintf(trailer,"SumExclSqr ProfileCalls");
00380       tlen = strlen(trailer);
00381       if (strncmp(line+hlen, trailer, tlen) == 0) {
00382         profilestats = true;
00383       } else { // doesn't contain SumExclSqr 
00384         sprintf(trailer, "ProfileCalls");
00385         tlen = strlen(trailer);
00386         if (strncmp(line+hlen, trailer, tlen) == 0) {
00387           profilestats = false;
00388         } else { // neither matched! 
00389           printf("Error in reading Format String : Got %s\n", line);
00390           exit(1);
00391         } // trailer matches 
00392       } // doesn't contain SumExclSqr 
00393 #ifdef DEBUG
00394       printf("Format String correct ProfileStats is %d\n", profilestats);
00395 #endif /* DEBUG */ 
00396     } // Format String available  
00397   } // First char is '#'
00398   else { // Old data format! # is not there! 
00399     profilestats = false;
00400     dontread = true; //already read a data line - process that first!
00401   } // line[0] = '#' 
00402 
00403 
00404 
00405   for (i =0; i < numberOfFunctions; i++) {
00406     if((i == 0) && (dontread == true)) { //skip 
00407     } else { 
00408       if (fgets(line, SIZE_OF_LINE, fp) == NULL) {
00409         perror("Error in fgets: Cannot read function table");
00410         return 0;
00411       }
00412     }
00413     // line[0] has '"' - start loop from 1 to get the entire function name
00414     for (j=1; line[j] != '"'; j++) {
00415         func[j-1] = line[j];
00416     }
00417     func[j-1] = '\0'; // null terminate the string
00418     // At this point line[j] is '"' and the has a blank after that, so
00419     // line[j+1] corresponds to the beginning of other data.
00420     if (!profilestats) { // SumExclSqr is not there 
00421 #ifdef USE_LONG 
00422       sscanf(&line[j+1], "%ld %ld %lG %lG %ld", &numcalls, &numsubrs, &excl, &incl, &numinvocations);
00423 #else // DEFAULT double
00424       sscanf(&line[j+1], "%lG %lG %lG %lG %lG", &numcalls, &numsubrs, &excl, &incl, &numinvocations);
00425 #endif // USE_LONG 
00426     } else { // SumExclSqr is there.
00427 #ifdef USE_LONG 
00428       sscanf(&line[j+1], "%ld %ld %lG %lG %lG %ld", &numcalls, &numsubrs, &excl, &incl, &sumexclsqr, &numinvocations);
00429 #else // DEFAULT double
00430       sscanf(&line[j+1], "%lG %lG %lG %lG %lG %lG", &numcalls, &numsubrs, &excl, &incl, &sumexclsqr, &numinvocations);
00431 #endif // USE_LONG 
00432     } // profilestats 
00433 #ifdef DEBUG
00434     cout << "func = "<< func << endl;
00435     cout << "numcalls = "<< numcalls << " numsubrs = "<< numsubrs << " excl = "<< excl <<" incl = " << incl << " no profiled invocations " << numinvocations << endl;
00436 #endif /* DEBUG */
00437 
00438     functionName = new char[strlen(func)+1]; // create a new storage - STL req.
00439     strcpy(functionName,func);
00440 
00441     if ((it = funcDB.find((const char *)functionName)) != funcDB.end()) { 
00442 #ifdef DEBUG 
00443       cout << "Found the name " << functionName << endl;
00444 #endif /* DEBUG */
00445       delete functionName; // don't need this if its already there.
00446     }
00447     else 
00448       funcDB[(const char *)functionName] = FunctionData(); 
00449       // adds  a null record and creates the name key in the map
00450       // Note: don't delete functionName - STL needs it
00451         /* PROCESS NO. OF Invocations Profiled */
00452     for(k = 0; k < numinvocations; k++) {
00453       if(fgets(line,SIZE_OF_LINE,fp) == NULL) {
00454         perror("Error in fgets: Cannot read invocation data ");
00455         return 0;
00456       }
00457       /* use this data */
00458       sscanf(line, "%lG %lG", &exclthiscall, &inclthiscall);
00459 #ifdef DEBUG
00460       cout << "func = " << func << " ExclThisCall = " << exclthiscall << " InclThisCall = " << inclthiscall << endl;
00461 #endif /* DEBUG */
00462     }
00463   }
00464   fclose(fp);
00465   return 1;
00466 }
00467 
00468 /* to iterate over nodes, contexts and threads */
00469 int FillFunctionDBInContext(int node, int ctx, int thr, char *prefix)
00470 {
00471 #ifdef DEBUG
00472   cout << "FillFunctionDBInContext n" << node << " c " << ctx << " t " << thr << endl;
00473 #endif /* DEBUG */
00474   for(thr = 0,filledDBThr = 0; FillFunctionDB(node, ctx, thr, prefix); thr++);
00475   if (filledDBThr) /* did some work */
00476     return TRUE;
00477   else
00478     return FALSE;
00479 }
00480 
00481 int FillFunctionDBInNode (int node, int ctx, int thr, char *prefix) 
00482 {
00483 #ifdef DEBUG
00484   cout << "FillFunctionDBInNode n" << node << " c " << ctx << " t " << thr << endl;
00485 #endif /* DEBUG */
00486   for(ctx = 0, filledDBCtx = 0; FillFunctionDBInContext(node, ctx, thr, prefix); ctx ++);
00487   if (filledDBCtx) 
00488     return TRUE;
00489   else
00490     return FALSE;
00491   /* This allows for iteration over 0.0.0, 0.0.1, 0.1.0. 1.0.0 etc. */
00492 }
00493 
00494   
00495 int DumpFunctionNamesInDB(void) 
00496 { /* For debugging */
00497   map<const char*, FunctionData, ltstr>::iterator it;
00498   
00499   for(it=funcDB.begin(); it != funcDB.end(); it++) {
00500     cout <<(*it).first << endl; /* Just print the name */
00501   }
00502   return 1;
00503 }
00504 
00505 int DumpFtabFile(char *prefix)
00506 { /* Racy needs a .ftab file - since one is not available in dynamic profiling,
00507      we need to generate it here */
00508   FILE *fp;
00509   char filename[SIZE_OF_FILENAME], error_msg[SIZE_OF_FILENAME];
00510   int i;
00511   /* Since funcnamebuf and functagbuf have already been initialized, use them */
00512 
00513   sprintf(filename, "%s.ftab",prefix); /* "profile.ftab"  */
00514 
00515   /* create this file only if its not there */
00516   if ((fp = fopen(filename, "r")) != NULL) { /* its already there */
00517     fclose (fp);
00518     return 1;
00519   }
00520   if (errno == ENOENT) /* The file does not exist - create it! */
00521     fclose(fp); /* reopen in another mode */
00522  
00523   if ((fp = fopen(filename, "w+")) == NULL) {
00524     sprintf(error_msg, "Error : Could not create %s", filename);
00525     perror(error_msg);
00526     return 0;
00527   }
00528 
00529   fprintf(fp,"default.dep\n%d templated_functions\n",numfunc);
00530   for (i = 0; i < numfunc; i++) {
00531     fprintf(fp,"%d %s\n", functagbuf[i], funcnamebuf[i]);
00532   }
00533   fflush(fp);
00534   fclose (fp);
00535   return 1;
00536 }
00537 
00538 int ProcessFileDynamic(int node, int ctx, int thr, int max, char *prefix)
00539 {
00540   char line[SIZE_OF_LINE]; // In case function name is *really* long - templ. args
00541   char func[SIZE_OF_LINE]; // - do - 
00542   char version[64],filename[SIZE_OF_FILENAME]; // double check?
00543   int numberOfFunctions, i, j, k;
00544 #ifdef USE_LONG 
00545   long numcalls, numsubrs, numinvocations;
00546 #else // DEFAULT double
00547   double numcalls, numsubrs, numinvocations;
00548 #endif // USE_LONG 
00549   double excl, incl, exclthiscall, inclthiscall, sumexclsqr, stddev;
00550   bool dontread = false;
00551   FILE *fp;
00552   map<const char*, FunctionData, ltstr>::iterator it;
00553 
00554 
00555   sprintf(filename,"%s.%d.%d.%d",prefix, node, ctx, thr);
00556 
00557 
00558   if ((fp = fopen(filename, "r")) == NULL) {
00559     /* comment this line later */
00560 #ifdef DEBUG /* In sweeping through n,c,t tree its ok if a file is not found */
00561     sprintf(line,"Error: Could not open file %s", filename);
00562     perror(line);
00563 #endif /* DEBUG */
00564     return 0;
00565   }
00566   
00567 #ifdef DEBUG
00568   printf("Inside ProcessFileDynamic : Filename %s\n",filename);
00569 #endif /* DEBUG */
00570 
00571   filledDBThr++; /* Set flag to indicate that some work was done */
00572   filledDBCtx++; /* Set flag to indicate that some work was done */
00573 
00574   if (fgets(line, sizeof(line), fp) == NULL) {
00575     perror("Error: fgets returns NULL ");
00576     return 0;
00577   }
00578   sscanf(line,"%d %s", &numberOfFunctions, version);
00579   // double check - just to be sure
00580   if (strncmp(version,"templated_functions",strlen("templated_functions")) != 0 ) { 
00581    // Neither templated_functions nor templated_functions_hw_counters
00582     printf("Incorrect version in file %s : %s", filename, version);
00583     return 0;
00584   }
00585 
00586 
00587   
00588   // New Data format contains a string like 
00589   // "# Name Calls Subrs Excl Incl SumExclSqr ProfileCalls"
00590   if (fgets(line, sizeof(line), fp) == NULL) {
00591     perror("Error: fgets returns NULL in format string ");
00592     return 0;
00593   }
00594   if (line[0] != '#') { // Old data format without '#' 
00595     profilestats = false;
00596     dontread = true; // have already read a valid data line
00597   } 
00598   // We've already parsed the options correctly in FillFunctionDB
00599 
00600 
00601 
00602   /* Before reading the data, initialize the map for the function */
00603   for(it = funcDB.begin(); it != funcDB.end(); it++) {
00604     (*it).second = FunctionData(); /* initialized to null values */
00605   } /* This ensures that data from two files don't interfere */
00606   
00607   /* Main loop of reading the function information, line by line */
00608   for (i =0; i < numberOfFunctions; i++) {
00609     if ( (i==0) && (dontread == true)) { //skip 
00610     } else {
00611       if (fgets(line, SIZE_OF_LINE, fp) == NULL) {
00612         perror("Error in fgets: Cannot read function table");
00613         return 0;
00614       }
00615     }
00616     // line[0] has '"' - start loop from 1 to get the entire function name
00617     for (j=1; line[j] != '"'; j++) {
00618         func[j-1] = line[j];
00619     }
00620     func[j-1] = '\0'; // null terminate the string
00621     // At this point line[j] is '"' and the has a blank after that, so
00622     // line[j+1] corresponds to the beginning of other data.
00623 
00624     if (!profilestats) { // SumExclSqr is not there 
00625 #ifdef USE_LONG 
00626       sscanf(&line[j+1], "%ld %ld %lG %lG %ld", &numcalls, &numsubrs, &excl, &incl, &numinvocations);
00627 #else // DEFAULT double
00628       sscanf(&line[j+1], "%lG %lG %lG %lG %lG", &numcalls, &numsubrs, &excl, &incl, &numinvocations);
00629 #endif // USE_LONG 
00630       stddev = 0; // Not defined in this case 
00631     } else { // SumExclSqr is there.
00632 #ifdef USE_LONG 
00633       sscanf(&line[j+1], "%ld %ld %lG %lG %lG %ld", &numcalls, &numsubrs, &excl, &incl, &sumexclsqr, &numinvocations);
00634 #else // DEFAULT double
00635       sscanf(&line[j+1], "%lG %lG %lG %lG %lG %lG", &numcalls, &numsubrs, &excl, &incl, &sumexclsqr, &numinvocations);
00636 #endif // USE_LONG 
00637       // Calculate the standard deviation = sqrt((sumt^2)/N - mean^2)
00638       stddev = sqrt(fabs( (sumexclsqr/numcalls) - ((excl/numcalls) * (excl/numcalls))) );
00639 #ifdef DEBUG
00640       cout << "stddeviation = "<< stddev << " sumexclsqr = "<< sumexclsqr << " func : "<< " excl " << excl<< " calls " << numcalls << func<< endl; 
00641 #endif /* DEBUG */
00642     } // profilestats 
00643 
00644 #ifdef DEBUG
00645     cout << "func = "<< func << endl;
00646     cout << "numcalls = "<< numcalls <<" numsubrs = "<< numsubrs<< " excl = "<< excl <<" incl = " << incl << " num invocations profiled = " << numinvocations << endl;
00647 #endif /* DEBUG */
00648 
00649     if ((it = funcDB.find((const char *)func)) == funcDB.end()) {
00650       cout << "ERROR : In second pass ProcessFileDynamic didn't find name " << func << " in file "<< filename << endl;
00651       return 0;
00652     }
00653     funcDB[func] += FunctionData(numcalls, numsubrs, excl, incl, stddev);
00654     /* In case a function appears twice in the same file (templated function
00655     the user didn't specify exactly unique type - then add the data. Defaults
00656     to assignment as initialization cleans it up. */ 
00657         /* PROCESS NO. OF Invocations Profiled */
00658     for(k = 0; k < numinvocations; k++) {
00659       if(fgets(line,SIZE_OF_LINE,fp) == NULL) {
00660         perror("Error in fgets: Cannot read invocation data ");
00661         return 0;
00662       }
00663       /* use this data */
00664       sscanf(line, "%lG %lG", &exclthiscall, &inclthiscall);
00665 #ifdef DEBUG
00666       cout << "func = " << func << " ExclThisCall = " << exclthiscall << " InclThisCall = " << inclthiscall << endl;
00667 #endif /* DEBUG */
00668     }
00669   }
00670 
00671   p_func_list = (struct p_func_descr *) malloc(numfunc * sizeof(struct p_func_descr));
00672 
00673   /* fill up the p_func_list */
00674   for(it=funcDB.begin(), i = 0; it != funcDB.end(); it++, i++) {
00675     p_func_list[i].numcalls     = (*it).second.numcalls;
00676     p_func_list[i].numsubrs     = (*it).second.numsubrs;
00677     p_func_list[i].usec         = (*it).second.excl;
00678     p_func_list[i].cumusec      = (*it).second.incl;
00679     p_func_list[i].stddeviation = (*it).second.stddeviation;
00680 
00681     if (p_func_list[i].cumusec > max_thread_cumusec) {
00682         top_level_function = i; /* to find which is the top level function
00683         in this thread we find the function with the max cumusec */
00684         max_thread_cumusec = p_func_list[i].cumusec;
00685     }
00686 #ifdef DEBUG
00687 #ifdef USE_LONG 
00688     printf("Func Id %d name %s numcalls %ld numsubrs %ld usec %lG cumusec %lG\n",i, funcnamebuf[i],  p_func_list[i].numcalls, p_func_list[i].numsubrs, p_func_list[i].usec, p_func_list[i].cumusec);
00689 #else // DEFAULT double
00690     printf("Func Id %d name %s numcalls %lG numsubrs %lG usec %lG cumusec %lG\n",i, funcnamebuf[i],  p_func_list[i].numcalls, p_func_list[i].numsubrs, p_func_list[i].usec, p_func_list[i].cumusec);
00691 #endif // USE_LONG 
00692 #endif /* DEBUG */
00693   }
00694   /* -- read number of collections ------------------------------------------ */
00695   if ( fgets (line, 256, fp) == NULL ) {
00696     fprintf (stderr,
00697                   "invalid proftablefile: cannot read number of collections\n");
00698     exit (1);
00699   }
00700   sscanf(line, "%d %s", &numcoll, version);
00701   if (strcmp(version, "aggregates") == 0) /* Aggregates in dynamic profiling */
00702   { // WRITE CODE TO SUPPORT AGGREGATES HERE 
00703     if(numcoll) { 
00704     } // numcoll > 0 
00705   } // "aggregates" 
00706 
00707      
00708   fclose(fp);
00709 #ifdef DEBUG
00710   cout << "Closing file " << filename << endl;
00711 #endif /* DEBUG */
00712 
00713   // FUNCTION SUMMARY INFO 
00714   FunctionSummaryInfo(node, ctx, thr, max);
00715 
00716   return 1;
00717 
00718 }
00719 
00720 int FunctionSummaryInfo(int no, int ctx, int thr, int max) 
00721 { // Continuation of ProcessFileDynamic - just breaking up the code 
00722   int i, j;
00723   int active_counters=0;
00724   int numf;
00725   int numc;
00726   int numa;
00727   double total, ct;
00728   char ident_str[32];
00729 
00730 
00731   /* Globals used to initialize locals */
00732   numf = numfunc;
00733   numc = numa = numcoll; 
00734   hpcxx_flag = TRUE; // for n,c,t display
00735 
00736   /* -- initialize summary function profile data table ---------------------- */
00737   if ( !p_total_tbl ) {
00738     p_total_tbl = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
00739     p_min_tbl   = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
00740     p_max_tbl   = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
00741     for (i=0; i<numf; i++) {
00742       p_total_tbl[i].tag                = functagbuf[i];
00743       p_total_tbl[i].name               = funcnamebuf[i];
00744       p_total_tbl[i].usec               = 0.0;
00745       p_total_tbl[i].cumusec            = 0.0;
00746       p_total_tbl[i].numcalls           = 0;
00747       p_total_tbl[i].numsubrs           = 0;
00748       p_total_tbl[i].stddeviation       = 0;
00749 
00750       p_max_tbl[i].tag      = p_min_tbl[i].tag      = p_total_tbl[i].tag;
00751       p_max_tbl[i].name     = p_min_tbl[i].name     = p_total_tbl[i].name;
00752       p_max_tbl[i].usec     = p_min_tbl[i].usec     = p_func_list[i].usec;
00753       p_max_tbl[i].cumusec  = p_min_tbl[i].cumusec  = p_func_list[i].cumusec; 
00754       p_max_tbl[i].numcalls = p_min_tbl[i].numcalls = p_func_list[i].numcalls;
00755       p_max_tbl[i].numsubrs = p_min_tbl[i].numsubrs = p_func_list[i].numsubrs;
00756       p_max_tbl[i].stddeviation = p_min_tbl[i].stddeviation = p_func_list[i].stddeviation;
00757 #ifdef DEBUG
00758 #ifdef USE_LONG 
00759     printf(" Func %d, min_tbl[i].numcalls %ld min_tbl[i].numsubrs %ld usec %lG, cumusec %lG\n",
00760         i, p_min_tbl[i].numcalls, p_min_tbl[i].numsubrs, p_min_tbl[i].usec, p_min_tbl[i].cumusec);
00761 
00762     printf(" Func %d, max_tbl[i].numcalls %ld max_tbl[i].numsubrs %ld usec %lG, cumusec %lG\n",
00763         i, p_max_tbl[i].numcalls, p_max_tbl[i].numsubrs, p_max_tbl[i].usec, p_max_tbl[i].cumusec);
00764 #else // DEFAULT double
00765     printf(" Func %d, min_tbl[i].numcalls %lG min_tbl[i].numsubrs %lG usec %lG, cumusec %lG\n",
00766         i, p_min_tbl[i].numcalls, p_min_tbl[i].numsubrs, p_min_tbl[i].usec, p_min_tbl[i].cumusec);
00767 
00768     printf(" Func %d, max_tbl[i].numcalls %lG max_tbl[i].numsubrs %lG usec %lG, cumusec %lG\n",
00769         i, p_max_tbl[i].numcalls, p_max_tbl[i].numsubrs, p_max_tbl[i].usec, p_max_tbl[i].cumusec);
00770 #endif // USE_LONG 
00771 #endif /* DEBUG */
00772     }
00773     total_total = 0.0;
00774     /* old
00775     max_total = min_total = p_func_list[0].cumusec; 0 is not top level fn.
00776    */
00777     max_total = min_total = p_func_list[top_level_function].cumusec;
00778   }
00779 
00780   /* -- set function profile data table ------------------------------------- */
00781   /* -- and update summary function profile data table ---------------------- */
00782   p_prof_tbl = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
00783   for (i=0; i<numf; i++) {
00784     p_prof_tbl[i].tag   = p_total_tbl[i].tag;
00785     p_prof_tbl[i].name  = p_total_tbl[i].name;
00786     p_total_tbl[i].usec     += p_prof_tbl[i].usec     = p_func_list[i].usec;
00787     p_total_tbl[i].cumusec  += p_prof_tbl[i].cumusec  = p_func_list[i].cumusec;
00788     p_total_tbl[i].numcalls += p_prof_tbl[i].numcalls = p_func_list[i].numcalls;
00789     p_total_tbl[i].numsubrs += p_prof_tbl[i].numsubrs = p_func_list[i].numsubrs;
00790     p_total_tbl[i].stddeviation += p_prof_tbl[i].stddeviation = p_func_list[i].stddeviation;
00791 
00792     if ( p_min_tbl[i].usec     > p_func_list[i].usec )
00793       p_min_tbl[i].usec     = p_func_list[i].usec;
00794     if ( p_min_tbl[i].cumusec  > p_func_list[i].cumusec )
00795       p_min_tbl[i].cumusec  = p_func_list[i].cumusec;
00796     if ( p_min_tbl[i].numcalls > p_func_list[i].numcalls )
00797       p_min_tbl[i].numcalls = p_func_list[i].numcalls;
00798     if ( p_min_tbl[i].numsubrs > p_func_list[i].numsubrs )
00799       p_min_tbl[i].numsubrs = p_func_list[i].numsubrs;
00800     if ( p_min_tbl[i].stddeviation > p_func_list[i].stddeviation )
00801       p_min_tbl[i].stddeviation = p_func_list[i].stddeviation;
00802 
00803     if ( p_max_tbl[i].usec     < p_func_list[i].usec )
00804       p_max_tbl[i].usec     = p_func_list[i].usec;
00805 
00806     if ( p_max_tbl[i].cumusec  < p_func_list[i].cumusec )
00807       p_max_tbl[i].cumusec  = p_func_list[i].cumusec;
00808     if ( p_max_tbl[i].numcalls < p_func_list[i].numcalls )
00809       p_max_tbl[i].numcalls = p_func_list[i].numcalls;
00810     if ( p_max_tbl[i].numsubrs < p_func_list[i].numsubrs )
00811       p_max_tbl[i].numsubrs = p_func_list[i].numsubrs;
00812     if ( p_max_tbl[i].stddeviation < p_func_list[i].stddeviation )
00813       p_max_tbl[i].stddeviation = p_func_list[i].stddeviation;
00814   }
00815 #ifdef DEBUG
00816   for (i=0; i<numf; i++) {
00817 #ifdef USE_LONG 
00818     printf(" Func %d, min_tbl[i].numcalls %ld  numsubrs %ld usec %lG, cumusec %lG\n",
00819         i, p_min_tbl[i].numcalls, p_min_tbl[i].numsubrs, p_min_tbl[i].usec, p_min_tbl[i].cumusec);
00820 
00821     printf(" Func %d, max_tbl[i].numcalls %ld numsubrs %ld usec %lG, cumusec %lG\n",
00822         i, p_max_tbl[i].numcalls, p_max_tbl[i].numsubrs, p_max_tbl[i].usec, p_max_tbl[i].cumusec);
00823 #else // DEFAULT double
00824     printf(" Func %d, min_tbl[i].numcalls %lG  numsubrs %lG usec %lG, cumusec %lG\n",
00825         i, p_min_tbl[i].numcalls, p_min_tbl[i].numsubrs, p_min_tbl[i].usec, p_min_tbl[i].cumusec);
00826 
00827     printf(" Func %d, max_tbl[i].numcalls %lG numsubrs %lG usec %lG, cumusec %lG\n",
00828         i, p_max_tbl[i].numcalls, p_max_tbl[i].numsubrs, p_max_tbl[i].usec, p_max_tbl[i].cumusec);
00829 #endif // USE_LONG 
00830   }
00831 #endif /* DEBUG */
00832 
00833 
00834 #ifdef DEBUG
00835   printf("Top level function = %d in file %s\n", top_level_function, proffile);
00836 #endif /* DEBUG */
00837   /* -- get total runtime (time of "main" function (always function 0)) ----- */
00838   /* This is not true for all programs; new method -
00839      The top level function has max cumusec time for that thread (support
00840      for MIMD programs where top level fn is different for different threads
00841 */
00842   total_total += total = p_func_list[top_level_function].cumusec;
00843   if ( min_total > p_func_list[top_level_function].cumusec ) min_total = p_func_list[top_level_function].cumusec;
00844   if ( max_total < p_func_list[top_level_function].cumusec ) max_total = p_func_list[top_level_function].cumusec;
00845 
00846 #ifdef DEBUG
00847   printf("%s : total = %5.1f top level = %5.1f\n", proffile, total, max_thread_cumusec);
00848 #endif
00849   if (hpcxx_flag == FALSE)
00850   {
00851     sprintf(ident_str,"%d", no);
00852   }
00853   else  /* hpc++ */
00854   {
00855     sprintf(ident_str,"%d,%d,%d", no, ctx, thr);
00856   }
00857 
00858 
00859   /* -- print function profile data table ----------------------------------- */
00860   if ( nodeprint ) {
00861     if ( dump ) {
00862       qsort ((void *) p_prof_tbl, numf, sizeof(struct p_prof_elem), MsecCmp);
00863       DumpFuncTab (p_prof_tbl, ident_str, total, max, "excl");
00864       qsort ((void *) p_prof_tbl, numf, sizeof(struct p_prof_elem), CumMsecCmp);
00865       DumpFuncTab (p_prof_tbl, ident_str, total, max, "incl");
00866     }
00867     else {
00868       qsort ((void *) p_prof_tbl, numf, sizeof(struct p_prof_elem), compar);
00869       if (hpcxx_flag == FALSE)
00870         printf ("\nNODE %d: \n", no);
00871       else
00872       {
00873         printf ("\nNODE %d;", no);
00874         printf ("CONTEXT %d;", ctx);
00875         printf ("THREAD %d:\n", thr);
00876       }
00877 
00878       PrintFuncTab (p_prof_tbl, total, max);
00879     }
00880   }
00881 
00882   if ( numc ) {
00883     if ( hpcxx_flag == FALSE) { /* pc++ data format */
00884       if ( nodeprint ) {
00885         if ( ! dump ) {
00886           printf ("\n   local    remote  collection\n");
00887           printf (  "accesses  accesses  num   name\n");
00888         }
00889       }
00890       for (i=0; i<numc; i++) {
00891         if ( nodeprint ) {
00892           /* -- print collection profile data table --------------------------- */
00893           if ( dump ) {
00894             if ( ct = p_coll_list[i].localacs + p_coll_list[i].remoteacs ) {
00895               printf ("coll %d %d %d %4.2f %d %4.2f\n", no, i,
00896                      p_coll_list[i].localacs, p_coll_list[i].localacs/ct*100.0,
00897                      p_coll_list[i].remoteacs, p_coll_list[i].remoteacs/ct*100.0);
00898             }
00899             else {
00900               printf ("coll %d %d 0 0.0 0 0.0\n", no, i);
00901             }
00902           }
00903           else {
00904             printf ("%8d  %8d  %3d   %s\n",
00905               p_coll_list[i].localacs, p_coll_list[i].remoteacs,
00906               i, p_coll_list[i].varname);
00907           }
00908         }
00909  
00910         /* -- compute collection profile summary ------------------------------ */
00911         p_coll_tbl[i].localacs  += p_coll_list[i].localacs;
00912         p_coll_tbl[i].remoteacs += p_coll_list[i].remoteacs;
00913       }
00914     } /* hpcxx_flag == FALSE */
00915     else {
00916         /* print aggregate info */
00917 /*
00918       if ( nodeprint ) {
00919         if ( ! dump ) {
00920           printf ("\n   local    remote  collection\n");
00921           printf (  "accesses  accesses  num   name\n");
00922         }
00923       }
00924 */
00925       for (i=0; i<numa; i++) {
00926         if ( nodeprint ) {
00927           /* -- print aggregate profile data table --------------------------- */
00928           if ( dump ) {
00929             if ( p_aggr_list[i].total_events ) {
00930               active_counters = 0;
00931               for(j=0; j < MAX_COUNTERS; j++)
00932               {
00933                 if (p_aggr_list[i].counters[j]) active_counters++ ;
00934               }
00935               printf("aggregates %d,%d,%d %d %d ",no, ctx, thr, i, active_counters);
00936               /* and then the quads <eid, name, no, %val> */
00937               for (j = 0; j < MAX_COUNTERS; j++)
00938               {
00939                 /* print only those events that took place */
00940                 if ( p_aggr_list[i].counters[j])
00941                 {
00942                   if (eventnamebuf == NULL)
00943                   { /* print NULL */
00944                     printf("%d NULL %d %4.2f ", j,
00945                         p_aggr_list[i].counters[j],
00946         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
00947                   }
00948                   else
00949                   {
00950                     printf("%d %s %d %4.2f ", j, eventnamebuf[j],
00951                         p_aggr_list[i].counters[j],
00952         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
00953                   }
00954                 }
00955               } /* printed the j counters */
00956               printf("%s %s %s\n", p_aggr_list[i].container_name,
00957                 p_aggr_list[i].container_type, p_aggr_list[i].var_name);
00958             }
00959             else /* all counters are 0 */
00960             {
00961               printf("aggregates %d,%d,%d %d 0 NULL 0 0.0 %s %s %s\n",
00962                 no, ctx, thr, i, p_aggr_list[i].container_name,
00963                 p_aggr_list[i].container_type, p_aggr_list[i].var_name);
00964               /* node no ctx thr , eid 0 name NULL events 0 % 0.0 */
00965             }
00966           }
00967           else
00968           { /* not dump */
00969             printf("aggregates %s <%s> %s\n",p_aggr_list[i].container_name,
00970                         p_aggr_list[i].container_type, p_aggr_list[i].var_name);
00971             for(j = 0; j < MAX_COUNTERS; j++)
00972             {
00973               if(p_aggr_list[i].counters[j])
00974               {
00975                 if(eventnamebuf == NULL)
00976                 {
00977                   printf("Event id %d\t: %d %4.2f       percent\n",
00978                         j, p_aggr_list[i].counters[j],
00979         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
00980                 }
00981                 else
00982                 {
00983                   printf("Event id %d name %s\t: %d %4.2f percent\n",
00984                         j, eventnamebuf[j], p_aggr_list[i].counters[j],
00985         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
00986                 }
00987               }
00988             } /* printed all events */
00989           } /* not dump */
00990         } /* nodeprint */
00991         /* -- compute collection profile summary ------------------------------ */
00992         for (j = 0; j < MAX_COUNTERS; j++)
00993         {
00994           p_aggr_tbl[i].counters[j] += p_aggr_list[i].counters[j];
00995         }
00996         p_aggr_tbl[i].total_events += p_aggr_list[i].total_events;
00997       } /* for i */
00998     } /* hpcxx_flag == TRUE */
00999   } /* numc > 0 */
01000 
01001   free (p_coll_list);
01002   free (p_func_list);
01003   free (p_prof_tbl);
01004   free (p_aggr_list);
01005   files_processed ++; /* increment counter for hpc++ */
01006   return (TRUE);
01007 }
01008 
01009 int ProcessFileDynamicInContext(int node, int ctx, int thr, int maxfuncs, char *prefix)
01010 {
01011 #ifdef DEBUG
01012   cout << "ProcessFileDynamicInContext n " << node << " c " << ctx << " t " << thr << endl;
01013 #endif /* DEBUG */
01014   for (thr =0, filledDBThr = 0; ProcessFileDynamic(node, ctx, thr, maxfuncs, prefix); thr++);
01015   if (filledDBThr)
01016     return TRUE;
01017   else
01018     return FALSE; 
01019 
01020 }
01021 
01022 int ProcessFileDynamicInNode (int node, int ctx, int thr, int maxfuncs, char *prefix)
01023 {
01024 #ifdef DEBUG 
01025   cout << "ProcessFileDynamicInNode n "<< node << " c "<< ctx << " t "<< thr<< endl;
01026 #endif /* DEBUG */
01027   for(ctx=0, filledDBCtx = 0; ProcessFileDynamicInContext(node, ctx, thr, maxfuncs, prefix); ctx++);
01028   if (filledDBCtx)
01029     return TRUE;
01030   else
01031     return FALSE;
01032   /* Iterations over 0.0.0 0.0.1 0.1.0 1.0.0 etc. */
01033 }
01034 
01035 
01036 
01037 
01038 /******************** pC++ /HPC++ profiling code **************************/
01039 static char *strsave (const char *s)
01040 {
01041   char *r;
01042 
01043   if ( (r = (char *) malloc (strlen(s)+1)) == NULL ) {
01044     fprintf (stderr, "error: no more memory\n");
01045     exit (1);
01046   }
01047   strcpy (r, s);
01048   return r;
01049 }
01050 
01051 /*
01052  * ToTimeStr: convert usec to hh:mm:ss.mmm
01053  */
01054 
01055 static char *ToTimeStr (double ti, char timbuf[])
01056 {
01057   long msec, sec, min, hour;
01058 
01059   if (hwcounters == false) { /* time */
01060     msec = fmod (ti / 1.0e3, 1.0e3);
01061     sec  = fmod (ti / 1.0e6, 60.0);
01062     min  = fmod (ti / 60.0e6, 60.0);
01063     hour = ti / 36.0e8;
01064   
01065     if ( hour )
01066       sprintf (timbuf, "%2d:%02d:%02d.%03d", hour, min, sec, msec);
01067     else if ( min )
01068       sprintf (timbuf, "   %2d:%02d.%03d", min, sec, msec);
01069     else if ( sec )
01070       sprintf (timbuf, "      %2d,%03d", sec, msec);
01071     else
01072       sprintf (timbuf, "         %3d", msec);
01073     if (ti < 1.0e3) 
01074       sprintf (timbuf, "   %9.3G",ti/1.0e3);
01075   } else { /* counters */
01076     sprintf(timbuf,"%12.4G", ti);
01077   }
01078 
01079   return (timbuf);
01080 }
01081 
01082 /*
01083  * MsecCmp   : compare usec field
01084  * CumMsecCmp: compare cumusec field
01085  * CallCmp   : compare numcalls field
01086  *
01087  * functions return (unsually) -1 for greater than, 0 for equal, 1 for less than
01088  * in order to reverse the order of sort (descending instead of ascending)
01089  * can be changed through sign
01090  */
01091 
01092 static int sign = 1;
01093 
01094 static int MsecCmp (const void *left, const void *right)
01095 {
01096   double l = ((struct p_prof_elem *) left)->usec;
01097   double r = ((struct p_prof_elem *) right)->usec;
01098 
01099   if ( l < r )
01100     return sign;
01101   else if ( l > r )
01102     return -sign;
01103   else
01104     return 0;
01105 }
01106 
01107 static int CumMsecCmp (const void *left, const void *right)
01108 {
01109   double l = ((struct p_prof_elem *) left)->cumusec;
01110   double r = ((struct p_prof_elem *) right)->cumusec;
01111 
01112   if ( l < r )
01113     return sign;
01114   else if ( l > r )
01115     return -sign;
01116   else
01117     return 0;
01118 }
01119 
01120 static int CallCmp (const void *left, const void *right)
01121 {
01122   int l = ((struct p_prof_elem *) left)->numcalls;
01123   int r = ((struct p_prof_elem *) right)->numcalls;
01124 
01125   if ( l < r )
01126     return sign;
01127   else if ( l > r )
01128     return -sign;
01129   else
01130     return 0;
01131 }
01132 
01133 static int MsecPerCallCmp (const void *left, const void *right)
01134 {
01135   double l = ((struct p_prof_elem *) left) ->usec/ ((struct p_prof_elem *) left) ->numcalls;
01136   double r = ((struct p_prof_elem *) right) ->usec/ ((struct p_prof_elem *) right)->numcalls;
01137 
01138   if ( l < r )
01139     return sign;
01140   else if (l > r)
01141     return -sign;
01142   else
01143     return 0;
01144 }
01145 
01146 static int CumMsecPerCallCmp (const void *left, const void *right)
01147 {
01148   double l = ((struct p_prof_elem *) left) ->cumusec/ ((struct p_prof_elem *) left) ->numcalls;
01149   double r = ((struct p_prof_elem *) right) ->cumusec/ ((struct p_prof_elem *) right)->numcalls;
01150 
01151   if ( l < r )
01152     return sign;
01153   else if (l > r)
01154     return -sign;
01155   else
01156     return 0;
01157 }
01158 
01159 static int StdDevCmp (const void *left, const void *right)
01160 {
01161   double l = ((struct p_prof_elem *) left ) -> stddeviation;
01162   double r = ((struct p_prof_elem *) right) -> stddeviation;
01163 
01164   if ( l < r )
01165     return sign;
01166   else if (l > r)
01167     return -sign;
01168   else
01169     return 0;
01170 }
01171 
01172 static int SubrCmp (const void *left, const void *right)
01173 {
01174   int l = ((struct p_prof_elem *) left)->numsubrs;
01175   int r = ((struct p_prof_elem *) right)->numsubrs;
01176 
01177   if ( l < r )
01178     return sign;
01179   else if ( l > r )
01180     return -sign;
01181   else
01182     return 0;
01183 }
01184 
01185 /*
01186  * PrintFuncTab : Print plain function profile data
01187  * DumpFuncTab  : Dump plain function profile data
01188  */
01189 
01190 
01191 static void PrintFuncTab (struct p_prof_elem *tab, double total, int max)
01192 {
01193   int i;
01194 #ifdef USE_LONG 
01195   int o_numcalls = 0;
01196   int o_numsubrs = 0;
01197 #else // DEFAULT double 
01198   double o_numcalls = 0.0;
01199   double o_numsubrs = 0.0;
01200 #endif // USE_LONG 
01201   double o_usec = 0.0;
01202   double o_cumusec = 0.0;
01203   double o_stddeviation = 0.0;
01204   char buf1[20], buf2[20];
01205 
01206   for (i=max; i<numfunc; i++) {
01207     o_numcalls     += tab[i].numcalls;
01208     o_numsubrs     += tab[i].numsubrs;
01209     o_usec         += tab[i].usec;
01210     o_cumusec      += tab[i].cumusec;
01211     o_stddeviation += tab[i].stddeviation;
01212   }
01213 
01214   if (hwcounters == false) {
01215     printf ("---------------------------------------------------------------------------------------\n");
01216     printf ("%%Time    Exclusive    Inclusive    #Call   #Subrs  Inclusive ");
01217     if (profilestats) printf("Standard  ");
01218     printf("Name\n");
01219     printf ("              msec   total msec                    usec/call  ");
01220     if (profilestats) printf("deviation ");
01221     printf("\n");
01222     printf ("---------------------------------------------------------------------------------------\n");
01223   } // timing data
01224   else {
01225     printf ("---------------------------------------------------------------------------------------\n");
01226     printf ("%%Time    Exclusive  Inclusive    #Call   #Subrs Count/Call  ");
01227     if (profilestats) printf("Standard  ");
01228     printf("Name\n");
01229     printf ("            counts  total counts                            ");
01230     if (profilestats) printf("deviation ");
01231     printf("\n");
01232     printf ("---------------------------------------------------------------------------------------\n");
01233 
01234   } // Counters data 
01235 
01236   for (i=0; i<numfunc && i<max; i++) {
01237 #ifdef DEBUG
01238 #ifdef USE_LONG 
01239     printf(" PrintFuncTab name = %s, numcalls %ld, numsubrs %ld usec %lG, cumusec %lG \n",
01240         tab[i].name, tab[i].numcalls, tab[i].numsubrs, tab[i].usec, tab[i].cumusec);
01241 #else // DEFAULT double
01242     printf(" PrintFuncTab name = %s, numcalls %lG, numsubrs %lG usec %lG, cumusec %lG \n",
01243         tab[i].name, tab[i].numcalls, tab[i].numsubrs, tab[i].usec, tab[i].cumusec);
01244 #endif // USE_LONG 
01245 #endif 
01246 /* DO WE NEED if tab[i].numcalls > 0 ? Yes - otherwise usec/call is inf */
01247     if ( tab[i].numcalls > 0 )  {
01248       if ( tab[i].cumusec > 0.0 ) { /*changed from usec > 0.0 to cumusec >0.0 */
01249         if ( hwcounters == false) { /* timing data use strings conversion */
01250 #ifdef USE_LONG
01251           printf ("%5.1f %s %s %8ld %8ld %10.0f ",
01252 #else // DEFAULT double 
01253           printf ("%5.1f %s %s %8G %8G %10.0f ",
01254 #endif // USE_LONG
01255             tab[i].cumusec / total * 100.0,
01256             ToTimeStr (tab[i].usec, buf1),
01257             ToTimeStr (tab[i].cumusec, buf2),
01258             tab[i].numcalls,
01259             tab[i].numsubrs,
01260             tab[i].cumusec / tab[i].numcalls);
01261           if (profilestats) printf("%10.4G ", tab[i].stddeviation); 
01262           printf("%s\n", tab[i].name);
01263         } 
01264         else { /* Counters  - do not use hr:mn:sec.msec format */
01265 #ifdef USE_LONG 
01266           printf ("%5.1f  %10.4G  %10.4G %8ld %8ld %10.0f ",
01267 #else // DEFAULT double
01268           printf ("%5.1f  %10.4G  %10.4G %8G %8G %10.0f ",
01269 #endif // USE_LONG 
01270             tab[i].cumusec / total * 100.0,
01271             tab[i].usec,
01272             tab[i].cumusec,
01273             tab[i].numcalls,
01274             tab[i].numsubrs,
01275             tab[i].cumusec / tab[i].numcalls);
01276           if(profilestats) printf("%10.4G ", tab[i].stddeviation);
01277           printf("%s\n", tab[i].name);
01278         } /* counters */
01279       } /* cumusec > 0 */
01280       else {
01281 #ifdef USE_LONG
01282         printf ("  0.0           0           0 %8ld %8ld          0 ",
01283 #else // DEFAULT double 
01284         printf ("  0.0           0           0 %8G %8G          0 ",
01285 #endif // USE_LONG 
01286           tab[i].numcalls,
01287           tab[i].numsubrs);
01288         if (profilestats) printf("%10.4G ", tab[i].stddeviation);
01289         printf("%s\n", tab[i].name);
01290 
01291       }
01292     } 
01293   }
01294 
01295   if ( o_numcalls > 0 ) {
01296     if ( o_cumusec > 0.0 ) {
01297       if (hwcounters == false) { /* time */
01298 #ifdef USE_LONG
01299         printf ("%5.1f %s %s %8ld %8ld %10.0f ",
01300 #else // DEFAULT double 
01301         printf ("%5.1f %s %s %8G %8G %10.0f ",
01302 #endif // USE_LONG 
01303           o_cumusec / total * 100.0,
01304           ToTimeStr (o_usec, buf1), ToTimeStr (o_cumusec, buf2),
01305           o_numcalls, o_numsubrs, o_cumusec / o_numcalls);
01306         if (profilestats) printf("%10.4G ",o_stddeviation);
01307         printf("-others-\n");
01308       }
01309       else { /* counters */
01310 #ifdef USE_LONG
01311         printf ("%5.1f  %10.4G  %10.4G %8ld %8ld %10.0f ", 
01312 #else // DEFAULT double
01313         printf ("%5.1f  %10.4G  %10.4G %8G %8G %10.0f ", 
01314 #endif // USE_LONG 
01315           o_cumusec / total * 100.0,
01316           o_usec, o_cumusec,
01317           o_numcalls, o_numsubrs, o_cumusec / o_numcalls);
01318         if (profilestats) printf("%10.4G ",o_stddeviation);
01319         printf("-others-\n");
01320       } /* counters */
01321     } /* o_cumusec > 0 */
01322     else {
01323 #ifdef USE_LONG
01324       printf ("  0.0           0           0 %8ld %8ld          0 ",
01325 #else // DEFAULT double 
01326       printf ("  0.0           0           0 %8G %8G          0 ",
01327 #endif // USE_LONG 
01328         o_numcalls, o_numsubrs);
01329       if (profilestats) printf("%10.4G ", o_stddeviation);
01330       printf("-others-\n");
01331     }
01332   }
01333 }
01334 
01336 static void PrintFuncTabOrig (struct p_prof_elem *tab, double total, int max)
01337 {
01338   int i;
01339 #ifdef USE_LONG
01340   int o_numcalls = 0;
01341   int o_numsubrs = 0;
01342 #else // DEFAULT double 
01343   double o_numcalls = 0.0;
01344   double o_numsubrs = 0.0;
01345 #endif // USE_LONG 
01346 
01347   double o_usec = 0.0;
01348   double o_cumusec = 0.0;
01349   char buf1[20], buf2[20];
01350 
01351   for (i=max; i<numfunc; i++) {
01352     o_numcalls += tab[i].numcalls;
01353     o_numsubrs += tab[i].numsubrs;
01354     o_usec     += tab[i].usec;
01355     o_cumusec  += tab[i].cumusec;
01356   }
01357 
01358   if (hwcounters == false) {
01359     printf ("---------------------------------------------------------------------------\n");
01360     printf ("%%time         msec   total msec    #call   #subrs  usec/call name\n");
01361     printf ("---------------------------------------------------------------------------\n");
01362   } // timing data
01363   else {
01364     printf ("---------------------------------------------------------------------------\n");
01365     printf ("%%time   exclusive   inclusive    #call   #subrs count/call name\n");
01366     printf ("---------------------------------------------------------------------------\n");
01367   } // Counters data 
01368 
01369   for (i=0; i<numfunc && i<max; i++) {
01370 #ifdef DEBUG
01371 #ifdef USE_LONG 
01372     printf(" PrintFuncTab name = %s, numcalls %ld, numsubrs %ld usec %lG, cumusec %lG \n",
01373         tab[i].name, tab[i].numcalls, tab[i].numsubrs, tab[i].usec, tab[i].cumusec);
01374 #else // DEFAULT double
01375     printf(" PrintFuncTab name = %s, numcalls %lG, numsubrs %lG usec %lG, cumusec %lG \n",
01376         tab[i].name, tab[i].numcalls, tab[i].numsubrs, tab[i].usec, tab[i].cumusec);
01377 #endif // USE_LONG 
01378 #endif 
01379 /* DO WE NEED if tab[i].numcalls > 0 ? Yes - otherwise usec/call is inf */
01380     if ( tab[i].numcalls > 0 )  {
01381       if ( tab[i].cumusec > 0.0 ) { /*changed from usec > 0.0 to cumusec >0.0 */
01382         if ( hwcounters == false) { /* timing data use strings conversion */
01383 #ifdef USE_LONG 
01384           printf ("%5.1f %s %s %8ld %8ld %10.0f %s\n",
01385 #else // DEFAULT double 
01386           printf ("%5.1f %s %s %8G %8G %10.0f %s\n",
01387 #endif // USE_LONG
01388             tab[i].cumusec / total * 100.0,
01389             ToTimeStr (tab[i].usec, buf1),
01390             ToTimeStr (tab[i].cumusec, buf2),
01391             tab[i].numcalls,
01392             tab[i].numsubrs,
01393             tab[i].cumusec / tab[i].numcalls,
01394             tab[i].name);
01395         } 
01396         else { /* Counters  - do not use hr:mn:sec.msec format */
01397 #ifdef USE_LONG
01398           printf ("%5.1f  %10.4G  %10.4G %8ld %8ld %10.0f %s\n",
01399 #else // DEFAULT double 
01400           printf ("%5.1f  %10.4G  %10.4G %8G %8G %10.0f %s\n",
01401 #endif // USE_LONG 
01402             tab[i].cumusec / total * 100.0,
01403             tab[i].usec,
01404             tab[i].cumusec,
01405             tab[i].numcalls,
01406             tab[i].numsubrs,
01407             tab[i].cumusec / tab[i].numcalls,
01408             tab[i].name);
01409         } /* counters */
01410       } /* cumusec > 0 */
01411       else {
01412 #ifdef USE_LONG 
01413         printf ("  0.0           0           0 %8ld %8ld          0 %s\n",
01414 #else // DEFAULT double
01415         printf ("  0.0           0           0 %8G %8G          0 %s\n",
01416 #endif // USE_LONG 
01417           tab[i].numcalls,
01418           tab[i].numsubrs,
01419           tab[i].name);
01420 
01421       }
01422     } 
01423   }
01424 
01425   if ( o_numcalls > 0 ) {
01426     if ( o_cumusec > 0.0 ) {
01427       if (hwcounters == false) { /* time */
01428 #ifdef USE_LONG
01429         printf ("%5.1f %s %s %8ld %8ld %10.0f -others-\n",
01430 #else // DEFAULT double 
01431         printf ("%5.1f %s %s %8G %8G %10.0f -others-\n",
01432 #endif // USE_LONG 
01433           o_cumusec / total * 100.0,
01434           ToTimeStr (o_usec, buf1), ToTimeStr (o_cumusec, buf2),
01435           o_numcalls, o_numsubrs, o_cumusec / o_numcalls);
01436       }
01437       else { /* counters */
01438 #ifdef USE_LONG
01439         printf ("%5.1f  %10.4G  %10.4G %8ld %8ld %10.0f -others-\n",
01440 #else // DEFAULT double 
01441         printf ("%5.1f  %10.4G  %10.4G %8G %8G %10.0f -others-\n",
01442 #endif // USE_LONG 
01443           o_cumusec / total * 100.0,
01444           o_usec, o_cumusec,
01445           o_numcalls, o_numsubrs, o_cumusec / o_numcalls);
01446       } /* counters */
01447     } /* o_cumusec > 0 */
01448     else {
01449 #ifdef USE_LONG 
01450       printf ("  0.0           0           0 %8ld %8ld          0 -others-\n",
01451 #else // DEFAULT double 
01452       printf ("  0.0           0           0 %8G %8G          0 -others-\n",
01453 #endif // USE_LONG
01454         o_numcalls, o_numsubrs);
01455     }
01456   }
01457 }
01459 
01460 
01461 static void DumpFuncTab (struct p_prof_elem *tab, char *id_str, double total,
01462                          int max, char *order) 
01463 {
01464   int i;
01465   int printed_anything = 0;
01466 #ifdef USE_LONG 
01467   long o_numcalls = 0;
01468   long o_numsubrs = 0;
01469 #else // DEFAULT double
01470   double o_numcalls = 0.0;
01471   double o_numsubrs = 0.0;
01472 #endif // USE_LONG 
01473   double t = 0.0;
01474   double o_usec = 0.0;
01475   double o_cumusec = 0.0;
01476   char buf1[20], buf2[20];
01477 
01478   for (i=0; i<numfunc; i++) {
01479     if ( tab[i].numcalls ) t += tab[i].usec;
01480     if ( i >= max ) {
01481       o_numcalls += tab[i].numcalls;
01482       o_numsubrs += tab[i].numsubrs;
01483       o_usec     += tab[i].usec;
01484       o_cumusec  += tab[i].cumusec;
01485     }
01486   }
01487 
01488   
01489 /* SINCE RACY DOESN'T SUPPORT NO OF SUBROUTINES, WE DON'T SEND IT THIS YET! */
01490   for (i=0; i<numfunc && i<max; i++) {
01491     if ( tab[i].numcalls) {
01492       printf("%s ",id_str);
01493 /* old 
01494       if ( id < 0 ) printf ("%c ", -id); else printf ("%d ", id);
01495 */
01496       printf ("%d \"%s\" %s ", tab[i].tag, tab[i].name, order);
01497       if ( order[0] == 'e' )
01498         printf ("%.16G %4.2f\n", tab[i].usec, tab[i].usec / t * 100.0);
01499       else if ( order[0] == 'i' )
01500         printf ("%.16G %4.2f\n", tab[i].cumusec, tab[i].cumusec/total*100.0);
01501       if ( tab[i].cumusec > 0.0 ) {
01502 #ifdef USE_LONG 
01503         printf ("%5.1f %s %s %8d %10.0f %s\n",
01504 #else // DEFAULT double 
01505         printf ("%5.1f %s %s %8G %10.0f %s\n",
01506 #endif // USE_LONG
01507           tab[i].cumusec / total * 100.0,
01508           ToTimeStr (tab[i].usec, buf1), ToTimeStr (tab[i].cumusec, buf2),
01509           tab[i].numcalls, tab[i].cumusec / tab[i].numcalls, tab[i].name);
01510       }
01511       else {
01512 #ifdef USE_LONG
01513         printf ("  0.0         0         0 %8d          0 %s\n",
01514 #else // DEFAULT double 
01515         printf ("  0.0         0         0 %8G          0 %s\n",
01516 #endif // USE_LONG 
01517           tab[i].numcalls,
01518           tab[i].name);
01519       }
01520     printed_anything = 1; /* set flag */
01521     }
01522   }
01523 
01524   if ( o_numcalls > 0) {
01525     printf("%s ",id_str);
01526 /* old 
01527     if ( id < 0 ) printf ("%c ", -id); else printf ("%d ", id);
01528 */
01529     printf (" -1 -others- %s ", order);
01530     if ( order[0] == 'e' )
01531       printf ("%.16G %4.2f\n", o_usec, o_usec / t * 100.0);
01532     else if ( order[0] == 'i' )
01533       printf ("%.16G %4.2f\n", o_cumusec, o_cumusec / total * 100.0);
01534     if ( o_cumusec > 0.0 ) {
01535 #ifdef USE_LONG
01536       printf ("%5.1f %s %s %8d %10.0f -others-\n",
01537 #else // DEFAULT double 
01538       printf ("%5.1f %s %s %8G %10.0f -others-\n",
01539 #endif // USE_LONG 
01540         o_cumusec / total * 100.0,
01541         ToTimeStr (o_usec, buf1), ToTimeStr (o_cumusec, buf2),
01542         o_numcalls, o_cumusec / o_numcalls);
01543     }
01544     else {
01545 #ifdef USE_LONG
01546       printf ("  0.0            0            0 %8d          0 -others-\n",
01547 #else // DEFAULT double 
01548       printf ("  0.0            0            0 %8G          0 -others-\n",
01549 #endif // USE_LONG 
01550         o_numcalls);
01551     }
01552     printed_anything = 1; /* set flag */
01553   }
01554   /* if we don't print anything, racy sees an error in getting incomplete data */
01555   if (!printed_anything) { /* then print a dummy record */
01556     printf("%s ", id_str);
01557     printf (" -1 -others- %s ", order);
01558  
01559     if ( order[0] == 'e' )
01560       if (t > 0.0) {
01561         printf ("%.16G %4.2f\n", o_usec, o_usec / t * 100.0);
01562       }
01563       else { 
01564         printf ("%.16G %4.2f\n", o_usec, o_usec ); /* will print 0 0 */
01565       }
01566     else if ( order[0] == 'i' )
01567       printf ("%.16G %4.2f\n", o_cumusec, o_cumusec / total * 100.0);
01568 #ifdef USE_LONG
01569     printf ("  0.0            0            0 %8d          0 -others-\n",
01570 #else // DEFAULT double 
01571     printf ("  0.0            0            0 %8G          0 -others-\n",
01572 #endif // USE_LONG 
01573         o_numcalls);
01574   }
01575 }
01576 
01577 /*
01578  * ReadNameTable: read function name table file
01579  * ProcessFile  : read profile data node file and print results
01580  */
01581 
01582 
01583 static void ReadNameTable (char file[])
01584 {
01585   int i, tag;
01586   FILE *in;
01587 
01588   sprintf (proffile, "%s.ftab", file);
01589 
01590   if ( (in = fopen (proffile, "r")) == NULL ) {
01591     perror (proffile);
01592     exit (1);
01593   }
01594 
01595   /* -- read depfile -- */
01596   if ( fgets (lbuf, 256, in) == NULL ) {
01597     fprintf (stderr, "%s: cannot read function table\n", proffile);
01598     exit (1);
01599   }
01600   sscanf (lbuf, "%s", sbuf);
01601   depfile = strsave (sbuf);
01602 
01603   /* -- read number of functions -- */
01604   fgets (lbuf, 256, in);
01605   sscanf (lbuf, "%d", &numfunc);
01606   
01607   /* -- read function table -- */
01608   funcnamebuf = (char **) malloc (numfunc * sizeof(char *));
01609   functagbuf  = (int *) malloc (numfunc * sizeof(int));
01610   for (i=0; i<numfunc; i++) {
01611     fgets (lbuf, 256, in);
01612     sscanf (lbuf, "%d %s", &tag, sbuf);
01613     if ( tag < 0 )
01614       funcnamebuf[i] = NULL;
01615     else
01616       funcnamebuf[i] = strsave (sbuf);
01617     functagbuf[i] = tag;
01618   }
01619   fclose (in);
01620 }
01621 
01622 static void ReadEventTable (char file[])
01623 { /* reads from profile.ctab the event tables <eid, eventname> */
01624   int i, j, eventid;
01625   FILE *in;
01626 
01627   sprintf (proffile, "%s.ctab", file);
01628 
01629   if ( (in = fopen (proffile, "r")) == NULL ) {
01630         return ; /* there's no .ctab file - no need to fill table */
01631         /* its legal not to have .ctab - for pc++ e.g. */
01632   }
01633 
01634   /* -- read ctab -- */
01635   if ( fgets (lbuf, 256, in) == NULL ) {
01636     fprintf (stderr, "%s: cannot read event table\n", proffile);
01637     exit (1);
01638   }
01639   sscanf (lbuf, "%d", &numevents);
01640 
01641   /* -- read event table -- */
01642   eventnamebuf = (char **) malloc (numevents * sizeof(char *));
01643   for (i=0; i<numevents; i++) {
01644     fgets (lbuf, 256, in);
01645     sscanf (lbuf, "%d", &eventid);
01646     j = 0;
01647     while((lbuf[j] != '"') && (j < strlen(lbuf))) j++; /* skip */
01648     if ( j != strlen (lbuf))
01649     {
01650         strcpy(sbuf, &lbuf[j]);
01651         sbuf[strlen(sbuf) - 1] = '\0' ; /* remove \n at the end */
01652     }
01653     else 
01654     {
01655         sscanf(lbuf, "%d %s",&eventid, sbuf);
01656         fprintf(stderr,"Warning : event id %d name %s should be in quotes in %s\n", eventid, sbuf, proffile);
01657     }
01658     
01659     if ( eventid < 0 )
01660       eventnamebuf[i] = NULL;
01661     else
01662       eventnamebuf[eventid] = strsave (sbuf);
01663   }
01664   fclose (in);
01665   /* we know the number of counters */
01666   if (numevents > MAX_COUNTERS) /* realloc the counters array */
01667   {
01668     fprintf(stderr,"Number of events in %s exceeds system limit \n",proffile);
01669   }
01670 #ifdef DEBUG
01671   for(i=0; i<numevents; i++)
01672   {
01673     printf("Event id %d name=%s\n",i,eventnamebuf[i]);
01674   }
01675 #endif
01676   return;
01677 }
01678 
01679 static int ProcessFile (int no, int ctx, int thr, int longname, int max, char prefix[], int ignore)
01680 {
01681   int i, j, e, n, r, s, d, l, eid;
01682   int ret, active_counters=0;
01683   long count;
01684   int numf;
01685   int numc;
01686   int numa;
01687   FILE *in;
01688   double t1, t2;
01689   double total, ct;
01690   extern int errno;
01691   char s1[128], s2[128];
01692   char aggr_str[32],ident_str[32];
01693 
01694   if (longname == FALSE) /* pc++ */
01695   {
01696     sprintf (proffile, "%s.%d", prefix, no);
01697   }
01698   else
01699   { /* hpc++ profile.0.0.0 etc. */
01700     sprintf (proffile, "%s.%d.%d.%d", prefix, no, ctx, thr);
01701   }
01702     
01703 
01704   /* -- read profile data file and set profile data tables ------------------ */
01705   /* ------------------------------------------------------------------------ */
01706   if ( (in = fopen (proffile, "r")) == NULL ) {
01707     if ( errno == ENOENT && ignore)
01708       return (FALSE);
01709     else {
01710       perror (proffile);
01711       exit (1);
01712     }
01713   }
01714 
01715 #ifdef DEBUG
01716   printf("Reading %s\n", proffile);
01717 #endif
01718   /* reset top level function finding data */
01719   top_level_function = 0 ; /* by default - works for pC++ */
01720   max_thread_cumusec = 0.0 ; /* initialize */
01721 
01722   /* -- read number of functions -------------------------------------------- */  if ( fgets (lbuf, 256, in) == NULL ) {
01723     fprintf (stderr,"invalid proftablefile: cannot read number of functions\n");    exit (1);
01724   }
01725   sscanf (lbuf, "%d", &numf);
01726 
01727   if ( numf != numfunc ) {
01728     fprintf (stderr, "%s: number of functions does not match\n", proffile);
01729     exit (1);
01730   }
01731 
01732   /* -- read and setup function profile data -------------------------------- */  p_func_list = (struct p_func_descr *) malloc (numf * sizeof(struct p_func_descr));
01733   for (i=0; i<numf; i++) {
01734     fgets (lbuf, 256, in);
01735 
01736 #ifdef __bsdi__
01737     /* Wierd bogus HACK because bsdi is funky (PHB) */
01738     sscanf (lbuf, "%d %lf %lf", &n, &t1, &t2);
01739 #else
01740     sscanf (lbuf, "%d %lG %lG", &n, &t1, &t2);
01741 #endif
01742 
01743     p_func_list[i].numcalls = n;
01744     p_func_list[i].usec     = t1;
01745     p_func_list[i].cumusec  = t2;
01746     if (p_func_list[i].cumusec > max_thread_cumusec) {
01747         top_level_function = i; /* to find which is the top level function
01748         in this thread we find the function with the max cumusec */
01749         max_thread_cumusec = p_func_list[i].cumusec;
01750     }
01751 #ifdef DEBUG
01752     printf("Func Id %d numcalls %d usec %lG cumusec %lG\n",i, p_func_list[i].numcalls, p_func_list[i].usec, p_func_list[i].cumusec);
01753 #endif
01754   }
01755 
01756   /* -- read number of collections ------------------------------------------ */
01757   if ( fgets (lbuf, 256, in) == NULL ) {
01758     fprintf (stderr,
01759                   "invalid proftablefile: cannot read number of collections\n");
01760     exit (1);
01761   }
01762   sscanf (lbuf, "%d %s", &numc, aggr_str);
01763 
01764   if(strcmp(aggr_str,"coll") == 0) /* pc++ file, hpc++ has aggregates */
01765   {
01766     /* -- setup and read collection profile data ------------------------------ */
01767     if ( numc ) {
01768       p_coll_list = (struct p_coll_descr *) malloc (numc * sizeof(struct p_coll_descr));
01769   
01770       for (i=0; i<numc; i++) {
01771         fgets (lbuf, 256, in);
01772         sscanf (lbuf,"%d %d %d %d %d %s %s %s", &n, &d, &s, &l, &r, sbuf, s1, s2);
01773   
01774         p_coll_list[i].numelem   = n;
01775         p_coll_list[i].dim       = d;
01776         p_coll_list[i].size      = s;
01777         p_coll_list[i].localacs  = l;
01778         p_coll_list[i].remoteacs = r;
01779         p_coll_list[i].collname = strsave(sbuf);
01780         p_coll_list[i].elemname = strsave(s1);
01781         p_coll_list[i].varname  = strsave(s2);
01782       }
01783   
01784       if ( !p_coll_tbl ) {
01785         p_coll_tbl = (struct p_coll_descr *) malloc (numc * sizeof(struct p_coll_descr));
01786         for (i=0; i<numc; i++) {
01787           p_coll_tbl[i].numelem   = p_coll_list[i].numelem;
01788           p_coll_tbl[i].dim       = p_coll_list[i].dim;
01789           p_coll_tbl[i].size      = p_coll_list[i].size;
01790           p_coll_tbl[i].localacs  = 0;
01791           p_coll_tbl[i].remoteacs = 0;
01792           p_coll_tbl[i].collname = p_coll_list[i].collname;
01793           p_coll_tbl[i].elemname = p_coll_list[i].elemname;
01794           p_coll_tbl[i].varname  = p_coll_list[i].varname;
01795         }
01796         numcoll = numc;
01797       }
01798       else if ( numc != numcoll ) {
01799         fprintf (stderr, "%s: number of collections does not match\n", proffile);
01800         exit (1);
01801       }
01802     }
01803   } /* if aggr_str == "coll"*/
01804   else if (strcmp(aggr_str,"aggregates") == 0)
01805   { /* hpc++ aggregate info */
01806     numa = numc;
01807     hpcxx_flag = TRUE;
01808 
01809     if ( numa ) {
01810       p_aggr_list = (struct p_aggr_descr *) malloc (numa * sizeof(struct p_aggr_descr));
01811   
01812       for (i=0; i<numa; i++) {
01813 /*
01814         if (((ret = fscanf(in, "%d", &e)) < 0) ||
01815             ((ret = fscanf(in, "%d", &n)) < 0) ||
01816             ((ret = fscanf(in, "%d", &d)) < 0) ||
01817             ((ret = fscanf(in, "%d", &s)) < 0) )
01818 */
01819         if ((ret = fscanf(in, "%d %d %d %d ", &e, &n, &d, &s)) < 0)
01820         {
01821           perror("fscanf error:");
01822           exit(1);
01823         }
01824 #ifdef DEBUG
01825         printf("Got events %d no %d dim %d size %d\n", e,n,d,s);
01826 #endif
01827         /* clean the n counters */
01828         for(j =0; j < MAX_COUNTERS; j++)
01829         {
01830           p_aggr_list[i].counters[j] = 0L;
01831         }
01832         p_aggr_list[i].total_events = 0L;
01833   
01834         p_aggr_list[i].numelem   = n;
01835         p_aggr_list[i].dim       = d;
01836         p_aggr_list[i].size      = s;
01837         for(j = 0; j < e; j++)
01838         { /* read the tuples <eventid, count > */
01839           fscanf(in,"%d %ld ", &eid, &count);
01840 #ifdef DEBUG
01841           printf(" <e %d c %ld> ", eid, count);
01842 #endif
01843           if ((eid < 0) || (eid > MAX_COUNTERS))
01844           {
01845              printf("Illegal event id %d \n", eid);
01846              exit(1);
01847           }
01848           p_aggr_list[i].counters[eid] = count;
01849           p_aggr_list[i].total_events += count;
01850         }
01851         fscanf(in, "%s %s %s", sbuf, s1, s2);
01852         p_aggr_list[i].container_name = strsave(sbuf);
01853         p_aggr_list[i].container_type = strsave(s1);
01854         p_aggr_list[i].var_name  = strsave(s2);
01855 #ifdef DEBUG
01856         printf("\nReading %s %s %s\n", sbuf,s1, s2);
01857 #endif
01858       }
01859   
01860       if ( !p_aggr_tbl ) { /* this is done only once */
01861         p_aggr_tbl = (struct p_aggr_descr *) malloc (numa * sizeof(struct p_aggr_descr));
01862         for (i=0; i<numa; i++) {
01863           p_aggr_tbl[i].numelem   = p_aggr_list[i].numelem;
01864           p_aggr_tbl[i].dim       = p_aggr_list[i].dim;
01865           p_aggr_tbl[i].size      = p_aggr_list[i].size;
01866           p_aggr_tbl[i].container_name = p_aggr_list[i].container_name;
01867           p_aggr_tbl[i].container_type = p_aggr_list[i].container_type;
01868           p_aggr_tbl[i].var_name  = p_aggr_list[i].var_name;
01869           for(j = 0; j < MAX_COUNTERS; j++)
01870           { /* initialize */
01871             p_aggr_tbl[i].counters[j]  = 0L;
01872             p_aggr_tbl[i].total_events = 0L;
01873           }
01874         }
01875         numaggr = numa; 
01876       }
01877       else if ( numa != numaggr ) {
01878         fprintf (stderr, "%s: number of aggregates does not match\n", proffile);
01879         exit (1);
01880       }
01881     } /* numa > 0 */
01882   }  /* aggr_str == "aggregates" */
01883 
01884   
01885   fclose (in);
01886 
01887   /* -- initialize summary function profile data table ---------------------- */
01888   if ( !p_total_tbl ) {
01889     p_total_tbl = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
01890     p_min_tbl   = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
01891     p_max_tbl   = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
01892     for (i=0; i<numf; i++) {
01893       p_total_tbl[i].tag      = functagbuf[i];
01894       p_total_tbl[i].name     = funcnamebuf[i];
01895       p_total_tbl[i].usec     = 0.0;
01896       p_total_tbl[i].cumusec  = 0.0;
01897       p_total_tbl[i].numcalls = 0;
01898 
01899       p_max_tbl[i].tag      = p_min_tbl[i].tag      = p_total_tbl[i].tag;
01900       p_max_tbl[i].name     = p_min_tbl[i].name     = p_total_tbl[i].name;
01901       p_max_tbl[i].usec     = p_min_tbl[i].usec     = p_func_list[i].usec;
01902       p_max_tbl[i].cumusec  = p_min_tbl[i].cumusec  = p_func_list[i].cumusec;
01903       p_max_tbl[i].numcalls = p_min_tbl[i].numcalls = p_func_list[i].numcalls;
01904 #ifdef DEBUG
01905     printf(" Func %d, min_tbl[i].numcalls %d usec %lG, cumusec %lG\n",
01906         i, p_min_tbl[i].numcalls, p_min_tbl[i].usec, p_min_tbl[i].cumusec);
01907 
01908     printf(" Func %d, max_tbl[i].numcalls %d usec %lG, cumusec %lG\n",
01909         i, p_max_tbl[i].numcalls, p_max_tbl[i].usec, p_max_tbl[i].cumusec);
01910 #endif /* DEBUG */
01911     }
01912     total_total = 0.0;
01913     /* old
01914     max_total = min_total = p_func_list[0].cumusec; 0 is not top level fn.
01915    */
01916     max_total = min_total = p_func_list[top_level_function].cumusec;
01917   }
01918 
01919   /* -- set function profile data table ------------------------------------- */
01920   /* -- and update summary function profile data table ---------------------- */
01921   p_prof_tbl = (struct p_prof_elem *) malloc (numf * sizeof(struct p_prof_elem));
01922   for (i=0; i<numf; i++) {
01923     p_prof_tbl[i].tag   = p_total_tbl[i].tag;
01924     p_prof_tbl[i].name  = p_total_tbl[i].name;
01925     p_total_tbl[i].usec     += p_prof_tbl[i].usec     = p_func_list[i].usec;
01926     p_total_tbl[i].cumusec  += p_prof_tbl[i].cumusec  = p_func_list[i].cumusec;
01927     p_total_tbl[i].numcalls += p_prof_tbl[i].numcalls = p_func_list[i].numcalls;
01928 
01929     if ( p_min_tbl[i].usec     > p_func_list[i].usec )
01930       p_min_tbl[i].usec     = p_func_list[i].usec;
01931     if ( p_min_tbl[i].cumusec  > p_func_list[i].cumusec )
01932       p_min_tbl[i].cumusec  = p_func_list[i].cumusec;
01933     if ( p_min_tbl[i].numcalls > p_func_list[i].numcalls )
01934       p_min_tbl[i].numcalls = p_func_list[i].numcalls;
01935 
01936     if ( p_max_tbl[i].usec     < p_func_list[i].usec )
01937       p_max_tbl[i].usec     = p_func_list[i].usec;
01938     if ( p_max_tbl[i].cumusec  < p_func_list[i].cumusec )
01939       p_max_tbl[i].cumusec  = p_func_list[i].cumusec;
01940     if ( p_max_tbl[i].numcalls < p_func_list[i].numcalls )
01941       p_max_tbl[i].numcalls = p_func_list[i].numcalls;
01942   }
01943 #ifdef DEBUG
01944   for (i=0; i<numf; i++) {
01945     printf(" Func %d, min_tbl[i].numcalls %d usec %lG, cumusec %lG\n",
01946         i, p_min_tbl[i].numcalls, p_min_tbl[i].usec, p_min_tbl[i].cumusec);
01947 
01948     printf(" Func %d, max_tbl[i].numcalls %d usec %lG, cumusec %lG\n",
01949         i, p_max_tbl[i].numcalls, p_max_tbl[i].usec, p_max_tbl[i].cumusec);
01950   }
01951 #endif /* DEBUG */
01952 
01953 
01954 #ifdef DEBUG
01955   printf("Top level function = %d in file %s\n", top_level_function, proffile);
01956 #endif /* DEBUG */
01957   /* -- get total runtime (time of "main" function (always function 0)) ----- */
01958   /* This is not true for all programs; new method - 
01959      The top level function has max cumusec time for that thread (support 
01960      for MIMD programs where top level fn is different for different threads */
01961   total_total += total = p_func_list[top_level_function].cumusec;
01962   if ( min_total > p_func_list[top_level_function].cumusec ) min_total = p_func_list[top_level_function].cumusec;
01963   if ( max_total < p_func_list[top_level_function].cumusec ) max_total = p_func_list[top_level_function].cumusec;
01964 
01965 #ifdef DEBUG
01966   printf("%s : total = %5.1f top level = %5.1f\n", proffile, total, max_thread_cumusec);
01967 #endif
01968   if (hpcxx_flag == FALSE) 
01969   { 
01970     sprintf(ident_str,"%d", no);
01971   }
01972   else  /* hpc++ */
01973   {
01974     sprintf(ident_str,"%d,%d,%d", no, ctx, thr);
01975   }
01976 
01977  
01978   /* -- print function profile data table ----------------------------------- */
01979   if ( nodeprint ) {
01980     if ( dump ) {
01981       qsort ((void *) p_prof_tbl, numf, sizeof(struct p_prof_elem), MsecCmp);
01982       DumpFuncTab (p_prof_tbl, ident_str, total, max, "excl");
01983       qsort ((void *) p_prof_tbl, numf, sizeof(struct p_prof_elem), CumMsecCmp);
01984       DumpFuncTab (p_prof_tbl, ident_str, total, max, "incl");
01985     }
01986     else {
01987       qsort ((void *) p_prof_tbl, numf, sizeof(struct p_prof_elem), compar);
01988       if (hpcxx_flag == FALSE)
01989         printf ("\nNODE %d: \n", no);
01990       else
01991       {
01992         printf ("\nNODE %d;", no);
01993         printf ("CONTEXT %d;", ctx);
01994         printf ("THREAD %d:\n", thr);
01995       }
01996 
01997       PrintFuncTab (p_prof_tbl, total, max);
01998     }
01999   }
02000 
02001   if ( numc ) {
02002     if ( hpcxx_flag == FALSE) { /* pc++ data format */
02003       if ( nodeprint ) {
02004         if ( ! dump ) {
02005           printf ("\n   local    remote  collection\n");
02006           printf (  "accesses  accesses  num   name\n");
02007         }
02008       }
02009       for (i=0; i<numc; i++) {
02010         if ( nodeprint ) {
02011           /* -- print collection profile data table --------------------------- */
02012           if ( dump ) {
02013             if ( ct = p_coll_list[i].localacs + p_coll_list[i].remoteacs ) {
02014               printf ("coll %d %d %d %4.2f %d %4.2f\n", no, i, 
02015                      p_coll_list[i].localacs, p_coll_list[i].localacs/ct*100.0,
02016                      p_coll_list[i].remoteacs, p_coll_list[i].remoteacs/ct*100.0);
02017             }
02018             else {
02019               printf ("coll %d %d 0 0.0 0 0.0\n", no, i);
02020             }
02021           }
02022           else {
02023             printf ("%8d  %8d  %3d   %s\n",
02024               p_coll_list[i].localacs, p_coll_list[i].remoteacs,
02025               i, p_coll_list[i].varname);
02026           }
02027         }
02028   
02029         /* -- compute collection profile summary ------------------------------ */
02030         p_coll_tbl[i].localacs  += p_coll_list[i].localacs;
02031         p_coll_tbl[i].remoteacs += p_coll_list[i].remoteacs;
02032       }
02033     } /* hpcxx_flag == FALSE */
02034     else {
02035         /* print aggregate info */
02036 /*
02037       if ( nodeprint ) {
02038         if ( ! dump ) {
02039           printf ("\n   local    remote  collection\n");
02040           printf (  "accesses  accesses  num   name\n");
02041         }
02042       }
02043 */
02044       for (i=0; i<numa; i++) {
02045         if ( nodeprint ) {
02046           /* -- print aggregate profile data table --------------------------- */
02047           if ( dump ) {
02048             if ( p_aggr_list[i].total_events ) {
02049               active_counters = 0;
02050               for(j=0; j < MAX_COUNTERS; j++)
02051               {
02052                 if (p_aggr_list[i].counters[j]) active_counters++ ;
02053               }
02054               printf("aggregates %d,%d,%d %d %d ",no, ctx, thr, i, active_counters); 
02055               /* and then the quads <eid, name, no, %val> */
02056               for (j = 0; j < MAX_COUNTERS; j++) 
02057               {
02058                 /* print only those events that took place */ 
02059                 if ( p_aggr_list[i].counters[j])
02060                 {
02061                   if (eventnamebuf == NULL)
02062                   { /* print NULL */
02063                     printf("%d NULL %d %4.2f ", j, 
02064                         p_aggr_list[i].counters[j], 
02065         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
02066                   }
02067                   else
02068                   {
02069                     printf("%d %s %d %4.2f ", j, eventnamebuf[j],
02070                         p_aggr_list[i].counters[j], 
02071         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
02072                   }
02073                 }
02074               } /* printed the j counters */
02075               printf("%s %s %s\n", p_aggr_list[i].container_name,
02076                 p_aggr_list[i].container_type, p_aggr_list[i].var_name);
02077             }
02078             else /* all counters are 0 */
02079             {
02080               printf("aggregates %d,%d,%d %d 0 NULL 0 0.0 %s %s %s\n", 
02081                 no, ctx, thr, i, p_aggr_list[i].container_name,
02082                 p_aggr_list[i].container_type, p_aggr_list[i].var_name);
02083               /* node no ctx thr , eid 0 name NULL events 0 % 0.0 */
02084             }
02085           } 
02086           else 
02087           { /* not dump */
02088             printf("aggregates %s <%s> %s\n",p_aggr_list[i].container_name,
02089                         p_aggr_list[i].container_type, p_aggr_list[i].var_name);
02090             for(j = 0; j < MAX_COUNTERS; j++)
02091             {
02092               if(p_aggr_list[i].counters[j]) 
02093               {
02094                 if(eventnamebuf == NULL)
02095                 {
02096                   printf("Event id %d\t: %d %4.2f       percent\n",
02097                         j, p_aggr_list[i].counters[j],  
02098         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
02099                 }
02100                 else
02101                 {
02102                   printf("Event id %d name %s\t: %d %4.2f percent\n",
02103                         j, eventnamebuf[j], p_aggr_list[i].counters[j],
02104         p_aggr_list[i].counters[j]*100.0/p_aggr_list[i].total_events);
02105                 }
02106               } 
02107             } /* printed all events */
02108           } /* not dump */
02109         } /* nodeprint */
02110         /* -- compute collection profile summary ------------------------------ */
02111         for (j = 0; j < MAX_COUNTERS; j++)
02112         {
02113           p_aggr_tbl[i].counters[j] += p_aggr_list[i].counters[j];
02114         }
02115         p_aggr_tbl[i].total_events += p_aggr_list[i].total_events;
02116       } /* for i */
02117     } /* hpcxx_flag == TRUE */
02118   } /* numc > 0 */
02119 
02120   free (p_coll_list);
02121   free (p_func_list);
02122   free (p_prof_tbl);
02123   free (p_aggr_list);
02124   files_processed ++; /* increment counter for hpc++ */
02125   return (TRUE);
02126 }
02127 
02128 /*
02129  * PrintFuncSummary: Print summary function profile data
02130  * PrintSummary    : Print all summary profile information
02131  */
02132 
02133 static void PrintFuncSummary (struct p_prof_elem *tab, double total,
02134                               int max, char *message, char *ident)
02135 {
02136   /* -- print summary function profile data table --------------------------- */
02137   if ( dump ) {
02138     qsort ((void *) tab, numfunc, sizeof(struct p_prof_elem), MsecCmp);
02139     DumpFuncTab (tab,  ident, total, max, "excl");
02140     qsort ((void *) tab, numfunc, sizeof(struct p_prof_elem), CumMsecCmp);
02141     DumpFuncTab (tab,  ident, total, max, "incl");
02142   }
02143   else {
02144     qsort ((void *) tab, numfunc, sizeof(struct p_prof_elem), compar);
02145     printf ("\nFUNCTION SUMMARY (%s):\n", message);
02146     PrintFuncTab (tab, total, max);
02147   }
02148 }
02149 
02150 static void PrintSummary (int max, int numproc)
02151 {
02152   int i,j,no_active_counters;
02153   double ct;
02154 
02155 #ifdef DEBUG
02156   printf("PrintSummary: numproc = %d, dump = %d \n", numproc, dump);
02157 #endif /* DEBUG */
02158 
02159   if ( (numproc > 1) || dump ) {
02160     PrintFuncSummary (p_total_tbl, total_total, max, "total", "t");
02161     if (dumpminmax) {
02162       PrintFuncSummary (p_min_tbl, min_total, max, "min", "<");
02163       PrintFuncSummary (p_max_tbl, max_total, max, "max", ">");
02164     }
02165 
02166 #ifdef DEBUG
02167   for(i=0; i < numfunc; i++) {
02168     printf("p_total_tbl[i].numcalls = %d\n", p_total_tbl[i].numcalls);
02169   }
02170 #endif /* DEBUG */
02171   
02172     for (i=0; i<numfunc; i++) {
02173       p_total_tbl[i].numcalls /= numproc;
02174       p_total_tbl[i].numsubrs /= numproc;
02175       p_total_tbl[i].usec     /= numproc;
02176       p_total_tbl[i].cumusec  /= numproc;
02177     }
02178     total_total /= numproc;
02179 
02180 #ifdef DEBUG
02181   for (i=0; i < numfunc; i++) {
02182     printf("PrintSummary(Mean): Func %d p_total_tbl numcalls %d, usec %lG, cumusec %lg\n", i, p_total_tbl[i].numcalls, p_total_tbl[i].usec, p_total_tbl[i].cumusec);
02183   }
02184 #endif /* DEBUG */
02185 
02186 
02187     PrintFuncSummary (p_total_tbl, total_total, max, "mean", "m");
02188   }
02189 
02190   if(hpcxx_flag == FALSE) /* pc++ format */
02191   {
02192     if ( numcoll ) {
02193       if ( dump ) {
02194         for (i=0; i<numcoll; i++) {
02195           ct = p_coll_tbl[i].localacs + p_coll_tbl[i].remoteacs;
02196           printf ("cinfo %d %s<%s> %s %d %d %d %d %4.2f %d %4.2f\n",
02197             i, p_coll_tbl[i].collname, 
02198             p_coll_tbl[i].elemname, p_coll_tbl[i].varname,
02199             p_coll_tbl[i].numelem, p_coll_tbl[i].size, p_coll_tbl[i].dim,
02200             p_coll_tbl[i].localacs, p_coll_tbl[i].localacs/ct*100.0,
02201             p_coll_tbl[i].remoteacs, p_coll_tbl[i].remoteacs/ct*100.0);
02202         }
02203       }
02204       else {
02205         printf ("\nCOLLECTION SUMMARY:\n");
02206         printf ("------------------------------------------------------------\n");
02207         for (i=0; i<numcoll; i++) {
02208           printf ("%s<%s> %s, collection #%d\n", p_coll_tbl[i].collname,
02209             p_coll_tbl[i].elemname, p_coll_tbl[i].varname, i);
02210           printf ("\t%d elements of size %d, %d-dimensional\n",
02211             p_coll_tbl[i].numelem, p_coll_tbl[i].size, p_coll_tbl[i].dim);
02212           printf ("\t%8d local / %8d remote accesses\n",
02213             p_coll_tbl[i].localacs, p_coll_tbl[i].remoteacs);
02214         }
02215       }
02216     }
02217   }
02218   else /* hpcxx_flag == TRUE */
02219   {
02220     /* print aggregate information */
02221 
02222     if ( numaggr ) {
02223       if ( dump ) {
02224         for (i=0; i<numaggr; i++) {
02225           no_active_counters  = 0;
02226           for (j = 0; j < MAX_COUNTERS; j++) 
02227           { 
02228             if(p_aggr_tbl[i].counters[j]) no_active_counters ++;
02229           } 
02230         
02231           printf("ainfo %d %s %s  %s %d %d %d %d ", i, 
02232             p_aggr_tbl[i].container_name, p_aggr_tbl[i].container_type,
02233             p_aggr_tbl[i].var_name, p_aggr_tbl[i].numelem, 
02234             p_aggr_tbl[i].size, p_aggr_tbl[i].dim, no_active_counters);
02235 
02236           for(j = 0; j < MAX_COUNTERS; j++)
02237           {
02238             if (p_aggr_tbl[i].counters[j]) /* non zero */
02239             { 
02240               if (eventnamebuf == NULL)
02241               { /* print NULL */
02242                 printf("%d NULL %d %4.2f ", j, 
02243                   p_aggr_tbl[i].counters[j], 
02244         p_aggr_tbl[i].counters[j]*100.0/p_aggr_tbl[i].total_events);
02245               }
02246               else
02247               {
02248                 printf("%d %s %d %4.2f ", j, eventnamebuf[j],
02249                   p_aggr_tbl[i].counters[j], 
02250         p_aggr_tbl[i].counters[j]*100.0/p_aggr_tbl[i].total_events);
02251               }
02252             }
02253           } /* over counters j */
02254           printf("\n");
02255         } /* over all aggregates */
02256       } /* if dump */
02257       else {
02258         printf ("\nAGGREGATE SUMMARY:\n");
02259         printf ("------------------------------------------------------------\n");
02260         for (i=0; i<numaggr; i++) {
02261           printf ("%s<%s> %s, aggregate #%d\n", 
02262             p_aggr_tbl[i].container_name,
02263             p_aggr_tbl[i].container_type, p_aggr_tbl[i].var_name, i);
02264           printf ("\t%d elements of size %d, %d-dimensional\n",
02265             p_aggr_tbl[i].numelem, p_aggr_tbl[i].size, p_aggr_tbl[i].dim);
02266           for(j = 0; j < MAX_COUNTERS; j++)
02267           {
02268             if(p_aggr_tbl[i].counters[j]) 
02269             {
02270               if(eventnamebuf == NULL)
02271               {
02272                 printf("Event id %d\t: %d %4.2f percent\n",
02273                   j, p_aggr_tbl[i].counters[j],  
02274         p_aggr_tbl[i].counters[j]*100.0/p_aggr_tbl[i].total_events);
02275               }
02276               else
02277               {
02278                 printf("Event id %d name %s\t: %d %4.2f percent\n",
02279                   j, eventnamebuf[j], p_aggr_tbl[i].counters[j],
02280         p_aggr_tbl[i].counters[j]*100.0/p_aggr_tbl[i].total_events);
02281               }
02282             }
02283           } /* over counters */
02284           printf("\n");
02285         } /* aggregates */
02286       } /* if dump */
02287     } /* numaggr > 0 */
02288   } /* hpcxx_flag */
02289   return;
02290 }
02291 
02292 static int IsFilePresent(char *filename)
02293 {
02294 FILE *in;
02295  
02296   if ( (in = fopen (filename, "r")) == NULL ) {
02297     return (FALSE);
02298   }
02299   else 
02300   {
02301     fclose(in);
02302     return (TRUE);
02303   }
02304 }
02305 
02306 static int ProcessFileInContext (int no, int ctx, int thr, int longname, int max, char prefix[], int ignore)
02307 { 
02308   /* check files from thread 0 to n in loop till ProcessFile returns
02309         FALSE  */
02310   for (thr = 0; 
02311     ProcessFile (no, ctx, thr, longname, max, prefix, ignore);
02312        thr ++)
02313         ;
02314   return (FALSE);
02315 }
02316 
02317 
02318 static int ProcessFileInNode (int no, int ctx, int thr, int longname, int max, char prefix[], int ignore)
02319 { /* check files from context 0 to n */
02320   for (ctx = 0; 
02321     ProcessFileInContext(no, ctx, thr, longname, max, prefix, ignore);
02322        ctx ++) 
02323     ; /* blank */
02324     return (FALSE);
02325 }
02326 /*
02327  * profile main function
02328  */
02329 
02330 int main (int argc, char *argv[])
02331 {
02332   int argno, start;
02333   int ch;
02334   int i;
02335   int max = 999999999;
02336   int errflag;
02337   char *file = "profile";
02338   char proffile[SIZE_OF_FILENAME], *dir;
02339 
02340   extern char *optarg;
02341   extern int optind;
02342 
02343   dir = getenv("PROFILEDIR");
02344   if(dir != NULL) {
02345     file = strsave(strcat(strcat(dir,"/"),file));
02346   } 
02347 
02348   /* -- parse command line arguments ---------------------------------------- */
02349   errflag = FALSE;
02350   while ( (ch = getopt (argc, argv, "cbdf:lmeivn:rstx")) != EOF ) {
02351     switch ( ch ) {
02352     case 'c': /* -- sort according to number of *C*alls -- */
02353       compar = CallCmp;
02354       break;
02355     case 'b': /* -- sort according to number of subroutines called -- */
02356       compar = SubrCmp;
02357       break;
02358     case 'd': /* -- *D*ump output format (for racy) -- */
02359       dump = TRUE;
02360       break;
02361     case 'f': /* -- profile data *F*ile prefix -- */
02362       file = optarg;
02363       break;
02364     case 'l': /* -- *L*ist function table for debug purposes -- */
02365       list = TRUE;
02366       break;
02367     case 'm': /* -- sort according to *M*illiseconds -- */
02368       compar = MsecCmp;
02369       break;
02370     case 'e': /* -- sort according to Milliseconds (*E*xclusive per call)  -- */
02371       compar = MsecPerCallCmp;
02372       break;
02373     case 'i': /* -- sort according to Milliseconds (*I*nclusive per call)  -- */
02374       compar = CumMsecPerCallCmp;
02375       break;
02376     case 'n': /* -- print only first n *N*umber of funtions -- */
02377       max = atoi(optarg);
02378       break;
02379     case 'r': /* -- *R*everse sorting order -- */
02380       sign = -1;
02381       break;
02382     case 's': /* -- print only *S*ummary profile information -- */
02383       nodeprint = FALSE;
02384       break;
02385     case 't': /* -- sort according to *T*otal milliseconds -- */
02386       compar = CumMsecCmp; /* default mode */
02387       break;
02388     case 'v': /* -- sort according to standard de*V*iation --*/
02389       compar = StdDevCmp;  
02390       break; 
02391     case 'x': /* -- dump min and ma*X* information as well (default don't) -- */
02392       dumpminmax  = TRUE;
02393       break;
02394     default:
02395       errflag = TRUE;
02396       break;
02397     }
02398   }
02399   if ( errflag ) {
02400     fprintf (stderr, "usage: %s [-c|-b|-m|-t|-e|-i|-v] [-r] [-s] [-n num] [-f filename] [-l] [node numbers]\n", argv[0]);
02401     fprintf(stderr," -c : Sort according to number of Calls \n");
02402     fprintf(stderr," -b : Sort according to number of suBroutines called by a function \n");
02403     fprintf(stderr," -m : Sort according to Milliseconds (exclusive time total)\n");
02404     fprintf(stderr," -t : Sort according to Total milliseconds (inclusive time total)  (default)\n");
02405     fprintf(stderr," -e : Sort according to Exclusive time per call (msec/call)\n");
02406     fprintf(stderr," -i : Sort according to Inclusive time per call (total msec/call)\n");
02407     fprintf(stderr," -v : Sort according to Standard Deviation (excl usec)\n");
02408     fprintf(stderr," -r : Reverse sorting order\n");
02409     fprintf(stderr," -s : print only Summary profile information \n");
02410     fprintf(stderr," -n <num> : print only first <num> number of functions \n");
02411     fprintf(stderr," -f filename : specify full path and Filename without node ids\n");
02412     fprintf(stderr," -l : List all functions and exit\n");
02413     fprintf(stderr," [node numbers] : prints only info about all contexts/threads of given node numbers\n");
02414 
02415         
02416     exit (1);
02417   }
02418 
02419   /* ASSUMPTION : Dynamic profiling and long file names are coupled. We'd always
02420   have profile.n.c.t with it - new file format */
02421 
02422   if(optind == argc) 
02423     start = 0; 
02424   else 
02425     start = atoi(argv[optind]);
02426 
02427   sprintf(proffile,"%s.%d.0.0", file, start);
02428 
02429   if (!dump) { // This statement not in the dump protocol 
02430     printf("Reading Profile files in %s.*\n", file);
02431   } 
02432 
02433   if (IsDynamicProfiling(proffile)) { /* we don't need to read .ftab files */
02434 
02435 
02436     if ( optind == argc) {  
02437     /* files not specified by specific node nos list  on cmdline */
02438       for(argno = 0; FillFunctionDBInNode(argno, 0, 0, file); argno++) ;
02439     }
02440     else { /* 4 45 68 ... - process this list of node nos. */
02441       for (argno = optind; argno < argc; argno++)
02442         FillFunctionDBInNode(atoi(argv[argno]), 0, 0, file);
02443     }
02444 
02445     numfunc = funcDB.size(); /* sets global number of functions */
02446 
02447     InitFuncNameBuf();
02448     /* funcnamebuf and functagbuf are initialized here */
02449 
02450     if (list)  {
02451       DumpFunctionNamesInDB();  /* for debugging purposes */
02452       exit(0); 
02453     } 
02454     else if (dump) { /* NOTE : Using TEMPLATED_FUNCTIONS as sig to RACY */
02455      // DumpFtabFile(file);
02456     /* used by racy - but here there's no depfile - for compatibility only */
02457       printf ("default.dep\n%d templated_functions\n", numfunc);
02458     }
02459 
02460     /* Process the files for data - second pass */
02461     /* iterate over nodes, contexts and threads */
02462     if ( optind == argc ) {
02463       for (argno = 0; ProcessFileDynamicInNode(argno, 0, 0, max, file); argno++);
02464     }
02465     else {
02466       for (argno = optind; argno < argc; argno++)
02467         ProcessFileDynamicInNode (atoi(argv[argno]), 0, 0,  max, file);
02468       argno -= optind;
02469     }
02470     if (files_processed > 0) PrintSummary (max, files_processed);
02471 
02472     exit(0);
02473   /* End of Dynamic Profiling */
02474   } else { /* static profiling using .ftab .ctab files */
02475 
02476     ReadNameTable (file); 
02477     /* read profile.ftab file and register function names*/
02478 
02479     ReadEventTable (file); /* for hpc++ */
02480     if ( list ) {
02481       printf ("%s:\n", depfile);
02482       for (i=0; i<numfunc; i++) {
02483         if ( functagbuf[i] > 0 )
02484           printf ("%5d  %s\n", functagbuf[i], funcnamebuf[i]);
02485       }
02486       exit (0); /* exit after printing list */
02487     } else if ( dump ) {
02488       printf ("%s\n%d functions\n", depfile, numfunc);
02489     }
02490   }
02491 
02492   
02493 
02494   sprintf(proffile,"%s.%d", file,start);
02495   if(IsFilePresent(proffile))
02496   { /* pc++ files - profile.0, etc. Use ctx 0, thr 0 and longname = FALSE */
02497     if ( optind == argc ) {
02498       for (argno = 0; ProcessFile(argno, 0, 0, FALSE,  max, file, TRUE); argno++);
02499     }
02500     else {
02501       for (argno = optind; argno < argc; argno++)
02502         ProcessFile (atoi(argv[argno]), 0, 0, FALSE, max, file, FALSE);
02503       argno -= optind;
02504     }
02505   /* pc++ format - we know how many files were processed */
02506   if ( argno ) PrintSummary (max, argno);
02507   }
02508   else 
02509   {
02510     sprintf(proffile,"%s.%d.0.0", file, start);
02511     if (IsFilePresent(proffile))
02512     { /* hpc++ files profile.0.0.0 present  - use longnames = TRUE */
02513     
02514       /* iterate over nodes, contexts and threads */
02515       if ( optind == argc ) {
02516         for (argno = 0; ProcessFileInNode(argno, 0, 0, TRUE,  max, file, TRUE); argno++);
02517       }
02518       else {
02519         for (argno = optind; argno < argc; argno++)
02520           ProcessFileInNode (atoi(argv[argno]), 0, 0, TRUE, max, file, TRUE);
02521         argno -= optind;
02522         /* Note: since we're iterating, we cannot use ignore as FALSE for
02523         hpc++ (it searches for files) */
02524       }
02525       if (files_processed > 0) PrintSummary (max, files_processed);
02526     }
02527     else
02528     { 
02529      /* both profile.0 and profile.0.0.0 not found */
02530         printf("Error : profile file %s not found",proffile);
02531         exit(1);
02532     }
02533   }
02534 
02535 
02536   exit (0);
02537 }
02538 /***************************************************************************
02539  * $RCSfile: pprof.cpp,v $   $Author: adelmann $
02540  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:32 $
02541  * IPPL_VERSION_ID: $Id: pprof.cpp,v 1.1.1.1 2003/01/23 07:40:32 adelmann Exp $                                                   
02542  ***************************************************************************/
02543 

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