Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

instrumentation.c

Go to the documentation of this file.
00001 /*
00002  * instrumentation.c
00003  *
00004  * Copyright (c) 2003, 2004 The University of Utah and the Flux Group.
00005  * All rights reserved.
00006  *
00007  * This file is licensed under the terms of the GNU Public License.  
00008  * See the file "license.terms" for restrictions on redistribution 
00009  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
00010  */
00011 
00012 /**
00013  * @file instrumentation.c
00014  *
00015  * Implementation of the functions in instrumentation.h.
00016  */
00017 
00018 #include "config.h"
00019 
00020 #include <math.h>
00021 #include <time.h>
00022 #include <sys/types.h>
00023 #include <sys/param.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <float.h>
00027 #include <assert_pp.h>
00028 
00029 #include "instrumentation.h"
00030 
00031 /**
00032  * Add an amount to an existing index into the ip_History.data array of the
00033  * iPoint structure.  In case the addition causes the index to extend beyond
00034  * the bounds of the array, the result will be wrapped around to the beginning.
00035  *
00036  * @param ip A pointer to a valid iPoint.
00037  * @param amount The amount to add to the ip_History.start value.
00038  * @return The new index.
00039  */
00040 #define IP_HISTORY_START_ADD(ip, amount) \
00041     ((ip)->ip_History.start + (amount)) % (ip)->ip_History.length
00042 
00043 /**
00044  * The default file name format for the instrumentation file.
00045  */
00046 static const char *DEFAULT_INSTRUMENTATION_FILE_NAME =
00047     PACKAGE "-instrumentation-%d.txt";
00048 
00049 struct iInstrumentationData instrumentation_data;
00050 
00051 /**
00052  * Initialize an instrumentation point and add it to the list of active points.
00053  * Normally, a point starts out with all fields initialized to zero, unless a
00054  * history array is provided.  We must then perform some additional setup by
00055  * assigning default values to some fields.
00056  *
00057  * @param ip The point to initialize.
00058  *
00059  * @todo Make thread safe.
00060  */
00061 static void iInitPoint(struct iPoint *ip)
00062 {
00063     require(ip != NULL);
00064     require(ip->ip_Name != NULL);
00065 
00066     /* Assign default values and */
00067     ip->ip_Minimum = FLT_MAX;
00068     ip->ip_Maximum = FLT_MIN;
00069     if( ip->ip_Format == NULL )
00070     {
00071         ip->ip_Format = "%10.2f  ";
00072     }
00073     /* ... link the point into the global list. */
00074     if( ip->ip_Succ == NULL )
00075     {
00076         if( instrumentation_data.iid_FirstPoint == NULL )
00077         {
00078             instrumentation_data.iid_FirstPoint =
00079                 &instrumentation_data.iid_NullPoint;
00080         }
00081         ip->ip_Succ = instrumentation_data.iid_FirstPoint;
00082         instrumentation_data.iid_FirstPoint = ip;
00083     }
00084 }
00085 
00086 void iPostFloatData(struct iPoint *ip, double value)
00087 {
00088     require(ip != NULL);
00089     require(ip->ip_Name != NULL);
00090 
00091     /* Check if we need to do any initialization, */
00092     if( ip->ip_Count == 0 )
00093     {
00094         iInitPoint(ip);
00095     }
00096     /* ... try to record the value in the history, and */
00097     if( ip->ip_History.data != NULL )
00098     {
00099         if( ip->ip_Count >= ip->ip_History.length )
00100         {
00101             ip->ip_History.lost += 1;
00102             if( ip->ip_Flags & IPF_DROP_HISTORY_START )
00103             {
00104                 ip->ip_History.data[ip->ip_History.start] = value;
00105                 ip->ip_History.start = IP_HISTORY_START_ADD(ip, 1);
00106             }
00107         }
00108         else
00109         {
00110             ip->ip_History.data[ip->ip_Count] = value;
00111         }
00112     }
00113     /* ... update the statistics. */
00114     ip->ip_Count += 1;
00115     ip->ip_Total += value;
00116     if( value < ip->ip_Minimum )
00117     {
00118         ip->ip_Minimum = value;
00119     }
00120     if( value > ip->ip_Maximum )
00121     {
00122         ip->ip_Maximum = value;
00123     }
00124 }
00125 
00126 void iPrintPoint(FILE *file, struct iPoint *ip)
00127 {
00128     double stddev = 0.0;
00129     
00130     require(file != NULL);
00131     require(ip != NULL);
00132     require(ip->ip_Name != NULL);
00133     require(ip->ip_Format != NULL);
00134     require(ip->ip_Count > 0);
00135     require((ip->ip_Flags & ~IPF_MASK) == 0);
00136 
00137     /* Print the summary for just the history array or */
00138     if( ip->ip_History.data != NULL )
00139     {
00140         double minimum = FLT_MAX, maximum = FLT_MIN, total = 0.0, avg;
00141         double stddev_total = 0.0;
00142         int lpc;
00143 
00144         /* Analyze the data posted to the history, */
00145         for( lpc = 0;
00146              (lpc < ip->ip_Count) && (lpc < ip->ip_History.length);
00147              lpc++ )
00148         {
00149             double value = ip->ip_History.data[IP_HISTORY_START_ADD(ip, lpc)];
00150 
00151             if( value < minimum )
00152             {
00153                 minimum = value;
00154             }
00155             if( value > maximum )
00156             {
00157                 maximum = value;
00158             }
00159             total += value;
00160         }
00161         avg = total / ((double)lpc);
00162         for( lpc = 0;
00163              (lpc < ip->ip_Count) && (lpc < ip->ip_History.length);
00164              lpc++ )
00165         {
00166             double value = ip->ip_History.data[IP_HISTORY_START_ADD(ip, lpc)];
00167 
00168             stddev_total += (value - avg) * (value - avg);
00169         }
00170         stddev = sqrt(stddev_total / ((double)lpc));
00171         /* ... give the user the summary, and */
00172         fprintf(file,
00173                 "%s: "
00174                 "count=%d/%qd total=%f min=%f max=%f avg=%f stddev=%f '%s'\n",
00175                 ip->ip_Name,
00176                 lpc, ip->ip_Count,
00177                 total,
00178                 minimum,
00179                 maximum,
00180                 avg,
00181                 stddev,
00182                 ip->ip_Description != NULL ? ip->ip_Description : "");
00183         /* ... possibly the whole history. */
00184         if( ip->ip_Flags & IPF_PRINT_HISTORY )
00185         {
00186             int lpc;
00187             
00188             if( ip->ip_History.lost > 0 )
00189             {
00190                 fprintf(file,
00191                         "\tLost %d data points at the start\n",
00192                         ip->ip_History.lost);
00193             }
00194             for( lpc = 0;
00195                  (lpc < ip->ip_Count) && (lpc < ip->ip_History.length);
00196                  )
00197             {
00198                 int row_count;
00199                 
00200                 fprintf(file, "\t");
00201                 for( row_count = 0;
00202                      (row_count < 5) &&
00203                          (lpc < ip->ip_Count) &&
00204                          (lpc < ip->ip_History.length);
00205                      row_count++, lpc++ )
00206                 {
00207                     fprintf(file,
00208                             ip->ip_Format,
00209                             ip->ip_History.data[IP_HISTORY_START_ADD(ip,
00210                                                                      lpc)]);
00211                 }
00212                 fprintf(file, "\n");
00213             }
00214         }
00215     }
00216     /* ... all of the data that has been posted. */
00217     else
00218     {
00219         fprintf(file,
00220                 "%s: count=%qd total=%f min=%f max=%f avg=%f '%s'\n",
00221                 ip->ip_Name,
00222                 ip->ip_Count,
00223                 ip->ip_Total,
00224                 ip->ip_Minimum,
00225                 ip->ip_Maximum,
00226                 ip->ip_Total / ((double)ip->ip_Count),
00227                 ip->ip_Description != NULL ? ip->ip_Description : "");
00228     }
00229 }
00230 
00231 void iPrintPoints(FILE *file)
00232 {
00233     struct iPoint *ip;
00234     
00235     require(file != NULL);
00236 
00237     /* Print all active points. */
00238     ip = instrumentation_data.iid_FirstPoint;
00239     while( (ip != NULL) && (ip != &instrumentation_data.iid_NullPoint) )
00240     {
00241         iPrintPoint(file, ip);
00242         ip = ip->ip_Succ;
00243     }
00244 }
00245 
00246 void iPrintPointsAtExit(void)
00247 {
00248     /* Make sure there are some points to print out. */
00249     if( instrumentation_data.iid_FirstPoint != NULL )
00250     {
00251         const char *file_name;
00252         FILE *file;
00253 
00254         /* Check for a user specified file name, otherwise */
00255         if( ((file_name = getenv(INSTR_FILE_NAME_ENV)) != NULL) ||
00256             ((file_name = instrumentation_data.iid_OutputFileName) != NULL) )
00257         {
00258             if( strcmp("-", file_name) == 0 )
00259             {
00260                 file = stdout;
00261             }
00262             else
00263             {
00264                 file = fopen(file_name, "a");
00265             }
00266         }
00267         /* ... use the default format. */
00268         else
00269         {
00270             static char formatted_filename[PATH_MAX];
00271             
00272             sprintf(formatted_filename,
00273                     DEFAULT_INSTRUMENTATION_FILE_NAME,
00274                     getpid());
00275             file = fopen(formatted_filename, "a");
00276         }
00277 
00278         /* Try to write to the file. */
00279         if( file != NULL )
00280         {
00281             time_t cl;
00282 
00283             cl = time(NULL);
00284             fprintf(file, "\n** %s", ctime(&cl));
00285             iPrintPoints(file);
00286             fclose(file);
00287         }
00288         else
00289         {
00290             fprintf(stderr,
00291                     "Warning: unable to create instrumentation file.\n");
00292         }
00293 
00294         /* Finally, clear the list so we do not repeatedly print the points. */
00295         instrumentation_data.iid_FirstPoint = NULL;
00296     }
00297 }

Generated on Fri Oct 22 07:50:24 2004 for CPU Broker by  doxygen 1.3.9.1