Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

StatCount.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Fri Apr 29 00:12:48 EDT 2005 by ken@xorian.net        
00020 //      modified on Fri Feb 27 18:54:28 PST 1998 by heydon
00021 
00022 #include <Basics.H>
00023 #include <Table.H>
00024 #include <IntKey.H>
00025 #include <Generics.H>
00026 #include "StatCount.H"
00027 
00028 using std::ostream;
00029 using std::endl;
00030 
00031 static int IdentityMap(int x) throw ()
00032 { return x; }
00033 
00034 static bool RESeqMatch(const char *string, RegExpSeq &res)
00035 {
00036   for(unsigned int i = 0; i < res.size(); i++)
00037     {
00038       Basics::RegExp *re = res.get(i);
00039       assert(re != 0);
00040       if(re->match(string))
00041         return true;
00042     }
00043   return false;
00044 }
00045 
00046 StatCount::StatCount() throw ()
00047   : numVals(0), total(0), tbl(/*sizeHint=*/ 0), histoMapName(NULL),
00048     minLoc(0), maxLoc(0),
00049     troubleEnd(troubleHigh),
00050     reportCount(0), reportCount_set(false), troubleSet()
00051 {
00052     this->histoMap = IdentityMap;
00053 }
00054 
00055 void StatCount::SetHistoMap(const char *name, int (*map)(int)) throw ()
00056 {
00057     this->histoMapName = name;
00058     this->histoMap = map;
00059 }
00060 
00061 void StatCount::AddTroubleEntry(int val, const Stat::Location *loc)
00062 {
00063   // Find the place in the troubleSet to insert this entry
00064   // (possibly at the end)
00065   troubleSet_t::iterator placement = this->troubleSet.begin();
00066   while((placement != this->troubleSet.end()) &&
00067         this->MoreTrouble((*placement).val, val))
00068     placement++;
00069 
00070   // Insert this trouble location.
00071   this->troubleSet.insert(placement, toubleLoc_t(val, loc));
00072 
00073   // Increment the count for this sourceFunc.
00074   int souceFuncCount = 0;
00075   (void) this->troubleCounts.Get(loc->get_sourceFunc(),
00076                                  /*OUT*/ souceFuncCount);
00077   this->troubleCounts.Put(loc->get_sourceFunc(),
00078                           ++souceFuncCount);
00079 }
00080 
00081 void StatCount::PruneTroubleEntries()
00082 {
00083   // Remove some "trouble" entries if we need to.
00084   while((this->troubleSet.size() > 0) &&
00085         (this->troubleCounts.Size() > this->reportCount))
00086     {
00087       // We always remove the one at the back of the list.
00088       toubleLoc_t removed = this->troubleSet.back();
00089       assert(removed.loc != 0);
00090       this->troubleSet.pop_back();
00091 
00092       // Update the count of trouble entries for this
00093       // sourceFunc in the table.
00094       int souceFuncCount;
00095       bool inTbl =
00096         this->troubleCounts.Get(removed.loc->get_sourceFunc(),
00097                                 /*OUT*/ souceFuncCount);
00098       assert(inTbl);
00099       souceFuncCount--;
00100       if(souceFuncCount > 0)
00101         {
00102           this->troubleCounts.Put(removed.loc->get_sourceFunc(),
00103                                   souceFuncCount);
00104         }
00105       else
00106         {
00107           this->troubleCounts.Delete(removed.loc->get_sourceFunc(),
00108                                      /*OUT*/ souceFuncCount);
00109         }
00110     }
00111 }
00112 
00113 void StatCount::AddVal(int val, const Stat::Location *loc) throw ()
00114 {
00115     if (this->numVals == 0) {
00116         this->minVal = this->maxVal = val;
00117         this->minLoc = this->maxLoc = loc;
00118     } else {
00119         if (val < this->minVal) {
00120             this->minVal = val;
00121             this->minLoc = loc;
00122         } else if (val > this->maxVal) {
00123             this->maxVal = val;
00124             this->maxLoc = loc;
00125         }
00126     }
00127     this->total += val;
00128     this->numVals++;
00129     IntKey key((*(this->histoMap))(val)); int cnt;
00130     if (this->tbl.Get(key, /*OUT*/ cnt)) {
00131         // already an entry in histogram table
00132         this->tbl.Put(key, cnt+1);
00133     } else {
00134         // create a new entry in histogram table
00135         this->tbl.Put(key, 1);
00136     }
00137 
00138     // If we're recording information about "troublesome" locations.
00139     if(this->reportCount_set)
00140       {
00141         // Skip any function matching one of our trouble masks.
00142         if(!RESeqMatch(loc->get_sourceFunc().cchars(), this->troubleMasks))
00143         {
00144           // We'll record this new value in the trouble set if either:
00145 
00146           // 1. We haven't met out minimum number of "trouble
00147           // functions" to report on.
00148 
00149           // 2. val is greater than the smallest value in the trouble
00150           // set.
00151           if((this->troubleCounts.Size() < this->reportCount) ||
00152              ((this->troubleSet.size() > 0) &&
00153               this->MoreTrouble(val, this->troubleSet.back().val)))
00154             {
00155               // Add an entry for this value.
00156               AddTroubleEntry(val, loc);
00157 
00158               // Prune if needed.
00159               PruneTroubleEntries();
00160             }
00161         }
00162       }
00163 }
00164 
00165 void StatCount::Merge(const StatCount &sc) throw ()
00166 {
00167     if (this->numVals == 0) {
00168         this->minVal = sc.minVal; this->minLoc = sc.minLoc;
00169         this->maxVal = sc.maxVal; this->maxLoc = sc.maxLoc;
00170     } else {
00171         if (sc.minVal < this->minVal) {
00172             this->minVal = sc.minVal;
00173             this->minLoc = sc.minLoc;
00174         }
00175         if (sc.maxVal > this->maxVal) {
00176             this->maxVal = sc.maxVal;
00177             this->maxLoc = sc.maxLoc;
00178         }
00179     }
00180     this->total += sc.total;
00181     this->numVals += sc.numVals;
00182     IntIntIter it(&(sc.tbl));
00183     IntKey key; int cnt, scCnt;
00184     while (it.Next(/*OUT*/ key, /*OUT*/ scCnt)) {
00185         assert(scCnt != 0);
00186         if (this->tbl.Get(key, /*OUT*/ cnt)) {
00187             // already an entry in histogram table
00188             this->tbl.Put(key, cnt + scCnt);
00189         } else {
00190             // create a new entry in histogram table
00191             this->tbl.Put(key, scCnt);
00192         }
00193     }
00194 
00195     // If we're keeping tracke of "troublesome" functions...
00196     if(this->reportCount_set)
00197       {
00198         // Loop over the touble set of the other StatCount
00199         for(troubleSet_t::const_iterator it = sc.troubleSet.begin();
00200             it != sc.troubleSet.end();
00201             it++)
00202           {
00203             // Skip any function matching one of our trouble masks.
00204             if(!RESeqMatch((*it).loc->get_sourceFunc().cchars(),
00205                            this->troubleMasks))
00206               continue;
00207 
00208             // If we haven't met our keep limit yet or this entry is
00209             // more trouble than our least troublesome, add it to our
00210             // troubleSet.
00211             if((this->troubleCounts.Size() < this->reportCount) ||
00212                ((this->troubleSet.size() > 0) &&
00213                 this->MoreTrouble((*it).val, this->troubleSet.back().val)))
00214               {
00215                 AddTroubleEntry((*it).val, (*it).loc);
00216               }
00217           }
00218 
00219         // Prune after adding all entries.
00220         PruneTroubleEntries();
00221       }
00222 }
00223 
00224 int StatCount::MinVal() const throw ()
00225 {
00226     if (this->numVals == 0) assert(false);
00227     return this->minVal;
00228 }
00229 
00230 int StatCount::MaxVal() const throw ()
00231 {
00232     if (this->numVals == 0) assert(false);
00233     return this->maxVal;
00234 }
00235 
00236 float StatCount::MeanVal() const throw ()
00237 {
00238     if (this->numVals == 0) assert(false);
00239     return (float)(this->total) / (float)(this->numVals);
00240 }
00241 
00242 static void SC_Indent(ostream &os, int i) throw ()
00243 {
00244     for (; i > 0; i--) os << ' ';
00245 }
00246 
00247 void StatCount::Print(ostream &os, int indent, bool printHisto,
00248   bool printMinLoc, bool printMaxLoc, bool printMean) const throw ()
00249 {
00250     SC_Indent(os, indent);
00251     if (this->numVals == 0) {
00252         os << "number = 0" << endl;
00253         return;
00254     } else if (!printMean && this->minVal == this->maxVal
00255                && this->numVals == this->total) {
00256         // in this case, all the values were 1, so only print the number
00257         os << "number = " << this->numVals << endl;
00258         return;
00259     } else {
00260         os << "number = " << this->numVals << endl;
00261         SC_Indent(os, indent);
00262         os << "min = " << this->minVal << ", mean = " <<
00263             this->MeanVal() << ", max = " << this->maxVal << endl;
00264         bool printBoth =
00265             (printMinLoc && printMaxLoc && (this->minVal == this->maxVal));
00266         if (printMinLoc && (this->minLoc != 0)) {
00267             SC_Indent(os, indent);
00268             os << (printBoth ? "Min/max" : "Min");
00269             os << " value in: " << endl;
00270             SC_Indent(os, indent+2);
00271             this->minLoc->print(os, indent+2);
00272             os << endl;
00273         }
00274         if (!printBoth && printMaxLoc && (this->maxLoc != 0)) {
00275             SC_Indent(os, indent);
00276             os << "Max value in: " << endl;
00277             SC_Indent(os, indent+2);
00278             this->maxLoc->print(os, indent+2);
00279             os << endl;
00280         }
00281     }
00282     if (printHisto) PrintHisto(os, indent);
00283     if (this->reportCount_set) PrintTrouble(os, indent);
00284 }
00285 
00286 bool StatCount::MoreTrouble(int val1, int val2)
00287 {
00288   if(this->troubleEnd == troubleHigh)
00289     {
00290       return (val1 > val2);
00291     }
00292   else
00293     {
00294       return (val1 < val2);
00295     }
00296 }
00297 
00298 extern "C"
00299 {
00300   static int IntCompare(const void *v1, const void *v2) throw ()
00301   {
00302     int *i1 = (int *)v1, *i2 = (int *)v2;
00303     return *i1 - *i2;
00304   }
00305 }
00306 
00307 void StatCount::PrintHisto(ostream &os, int indent) const throw ()
00308 {
00309     // allocate array of keys
00310     int tblSz = this->tbl.Size();
00311     int *keys = NEW_PTRFREE_ARRAY(int, tblSz);
00312     
00313     // iterate over table, filling keys array
00314     IntIntIter it(&(this->tbl));
00315     IntKey key; int val, i = 0;
00316     while (it.Next(/*OUT*/ key, /*OUT*/ val)) {
00317         keys[i++] = key.Val();
00318     }
00319     assert(i == tblSz);
00320     
00321     // sort the keys
00322     qsort(keys, tblSz, sizeof(*keys), IntCompare);
00323     
00324     // print the histogram in increasing key order
00325     int lineCnt = 0;
00326     if (this->histoMapName != NULL) {
00327         SC_Indent(os, indent);
00328         os << "Histogram mapping function: " << this->histoMapName << endl;
00329     }
00330     SC_Indent(os, indent); os << "{ ";
00331     for (i = 0; i < tblSz; i++) {
00332         IntKey key(keys[i]);
00333         bool inTbl = this->tbl.Get(key, /*OUT*/ val); assert(inTbl);
00334         if (i > 0) os << ", ";
00335         if (lineCnt >= 6) {
00336             os << endl; SC_Indent(os, indent); os << "  ";
00337             lineCnt = 0;
00338         }
00339         os << keys[i] << " -> " << val;
00340         lineCnt++;
00341     }
00342     os << " }" << endl;
00343 }
00344 
00345 void StatCount::PrintTrouble(ostream &os, int indent) const throw ()
00346 {
00347   // Print out just the sourceFuncs of the most troublesome functions,
00348   // in order of decreasing max value.
00349   SC_Indent(os, indent);
00350   os << ((this->troubleEnd == troubleHigh) ? "High " : "Low ")
00351      << this->reportCount << " functions:" << endl;
00352 
00353   TextIntTbl not_yet_printed(&this->troubleCounts, true);
00354   for(troubleSet_t::const_iterator it = this->troubleSet.begin();
00355       it != this->troubleSet.end();
00356       it++)
00357     {
00358       const Text &sourceFunc = (*it).loc->get_sourceFunc();
00359       int unused;
00360       if(not_yet_printed.Delete(sourceFunc, /*OUT*/ unused))
00361         {
00362           SC_Indent(os, indent+2);
00363           os << sourceFunc << endl;
00364         }
00365     }
00366   
00367   // Loop over the touble set, printing each entry.
00368   SC_Indent(os, indent);
00369   os << "Detailed "
00370      << ((this->troubleEnd == troubleHigh) ? "high" : "low")
00371      << " cases:" << endl;
00372 
00373   for(troubleSet_t::const_iterator it = this->troubleSet.begin();
00374       it != this->troubleSet.end();
00375       it++)
00376     {
00377       SC_Indent(os, indent+2);
00378       os << "value = " << (*it).val << endl;
00379       SC_Indent(os, indent+2);
00380       (*it).loc->print(os, indent+2);
00381       os << endl << endl;
00382     }
00383 }
00384 

Generated on Mon May 8 00:48:36 2006 for Vesta by  doxygen 1.4.2