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

read_lock_timing.C

Go to the documentation of this file.
00001 // Copyright (C) 2004, Kenneth C. Schalk
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 // read_lock_timing.C - Tool for reading and analyzing the
00020 // repository's StableLock/VolatileRootLock/userGroup_lock timing.
00021 
00022 #include "read_timing_common.H"
00023 
00024 #include <Basics.H>
00025 #include <BasicsAllocator.H>
00026 #include <BufStream.H>
00027 
00028 #include <unistd.h>
00029 #include <Atom.H>
00030 
00031 #include <list>
00032 
00033 using std::ostream;
00034 using std::ofstream;
00035 using std::cout;
00036 using std::cerr;
00037 using std::endl;
00038 using std::list;
00039 using Basics::OBufStream;
00040 
00041 enum which_lock_t
00042   {
00043     stable,
00044     volatileRoot,
00045     userGroup
00046   };
00047 
00048 void print_timeval(ostream &out, const struct timeval time)
00049 {
00050   time_t temp_secs = time.tv_sec;
00051   struct tm split_time;
00052   (void) localtime_r(&temp_secs, &split_time);
00053   char time_str_buf[512];
00054   strftime(time_str_buf, sizeof(time_str_buf),
00055            "%Y-%m-%d %H:%M:%S", &split_time);
00056   
00057   out << time_str_buf << " +" << (((double) time.tv_usec) / 1000) << " ms";
00058 }
00059 
00060 ostream &operator<<(ostream &out, const struct timeval time)
00061 {
00062   print_timeval(out, time);
00063   return out;
00064 }
00065 
00066 struct Lock_Data
00067 {
00068   struct FileFormatError {};
00069   which_lock_t lock;
00070   struct timeval start_time;
00071   Delta_Time time_to_acquire;
00072   bool acquired;
00073   bool write;
00074   Delta_Time time_held;
00075   Delta_Time time_to_release;
00076   Atom *reason;
00077 
00078   Lock_Data(which_lock_t lock)
00079     : lock(lock), reason(0)
00080   {
00081   }
00082 
00083   void read_start_time(FILE *input) throw(FS::EndOfFile)
00084   {
00085     // Start time
00086     unsigned int start_secs, start_usecs;
00087     size_t n_read =
00088       fread((void *) &start_secs, sizeof(unsigned int), 1, input);
00089     if(n_read < 1)
00090       {
00091         throw FS::EndOfFile();
00092       }
00093     assert(n_read == 1);
00094     n_read =
00095       fread((void *) &start_usecs, sizeof(unsigned int), 1, input);
00096     if(n_read < 1)
00097       {
00098         throw FS::EndOfFile();
00099       }
00100     assert(n_read == 1);
00101 
00102     start_time.tv_sec = start_secs;
00103     start_time.tv_usec = start_usecs;
00104   }
00105 
00106   void read_reason(FILE *input) throw(FS::EndOfFile)
00107   {
00108     char small_buf[1024];
00109     char *cur_buf = small_buf;
00110     unsigned int cur_buf_size = sizeof(small_buf);
00111     unsigned int buf_pos = 0;
00112     int next_char;
00113     while((next_char = getc(input)) != EOF)
00114       {
00115         // Expand buffer if needed
00116         if(buf_pos >= cur_buf_size)
00117           {
00118             cur_buf_size *= 2;
00119             char * new_buf =  NEW_PTRFREE_ARRAY(char, cur_buf_size);
00120             memcpy(new_buf, cur_buf, buf_pos);
00121             cur_buf = new_buf;
00122           }
00123         cur_buf[buf_pos++] = next_char;
00124         if(next_char == 0)
00125           break;
00126       }
00127 
00128     reason = NEW_CONSTR(Atom, (cur_buf));
00129   }
00130 
00131   bool read_record(FILE *input) throw(FS::EndOfFile, FileFormatError)
00132   {
00133     bool result = false;
00134     int record_byte = getc(input);
00135     switch(record_byte)
00136       {
00137       case 1:
00138         // acquireRead start
00139         write = false;
00140         read_start_time(input);
00141         break;
00142       case 2:
00143         // acquireRead completed
00144         acquired = true;
00145         time_to_acquire.read(input);
00146         break;
00147       case 3:
00148         // tryRead failed
00149         acquired = false;
00150         result = true;
00151         time_to_acquire.read(input);
00152         break;
00153       case 4:
00154         // acquireWrite start
00155         write = true;
00156         read_start_time(input);
00157         break;
00158       case 5:
00159         // acquireWrite completed
00160         acquired = true;
00161         time_to_acquire.read(input);
00162         break;
00163       case 6:
00164         // tryWrite failed
00165         acquired = false;
00166         result = true;
00167         time_to_acquire.read(input);
00168         break;
00169       case 7:
00170         // release start
00171         time_held.read(input);
00172         break;
00173       case 8:
00174         // release completed
00175         result = true;
00176         time_to_release.read(input);
00177         break;
00178       case 9:
00179         // reason
00180         read_reason(input);
00181         break;
00182       default:
00183         // WTF?
00184         throw FileFormatError();
00185       }
00186 
00187     return result;
00188   }
00189 
00190   void print_lock_info(ostream &out, const char *indent,
00191                        const struct timeval *beginning = 0) const
00192   {
00193     out << indent;
00194     switch(lock)
00195       {
00196       case stable:
00197         out << "StableLock.";
00198         break;
00199       case volatileRoot:
00200         out << "VolatileRootLock.";
00201         break;
00202       case userGroup:
00203         out << "userGroup_lock.";
00204         break;
00205       }
00206     out << (acquired?"acquire":"try") << (write?"Write":"Read") << "():"
00207         << endl;
00208     if(beginning != 0)
00209       {
00210         if(start_time < *beginning)
00211           {
00212             Delta_Time start_delta = (*beginning - start_time);
00213             out << indent << "  start:        -" << start_delta.msecs()
00214                 << " ms" << endl;
00215           }
00216         else
00217           {
00218             Delta_Time start_delta = (start_time - *beginning);
00219             out << indent << "  start:        " << start_delta.msecs()
00220                 << " ms" << endl;
00221           }
00222       }
00223     else
00224       {
00225         out << indent << "  start:        " << start_time << endl;
00226       }
00227     out << indent << "  acquire time: " << time_to_acquire.msecs() << " ms"
00228         << endl;
00229     if(acquired)
00230       {
00231         out 
00232           << indent << "  hold time:    " << time_held.msecs() << " ms" << endl
00233           << indent << "  release time: " << time_to_release.msecs() << " ms"
00234           << endl;
00235       }
00236     if(reason != 0)
00237       {
00238         out
00239           << indent << "  reason:       " << reason->cchars() << endl;
00240       }
00241   }
00242 
00243   void plot_lock_info(unsigned int x_val,
00244                       ostream &acquire_stream,
00245                       ostream &hold_stream,
00246                       ostream &release_stream,
00247                       const struct timeval &beginning) const
00248   {
00249     double my_acquire_start;
00250     if(start_time < beginning)
00251       {
00252         Delta_Time start_delta = (beginning - start_time);
00253         my_acquire_start = -(start_delta.msecs());
00254       }
00255     else
00256       {
00257         Delta_Time start_delta = (start_time - beginning);
00258         my_acquire_start = start_delta.msecs();
00259       }
00260 
00261     double my_acquire_delta = time_to_acquire.msecs();
00262     double my_hold_start = (my_acquire_start + my_acquire_delta);
00263     double my_hold_delta = time_held.msecs();
00264     double my_release_start = (my_hold_start + my_hold_delta);
00265     double my_release_delta = time_to_release.msecs();
00266 
00267     // Each of the data files gets four columns:
00268     // 1: X value
00269     // 2: Y center point
00270     // 3: Y min
00271     // 4: Y max
00272 
00273     acquire_stream << x_val << " "
00274                    << (my_acquire_start + (my_acquire_delta/2)) << " "
00275                    << my_acquire_start << " "
00276                    << my_hold_start << endl;
00277 
00278     if(acquired)
00279       {
00280         hold_stream << x_val << " "
00281                     << (my_hold_start + (my_hold_delta/2)) << " "
00282                     << my_hold_start << " "
00283                     << my_release_start << endl;
00284 
00285         release_stream << x_val << " "
00286                        << (my_release_start + (my_release_delta/2)) << " "
00287                        << my_release_start << " "
00288                        << (my_release_start + my_release_delta) << endl;
00289       }
00290   }
00291 
00292   bool operator<=(const Lock_Data & other) const
00293   {
00294     // Earlier start time: we're lesser
00295     if(this->start_time < other.start_time)
00296       {
00297         return true;
00298       }
00299     // Same start time: compare acquire times
00300     if(this->start_time == other.start_time)
00301       {
00302         return (other.time_to_acquire >= this->time_to_acquire);
00303       }
00304 
00305     return false;
00306   }
00307 };
00308 
00309 typedef list<const Lock_Data *,
00310              Basics::Allocator<Lock_Data *> > Lock_Event_List;
00311 
00312 void sorted_lock_insert(Lock_Event_List &lock_list,
00313                         const Lock_Data *lock)
00314 {
00315   assert(lock != 0);
00316 
00317   for(Lock_Event_List::iterator it = lock_list.begin();
00318       it != lock_list.end();
00319       it++)
00320     {
00321       // Found it's place: insert it here and return.
00322       if(*lock <= *(*it))
00323         {
00324           lock_list.insert(it, lock);
00325           return;
00326         }
00327     }
00328 
00329   // Didn't find a place for this one: add it to the end.
00330   lock_list.push_back(lock);
00331 }
00332 
00333 // This class represents sets of ranges of time.  These are used to
00334 // collect the times during which some particular event occurs so that
00335 // it's possible to locate other events that overlap in time with the
00336 // event of interest.
00337 
00338 struct Time_Ranges
00339 {
00340   struct time_range
00341   {
00342     struct timeval start_time, end_time;
00343     time_range()
00344     {
00345       start_time.tv_sec = 0;
00346       start_time.tv_usec = 0;
00347       end_time.tv_sec = 0;
00348       end_time.tv_usec = 0;
00349     }
00350     time_range(const struct timeval &start, const Delta_Time &delta)
00351       : start_time(start), end_time(start + delta)
00352     {
00353     }
00354     time_range(const struct time_range &other)
00355     {
00356       start_time.tv_sec = other.start_time.tv_sec;
00357       start_time.tv_usec = other.start_time.tv_usec;
00358       end_time.tv_sec = other.end_time.tv_sec;
00359       end_time.tv_usec = other.end_time.tv_usec;
00360     }
00361 
00362     inline bool overlaps_end_of(const struct time_range &other) const throw()
00363     {
00364       return ((this->start_time <= other.end_time) &&
00365               (other.end_time <= this->end_time));
00366     }
00367 
00368     inline bool overlaps_start_of(const struct time_range &other) const throw()
00369     {
00370       return ((this->start_time <= other.start_time) &&
00371               (other.start_time <= this->end_time));
00372     }
00373 
00374     inline bool contains(const struct time_range &other) const throw()
00375     {
00376       return overlaps_end_of(other) && overlaps_start_of(other);
00377     }
00378 
00379     inline bool contained_by(const struct time_range &other) const throw()
00380     {
00381       return other.contains(*this);
00382     }
00383 
00384     time_range &operator=(const struct time_range &other)
00385     {
00386       start_time.tv_sec = other.start_time.tv_sec;
00387       start_time.tv_usec = other.start_time.tv_usec;
00388       end_time.tv_sec = other.end_time.tv_sec;
00389       end_time.tv_usec = other.end_time.tv_usec;
00390 
00391       return *this;
00392     }
00393 
00394     struct time_range merge(const struct time_range &other)
00395     {
00396       struct time_range result;
00397 
00398       // When merging, there should be some overlap.
00399       assert(this->overlaps_end_of(other) ||
00400              this->overlaps_start_of(other) ||
00401              other.overlaps_end_of(*this) ||
00402              other.overlaps_start_of(*this));
00403 
00404       if(other.start_time < this->start_time)
00405         {
00406           result.start_time = other.start_time;
00407         }
00408       else
00409         {
00410           result.start_time = this->start_time;
00411         }
00412 
00413       if(other.end_time < this->end_time)
00414         {
00415           result.end_time = this->end_time;
00416         }
00417       else
00418         {
00419           result.end_time = other.end_time;
00420         }
00421 
00422       return result;
00423     }
00424   };
00425 
00426   typedef list<time_range> time_range_list;
00427   time_range_list ranges;
00428 
00429   // Add a time range to this set
00430   void add_range(const struct timeval &start, const Delta_Time &delta)
00431   {
00432     time_range new_range(start, delta);
00433 
00434     bool added = false;
00435 
00436     for(time_range_list::iterator it = ranges.begin();
00437         !added && (it != ranges.end());
00438         it++)
00439       {
00440         // Overlaps the end of current item: merge with current item.
00441         // (Note that this includes the case where the new range
00442         // completely contains the current range.
00443         if(new_range.overlaps_end_of(*it))
00444           {
00445             time_range merged = (*it).merge(new_range);
00446             *it = merged;
00447             added = true;
00448 
00449             // Check new range for overlap with following ranges
00450             bool done = false;
00451             while(1)
00452               {
00453                 time_range_list::iterator it_next = it;
00454                 it_next++;
00455                 if(it_next == ranges.end())
00456                   {
00457                     break;
00458                   }
00459 
00460                 if((*it).overlaps_start_of(*it_next))
00461                   {
00462                     if(!(*it).overlaps_end_of(*it_next))
00463                       {
00464                         // Partial overlap: merge before erasing.
00465                         merged = (*it).merge(*it_next);
00466                         *it = merged;
00467                       }
00468                     ranges.erase(it_next);
00469                   }
00470                 else
00471                   {
00472                     // Invariant: non-verlapping ranges are sequential
00473                     assert((*it).end_time < (*it_next).start_time);
00474                     break;
00475                   }
00476               }
00477           }
00478         // Overlaps with the start of current item: merge with
00479         // current.
00480         else if(new_range.overlaps_start_of(*it))
00481           {
00482             time_range merged = (*it).merge(new_range);
00483             *it = merged;
00484             added = true;
00485 
00486             // Note: don't need to check for overlap with previous
00487             // ranges, becuase if the new range overlapped with
00488             // them, it would have been merged with them.
00489           }
00490         // Completely contained by an existing range: do nothing.
00491         else if(new_range.contained_by(*it))
00492           {
00493             added = true;
00494           }
00495         // Earlier start than current item but no overlap: insert
00496         // before current item.
00497         else if(new_range.start_time < (*it).start_time)
00498           {
00499             ranges.insert(it, new_range);
00500             added = true;
00501           }
00502         else
00503           {
00504             // If we fall through to here, the new range must start
00505             // after the end of the current range.
00506             assert((*it).end_time < new_range.start_time);
00507           }
00508       }
00509 
00510     // Not placed before or merged with any existing item: insert it
00511     // at the end.
00512     if(!added)
00513       {
00514         ranges.push_back(new_range);
00515       }
00516   }
00517 
00518   // Test whether a time range overlaps any part of this set.
00519   bool in_range(const struct timeval &start, const Delta_Time &delta,
00520                 unsigned int &index)
00521   {
00522     if(ranges.empty())
00523       return false;
00524 
00525     time_range test_range(start, delta);
00526 
00527     // Find our starting position, which may be somewhere in the
00528     // middle.
00529     time_range_list::iterator it = ranges.begin();
00530     for(unsigned int i = 0; i < index; i++)
00531       {
00532         it++;
00533         if(it == ranges.end())
00534           return false;
00535       }
00536 
00537     // Loop over the remaining ranges looking for one that this event
00538     // falls in.
00539     while(it != ranges.end())
00540       {
00541         // Have to test for overlaps in both directions, as either
00542         // could be contained by the other.
00543         if(test_range.overlaps_start_of(*it) ||
00544            test_range.overlaps_end_of(*it) ||
00545            (*it).overlaps_start_of(test_range) ||
00546            (*it).overlaps_end_of(test_range))
00547           {
00548             return true;
00549           }
00550         else
00551           {
00552             // Time ranegs must be disjoint
00553             assert((test_range.end_time < (*it).start_time) ||
00554                    ((*it).end_time < test_range.start_time));
00555           }
00556 
00557         // Increment ourselves through the list of ranges.
00558         it++; index++;
00559       }
00560 
00561     // Didn't find an overlap: not in the set.
00562     return false;
00563   }
00564 
00565   void print(ostream &out, const char *indent,
00566              const Lock_Event_List *events = 0) const
00567   {
00568     unsigned int index = 0;
00569     for(time_range_list::const_iterator it = ranges.begin();
00570         it != ranges.end();
00571         it++, index++)
00572       {
00573         Delta_Time duration = ((*it).end_time - (*it).start_time);
00574         out << indent << "range " << index << ":" << endl
00575             << indent << "  start:    " << (*it).start_time << endl
00576             << indent << "  end:      " << (*it).end_time << endl
00577             << indent << "  duration: " << duration.msecs() << " ms" << endl;
00578 
00579         if(events != 0)
00580           {
00581             out << endl;
00582             Text sub_indent(indent);
00583             sub_indent += "  ";
00584             for(Lock_Event_List::const_iterator event_it =
00585                   events[index].begin();
00586                 event_it != events[index].end();
00587                 event_it++)
00588               {
00589                 (*event_it)->print_lock_info(out, sub_indent.cchars(),
00590                                              &((*it).start_time));
00591               }
00592           }
00593       }
00594   }
00595 
00596   void gen_plot(const Text &title_prefix,
00597                 const Text &basename,
00598                 const Lock_Event_List *events) const
00599   {
00600     unsigned int index = 0;
00601     for(time_range_list::const_iterator it = ranges.begin();
00602         it != ranges.end();
00603         it++, index++)
00604       {
00605         char range_buf[30];
00606         sprintf(range_buf, "_range%04d", index);
00607         Text ranage_base = basename+range_buf;
00608         Text cmd_fname = ranage_base+".gnuplot";
00609         Text img_name = ranage_base+".png";
00610 
00611         Text ar_data_fname = ranage_base+"_acquireRead.dat";
00612         Text hr_data_fname = ranage_base+"_holdRead.dat";
00613         Text rr_data_fname = ranage_base+"_releaseRead.dat";
00614         Text aw_data_fname = ranage_base+"_acquireWrite.dat";
00615         Text hw_data_fname = ranage_base+"_holdWrite.dat";
00616         Text rw_data_fname = ranage_base+"_releaseWrite.dat";
00617 
00618         ofstream cmd_stream(cmd_fname.cchars());
00619 
00620         if(cmd_stream.bad())
00621           {
00622             cerr << "Couldn't open \"" << cmd_fname.cchars()
00623                  << "\" for writing"
00624                  << endl;
00625             exit(1);
00626           }
00627         
00628         cmd_stream << "set title \"" << title_prefix.cchars()
00629                    << " range " << index << "\"" << endl
00630                    << "set data style yerrorbars" << endl
00631                    << "set term png color" << endl
00632                    << "set output \"" << img_name.cchars() << "\"" << endl
00633                    << "set ylabel \"time in ms\"" << endl
00634                    << "set xlabel \"time 0 = " << (*it).start_time << "\""
00635                    << endl;
00636 
00637         ofstream
00638           *ar_data_stream = 0,
00639           *hr_data_stream = 0,
00640           *rr_data_stream = 0,
00641           *aw_data_stream = 0,
00642           *hw_data_stream = 0,
00643           *rw_data_stream = 0;
00644 
00645         unsigned int x_pos = 0;
00646         for(Lock_Event_List::const_iterator event_it =
00647               events[index].begin();
00648             event_it != events[index].end();
00649             event_it++, x_pos++)
00650           {
00651             // Open the appropriate data files if we haven't already
00652             if((*event_it)->write && (aw_data_stream == 0))
00653               {
00654                 aw_data_stream = NEW_CONSTR(ofstream,
00655                                             (aw_data_fname.cchars()));
00656                 if(aw_data_stream->bad())
00657                   {
00658                     cerr << "Couldn't open \"" << aw_data_fname.cchars()
00659                          << "\" for writing"
00660                          << endl;
00661                     exit(1);
00662                   }
00663                 hw_data_stream = NEW_CONSTR(ofstream,
00664                                             (hw_data_fname.cchars()));
00665                 if(hw_data_stream->bad())
00666                   {
00667                     cerr << "Couldn't open \"" << hw_data_fname.cchars()
00668                          << "\" for writing"
00669                          << endl;
00670                     exit(1);
00671                   }
00672                 rw_data_stream = NEW_CONSTR(ofstream,
00673                                             (rw_data_fname.cchars()));
00674                 if(rw_data_stream->bad())
00675                   {
00676                     cerr << "Couldn't open \"" << rw_data_fname.cchars()
00677                          << "\" for writing"
00678                          << endl;
00679                     exit(1);
00680                   }
00681               }
00682             else if(!(*event_it)->write && (ar_data_stream == 0))
00683               {
00684                 ar_data_stream = NEW_CONSTR(ofstream,
00685                                             (ar_data_fname.cchars()));
00686                 if(ar_data_stream->bad())
00687                   {
00688                     cerr << "Couldn't open \"" << ar_data_fname.cchars()
00689                          << "\" for writing"
00690                          << endl;
00691                     exit(1);
00692                   }
00693                 hr_data_stream = NEW_CONSTR(ofstream,
00694                                             (hr_data_fname.cchars()));
00695                 if(hr_data_stream->bad())
00696                   {
00697                     cerr << "Couldn't open \"" << hr_data_fname.cchars()
00698                          << "\" for writing"
00699                          << endl;
00700                     exit(1);
00701                   }
00702                 rr_data_stream = NEW_CONSTR(ofstream,
00703                                             (rr_data_fname.cchars()));
00704                 if(rr_data_stream->bad())
00705                   {
00706                     cerr << "Couldn't open \"" << rr_data_fname.cchars()
00707                          << "\" for writing"
00708                          << endl;
00709                     exit(1);
00710                   }
00711               }
00712 
00713             // Tell the event to write appropriate data lines.
00714             (*event_it)->plot_lock_info(x_pos,
00715                                         ((*event_it)->write
00716                                          ? *aw_data_stream
00717                                          : *ar_data_stream),
00718                                         ((*event_it)->write
00719                                          ? *hw_data_stream
00720                                          : *hr_data_stream),
00721                                         ((*event_it)->write
00722                                          ? *rw_data_stream
00723                                          : *rr_data_stream),
00724                                         (*it).start_time);
00725           }
00726 
00727         cmd_stream << "plot ";
00728         if(aw_data_stream != 0)
00729           {
00730             assert(hw_data_stream != 0);
00731             assert(rw_data_stream != 0);
00732             aw_data_stream->close();
00733             hw_data_stream->close();
00734             rw_data_stream->close();
00735             delete aw_data_stream;
00736             delete hw_data_stream;
00737             delete rw_data_stream;
00738             
00739             cmd_stream << "\"" << aw_data_fname.cchars()
00740                        << "\" title \"acquireWrite\", \""
00741                        << hw_data_fname.cchars()
00742                        << "\" title \"holdWrite\", \""
00743                        << rw_data_fname.cchars()
00744                        << "\" title \"releaseWrite\"";
00745           }
00746         if(ar_data_stream != 0)
00747           {
00748             assert(hr_data_stream != 0);
00749             assert(rr_data_stream != 0);
00750             ar_data_stream->close();
00751             hr_data_stream->close();
00752             rr_data_stream->close();
00753             delete ar_data_stream;
00754             delete hr_data_stream;
00755             delete rr_data_stream;
00756 
00757             if(aw_data_stream != 0)
00758               {
00759                 cmd_stream << ", ";
00760               }
00761             cmd_stream << "\"" << ar_data_fname.cchars()
00762                        << "\" title \"acquireRead\", \""
00763                        << hr_data_fname.cchars()
00764                        << "\" title \"holdRead\", \""
00765                        << rr_data_fname.cchars()
00766                        << "\" title \"releaseRead\"";
00767           }
00768         cmd_stream << endl;
00769       }
00770   }
00771 
00772   bool empty()
00773   {
00774     return ranges.empty();
00775   }
00776 
00777   unsigned int range_count()
00778   {
00779     return ranges.size();
00780   }
00781 };
00782 
00783 static const char *program_name = 0;
00784 
00785 static void usage()
00786 {
00787   cerr << "Usage: " << program_name
00788        << " [-o <output prefix>] [-t <long acquire ms>] <lock timing file(s)>"
00789        << endl;
00790   exit(1);
00791 }
00792 
00793 int main(int argc, char * const argv[])
00794 {
00795   program_name = argv[0];
00796   const char *output_prefix = "rwlock_timing.out";
00797   unsigned int long_acquire_ms = 1000;
00798 
00799   int option;
00800   opterr = 0;
00801   while((option = getopt(argc, argv, "ho:t:")) != EOF)
00802     {
00803       switch(option)
00804         {
00805         case 'o':
00806           output_prefix = optarg;
00807           break;
00808         case 't':
00809           long_acquire_ms = atoi(optarg);
00810           break;
00811         case 'h':
00812         case '?':
00813         default:
00814           usage();
00815         }
00816     }
00817 
00818   // All "long" acquire times
00819   Time_Ranges
00820     stable_long_acquireReads,
00821     stable_long_acquireWrites,
00822     volatile_long_acquireReads,
00823     volatile_long_acquireWrites,
00824     userGroup_long_acquireReads,
00825     userGroup_long_acquireWrites;
00826 
00827   // Record holders
00828   Lock_Data
00829     *stable_longest_acquireRead = 0,
00830     *stable_longest_acquireWrite = 0,
00831     *stable_longest_held = 0,
00832     *stable_longest_release = 0,
00833     *volatile_longest_acquireRead = 0,
00834     *volatile_longest_acquireWrite = 0,
00835     *volatile_longest_held = 0,
00836     *volatile_longest_release = 0,
00837     *userGroup_longest_acquireRead = 0,
00838     *userGroup_longest_acquireWrite = 0,
00839     *userGroup_longest_held = 0,
00840     *userGroup_longest_release = 0;
00841 
00842   Delta_Time
00843     stable_total_acquireRead,
00844     stable_total_acquireWrite,
00845     stable_total_held,
00846     stable_total_release,
00847     volatile_total_acquireRead,
00848     volatile_total_acquireWrite,
00849     volatile_total_held,
00850     volatile_total_release,
00851     userGroup_total_acquireRead,
00852     userGroup_total_acquireWrite,
00853     userGroup_total_held,
00854     userGroup_total_release;
00855 
00856   unsigned int
00857     stable_count_acquireRead = 0,
00858     stable_count_acquireWrite = 0,
00859     stable_count_acquired = 0,
00860     volatile_count_acquireRead = 0,
00861     volatile_count_acquireWrite = 0,
00862     volatile_count_acquired = 0,
00863     userGroup_count_acquireRead = 0,
00864     userGroup_count_acquireWrite = 0,
00865     userGroup_count_acquired = 0;
00866 
00867   unsigned int total_count = 0;
00868 
00869   unsigned int
00870     stable_acquireRead_no_reason_count = 0,
00871     stable_acquireWrite_no_reason_count = 0,
00872     volatile_acquireRead_no_reason_count = 0,
00873     volatile_acquireWrite_no_reason_count = 0,
00874     userGroup_acquireRead_no_reason_count = 0,
00875     userGroup_acquireWrite_no_reason_count = 0;
00876 
00877   // First pass: gather general statistics and find time periods with
00878   // long acquire times.
00879 
00880   for(int arg = optind; arg < argc; arg++)
00881     {
00882       OBufStream l_cmd;
00883       l_cmd << "gunzip -q -c " << argv[arg];
00884       FILE *stream = popen(l_cmd.str(), "r");
00885       unsigned long file_count = 0;
00886 
00887       Lock_Data *cur_stable = 0, *cur_volatile = 0, *cur_userGroup = 0;
00888       try
00889         {
00890           while(1)
00891             {
00892               int lock_byte = getc(stream);
00893               if(lock_byte == EOF)
00894                 {
00895                   break;
00896                 }
00897               // StableLock record
00898               else if(lock_byte == 1)
00899                 {
00900                   if(cur_stable == 0)
00901                     {
00902                       cur_stable = NEW_CONSTR(Lock_Data, (stable));
00903                     }
00904 
00905                   bool done = cur_stable->read_record(stream);
00906 
00907                   if(done)
00908                     {
00909                       file_count++;
00910 
00911                       if(cur_stable->acquired && (cur_stable->reason == 0))
00912                         {
00913                           if(cur_stable->write)
00914                             {
00915                               stable_acquireWrite_no_reason_count++;
00916                             }
00917                           else
00918                             {
00919                               stable_acquireRead_no_reason_count++;
00920                             }
00921                         }
00922 
00923                       // Record "long" acquires
00924                       if(cur_stable->acquired &&
00925                          (cur_stable->time_to_acquire.msecs() >=
00926                           long_acquire_ms))
00927                         {
00928                           if(cur_stable->write)
00929                             {
00930                               stable_long_acquireWrites.
00931                                 add_range(cur_stable->start_time,
00932                                           cur_stable->time_to_acquire);
00933                             }
00934                           else
00935                             {
00936                               stable_long_acquireReads.
00937                                 add_range(cur_stable->start_time,
00938                                           cur_stable->time_to_acquire);
00939                             }
00940                         }
00941 
00942                       // Accumulate totals
00943                       if(cur_stable->write)
00944                         {
00945                           stable_total_acquireWrite +=
00946                             cur_stable->time_to_acquire;
00947                           stable_count_acquireWrite++;
00948                         }
00949                       else
00950                         {
00951                           stable_total_acquireRead +=
00952                             cur_stable->time_to_acquire;
00953                           stable_count_acquireRead++;
00954                         }
00955                       if(cur_stable->acquired)
00956                         {
00957                           stable_total_held += cur_stable->time_held;
00958                           stable_total_release += cur_stable->time_to_release;
00959                           stable_count_acquired++;
00960                         }
00961 
00962                       // Store record holders
00963                       if(cur_stable->write &&
00964                          (!stable_longest_acquireWrite ||
00965                           (cur_stable->time_to_acquire >
00966                            stable_longest_acquireWrite->time_to_acquire)))
00967                         {
00968                           stable_longest_acquireWrite = cur_stable;
00969                         }
00970                       if(!cur_stable->write &&
00971                          (!stable_longest_acquireRead ||
00972                           (cur_stable->time_to_acquire >
00973                            stable_longest_acquireRead->time_to_acquire)))
00974                         {
00975                           stable_longest_acquireRead = cur_stable;
00976                         }
00977                       if(cur_stable->acquired)
00978                         {
00979                           if(!stable_longest_held ||
00980                              (cur_stable->time_held >
00981                               stable_longest_held->time_held))
00982                             {
00983                               stable_longest_held = cur_stable;
00984                             }
00985                           if(!stable_longest_release ||
00986                              (cur_stable->time_to_release >
00987                               stable_longest_release->time_to_release))
00988                             {
00989                               stable_longest_release = cur_stable;
00990                             }
00991                         }
00992                          
00993                       cur_stable = 0;
00994                     }
00995                 }
00996               // VolatileRootLock record
00997               else if(lock_byte == 2)
00998                 {
00999                   if(cur_volatile == 0)
01000                     {
01001                       cur_volatile = NEW_CONSTR(Lock_Data, (volatileRoot));
01002                     }
01003 
01004                   bool done = cur_volatile->read_record(stream);
01005 
01006                   if(done)
01007                     {
01008                       file_count++;
01009 
01010                       if(cur_volatile->acquired && (cur_volatile->reason == 0))
01011                         {
01012                           if(cur_volatile->write)
01013                             {
01014                               volatile_acquireWrite_no_reason_count++;
01015                             }
01016                           else
01017                             {
01018                               volatile_acquireRead_no_reason_count++;
01019                             }
01020                         }
01021 
01022                       // Record "long" acquires
01023                       if(cur_volatile->acquired &&
01024                          (cur_volatile->time_to_acquire.msecs() >=
01025                           long_acquire_ms))
01026                         {
01027                           if(cur_volatile->write)
01028                             {
01029                               volatile_long_acquireWrites.
01030                                 add_range(cur_volatile->start_time,
01031                                           cur_volatile->time_to_acquire);
01032                             }
01033                           else
01034                             {
01035                               volatile_long_acquireReads.
01036                                 add_range(cur_volatile->start_time,
01037                                           cur_volatile->time_to_acquire);
01038                             }
01039                         }
01040 
01041                       // Accumulate totals
01042                       if(cur_volatile->write)
01043                         {
01044                           volatile_total_acquireWrite +=
01045                             cur_volatile->time_to_acquire;
01046                           volatile_count_acquireWrite++;
01047                         }
01048                       else
01049                         {
01050                           volatile_total_acquireRead +=
01051                             cur_volatile->time_to_acquire;
01052                           volatile_count_acquireRead++;
01053                         }
01054                       if(cur_volatile->acquired)
01055                         {
01056                           volatile_total_held += cur_volatile->time_held;
01057                           volatile_total_release +=
01058                             cur_volatile->time_to_release;
01059                           volatile_count_acquired++;
01060                         }
01061 
01062                       // Store record holders
01063                       if(cur_volatile->write &&
01064                          (!volatile_longest_acquireWrite ||
01065                           (cur_volatile->time_to_acquire >
01066                            volatile_longest_acquireWrite->time_to_acquire)))
01067                         {
01068                           volatile_longest_acquireWrite = cur_volatile;
01069                         }
01070                       if(!cur_volatile->write &&
01071                          (!volatile_longest_acquireRead ||
01072                           (cur_volatile->time_to_acquire >
01073                            volatile_longest_acquireRead->time_to_acquire)))
01074                         {
01075                           volatile_longest_acquireRead = cur_volatile;
01076                         }
01077                       if(cur_volatile->acquired)
01078                         {
01079                           if(!volatile_longest_held ||
01080                              (cur_volatile->time_held >
01081                               volatile_longest_held->time_held))
01082                             {
01083                               volatile_longest_held = cur_volatile;
01084                             }
01085                           if(!volatile_longest_release ||
01086                              (cur_volatile->time_to_release >
01087                               volatile_longest_release->time_to_release))
01088                             {
01089                               volatile_longest_release = cur_volatile;
01090                             }
01091                         }
01092 
01093                       cur_volatile = 0;
01094                     }
01095                 }
01096               // userGroup_lock record
01097               else if(lock_byte == 3)
01098                 {
01099                   if(cur_userGroup == 0)
01100                     {
01101                       cur_userGroup = NEW_CONSTR(Lock_Data, (userGroup));
01102                     }
01103 
01104                   bool done = cur_userGroup->read_record(stream);
01105 
01106                   if(done)
01107                     {
01108                       file_count++;
01109 
01110                       if(cur_userGroup->acquired && (cur_userGroup->reason == 0))
01111                         {
01112                           if(cur_userGroup->write)
01113                             {
01114                               userGroup_acquireWrite_no_reason_count++;
01115                             }
01116                           else
01117                             {
01118                               userGroup_acquireRead_no_reason_count++;
01119                             }
01120                         }
01121 
01122                       // Record "long" acquires
01123                       if(cur_userGroup->acquired &&
01124                          (cur_userGroup->time_to_acquire.msecs() >=
01125                           long_acquire_ms))
01126                         {
01127                           if(cur_userGroup->write)
01128                             {
01129                               userGroup_long_acquireWrites.
01130                                 add_range(cur_userGroup->start_time,
01131                                           cur_userGroup->time_to_acquire);
01132                             }
01133                           else
01134                             {
01135                               userGroup_long_acquireReads.
01136                                 add_range(cur_userGroup->start_time,
01137                                           cur_userGroup->time_to_acquire);
01138                             }
01139                         }
01140 
01141                       // Accumulate totals
01142                       if(cur_userGroup->write)
01143                         {
01144                           userGroup_total_acquireWrite +=
01145                             cur_userGroup->time_to_acquire;
01146                           userGroup_count_acquireWrite++;
01147                         }
01148                       else
01149                         {
01150                           userGroup_total_acquireRead +=
01151                             cur_userGroup->time_to_acquire;
01152                           userGroup_count_acquireRead++;
01153                         }
01154                       if(cur_userGroup->acquired)
01155                         {
01156                           userGroup_total_held += cur_userGroup->time_held;
01157                           userGroup_total_release +=
01158                             cur_userGroup->time_to_release;
01159                           userGroup_count_acquired++;
01160                         }
01161 
01162                       // Store record holders
01163                       if(cur_userGroup->write &&
01164                          (!userGroup_longest_acquireWrite ||
01165                           (cur_userGroup->time_to_acquire >
01166                            userGroup_longest_acquireWrite->time_to_acquire)))
01167                         {
01168                           userGroup_longest_acquireWrite = cur_userGroup;
01169                         }
01170                       if(!cur_userGroup->write &&
01171                          (!userGroup_longest_acquireRead ||
01172                           (cur_userGroup->time_to_acquire >
01173                            userGroup_longest_acquireRead->time_to_acquire)))
01174                         {
01175                           userGroup_longest_acquireRead = cur_userGroup;
01176                         }
01177                       if(cur_userGroup->acquired)
01178                         {
01179                           if(!userGroup_longest_held ||
01180                              (cur_userGroup->time_held >
01181                               userGroup_longest_held->time_held))
01182                             {
01183                               userGroup_longest_held = cur_userGroup;
01184                             }
01185                           if(!userGroup_longest_release ||
01186                              (cur_userGroup->time_to_release >
01187                               userGroup_longest_release->time_to_release))
01188                             {
01189                               userGroup_longest_release = cur_userGroup;
01190                             }
01191                         }
01192 
01193                       cur_userGroup = 0;
01194                     }
01195                 }
01196             }
01197         }
01198       catch(FS::EndOfFile)
01199         {
01200           // We don't care
01201         }
01202       catch(Lock_Data::FileFormatError)
01203         {
01204           cerr << "File format error reading " << argv[arg] << endl;
01205         }
01206 
01207       cout << argv[arg] << ": " << file_count << " locks" << endl;
01208       total_count +=  file_count;
01209       int gunzip_status = pclose(stream);
01210       cout << "gunzip status: " << gunzip_status << endl;
01211     }
01212 
01213   Text report_fname(output_prefix);
01214   report_fname += ".report";
01215   ofstream report(report_fname.cchars());
01216 
01217   if(report.bad())
01218     {
01219       cerr << "Couldn't open \"" << report_fname.cchars() << "\" for writing"
01220            << endl;
01221       exit(1);
01222     }
01223 
01224   report << "Total: " << total_count << " locks" << endl;
01225 
01226   report << "Acquired locks with no reason:" << endl
01227          << "  StableLock acquireRead:        "
01228          << stable_acquireRead_no_reason_count << endl
01229          << "  StableLock acquireWrite:       "
01230          << stable_acquireWrite_no_reason_count << endl
01231          << "  VolatileRootLock acquireRead:  "
01232          << volatile_acquireRead_no_reason_count << endl
01233          << "  VolatileRootLock acquireWrite: "
01234          << volatile_acquireWrite_no_reason_count << endl
01235          << "  userGroup_lock acquireRead:  "
01236          << userGroup_acquireRead_no_reason_count << endl
01237          << "  userGroup_lock acquireWrite: "
01238          << userGroup_acquireWrite_no_reason_count << endl;
01239 
01240   report << "StableLock:" << endl;
01241   if(stable_count_acquireRead > 0)
01242     {
01243       assert(stable_longest_acquireRead != 0);
01244       report
01245         << "  acquireRead/tryRead:" << endl
01246         << "    average: " << (stable_total_acquireRead.msecs() /
01247                                stable_count_acquireRead) << " ms" << endl
01248         << "    slowest: "
01249         << stable_longest_acquireRead->time_to_acquire.msecs()
01250         << " ms" << endl;
01251       if(stable_longest_acquireRead->reason)
01252         {
01253           report
01254             << "    slowest reason: "
01255             << stable_longest_acquireRead->reason->cchars() << endl;
01256         }
01257       if(!stable_long_acquireReads.empty())
01258         {
01259           report << "    long acquireRead periods:" << endl;
01260           stable_long_acquireReads.print(report, "      ");
01261         }
01262     }
01263   if(stable_count_acquireWrite > 0)
01264     {
01265       assert(stable_longest_acquireWrite != 0);
01266       report
01267         << "  acquireWrite/tryWrite:" << endl
01268         << "    average: " << (stable_total_acquireWrite.msecs() /
01269                                stable_count_acquireWrite) << " ms" << endl
01270         << "    slowest: "
01271         << stable_longest_acquireWrite->time_to_acquire.msecs()
01272         << " ms" << endl;
01273       if(stable_longest_acquireWrite->reason)
01274         {
01275           report
01276             << "    slowest reason: "
01277             << stable_longest_acquireWrite->reason->cchars() << endl;
01278         }
01279       if(!stable_long_acquireWrites.empty())
01280         {
01281           report << "    long acquireWrite periods:" << endl;
01282           stable_long_acquireWrites.print(report, "      ");
01283         }
01284     }
01285   if(stable_count_acquired > 0)
01286     {
01287       assert(stable_longest_held != 0);
01288       assert(stable_longest_release != 0);
01289       report
01290         << "  hold:" << endl
01291         << "    average: " << (stable_total_held.msecs() /
01292                                stable_count_acquired) << " ms" << endl
01293         << "    slowest: " << stable_longest_held->time_held.msecs()
01294         << " ms" << endl;
01295       if(stable_longest_held->reason)
01296         {
01297           report
01298             << "    slowest reason: "
01299             << stable_longest_held->reason->cchars() << endl;
01300         }
01301       report
01302         << "  release:" << endl
01303         << "    average: " << (stable_total_release.msecs() /
01304                                stable_count_acquired) << " ms" << endl
01305         << "    slowest: " << stable_longest_release->time_to_release.msecs()
01306         << " ms" << endl;
01307       if(stable_longest_release->reason)
01308         {
01309           report
01310             << "    slowest reason: "
01311             << stable_longest_release->reason->cchars() << endl;
01312         }
01313     }
01314   report << "VolatileRootLock:" << endl;
01315   if(volatile_count_acquireRead > 0)
01316     {
01317       assert(volatile_longest_acquireRead != 0);
01318       report
01319         << "  acquireRead/tryRead:" << endl
01320         << "    average: " << (volatile_total_acquireRead.msecs() /
01321                                volatile_count_acquireRead) << " ms" << endl
01322         << "    slowest: "
01323         << volatile_longest_acquireRead->time_to_acquire.msecs()
01324         << " ms" << endl;
01325       if(volatile_longest_acquireRead->reason)
01326         {
01327           report
01328             << "    slowest reason: "
01329             << volatile_longest_acquireRead->reason->cchars() << endl;
01330         }
01331       if(!volatile_long_acquireReads.empty())
01332         {
01333           report << "    long acquireRead periods:" << endl;
01334           volatile_long_acquireReads.print(report, "      ");
01335         }
01336     }
01337   if(volatile_count_acquireWrite > 0)
01338     {
01339       assert(volatile_longest_acquireWrite != 0);
01340       report
01341         << "  acquireWrite/tryWrite:" << endl
01342         << "    average: " << (volatile_total_acquireWrite.msecs() /
01343                                volatile_count_acquireWrite) << " ms" << endl
01344         << "    slowest: "
01345         << volatile_longest_acquireWrite->time_to_acquire.msecs()
01346         << " ms" << endl;
01347       if(volatile_longest_acquireWrite->reason)
01348         {
01349           report
01350             << "    slowest reason: "
01351             << volatile_longest_acquireWrite->reason->cchars() << endl;
01352         }
01353       if(!volatile_long_acquireWrites.empty())
01354         {
01355           report << "    long acquireWrite periods:" << endl;
01356           volatile_long_acquireWrites.print(report, "      ");
01357         }
01358     }
01359   if(volatile_count_acquired > 0)
01360     {
01361       assert(volatile_longest_held != 0);
01362       assert(volatile_longest_release != 0);
01363       report
01364         << "  hold:" << endl
01365         << "    average: " << (volatile_total_held.msecs() /
01366                                volatile_count_acquired) << " ms" << endl
01367         << "    slowest: " << volatile_longest_held->time_held.msecs()
01368         << " ms" << endl;
01369       if(volatile_longest_held->reason)
01370         {
01371           report
01372             << "    slowest reason: "
01373             << volatile_longest_held->reason->cchars() << endl;
01374         }
01375       report
01376         << "  release:" << endl
01377         << "    average: " << (volatile_total_release.msecs() /
01378                                volatile_count_acquired) << " ms" << endl
01379         << "    slowest: " << volatile_longest_release->time_to_release.msecs()
01380         << " ms" << endl;
01381       if(volatile_longest_release->reason)
01382         {
01383           report
01384             << "    slowest reason: "
01385             << volatile_longest_release->reason->cchars() << endl;
01386         }
01387     }
01388   report << "userGroup_lock [AccessControl.C]:" << endl;
01389   if(userGroup_count_acquireRead > 0)
01390     {
01391       assert(userGroup_longest_acquireRead != 0);
01392       report
01393         << "  acquireRead/tryRead:" << endl
01394         << "    average: " << (userGroup_total_acquireRead.msecs() /
01395                                userGroup_count_acquireRead) << " ms" << endl
01396         << "    slowest: "
01397         << userGroup_longest_acquireRead->time_to_acquire.msecs()
01398         << " ms" << endl;
01399       if(userGroup_longest_acquireRead->reason)
01400         {
01401           report
01402             << "    slowest reason: "
01403             << userGroup_longest_acquireRead->reason->cchars() << endl;
01404         }
01405       if(!userGroup_long_acquireReads.empty())
01406         {
01407           report << "    long acquireRead periods:" << endl;
01408           userGroup_long_acquireReads.print(report, "      ");
01409         }
01410     }
01411   if(userGroup_count_acquireWrite > 0)
01412     {
01413       assert(userGroup_longest_acquireWrite != 0);
01414       report
01415         << "  acquireWrite/tryWrite:" << endl
01416         << "    average: " << (userGroup_total_acquireWrite.msecs() /
01417                                userGroup_count_acquireWrite) << " ms" << endl
01418         << "    slowest: "
01419         << userGroup_longest_acquireWrite->time_to_acquire.msecs()
01420         << " ms" << endl;
01421       if(userGroup_longest_acquireWrite->reason)
01422         {
01423           report
01424             << "    slowest reason: "
01425             << userGroup_longest_acquireWrite->reason->cchars() << endl;
01426         }
01427       if(!userGroup_long_acquireWrites.empty())
01428         {
01429           report << "    long acquireWrite periods:" << endl;
01430           userGroup_long_acquireWrites.print(report, "      ");
01431         }
01432     }
01433   if(userGroup_count_acquired > 0)
01434     {
01435       assert(userGroup_longest_held != 0);
01436       assert(userGroup_longest_release != 0);
01437       report
01438         << "  hold:" << endl
01439         << "    average: " << (userGroup_total_held.msecs() /
01440                                userGroup_count_acquired) << " ms" << endl
01441         << "    slowest: " << userGroup_longest_held->time_held.msecs()
01442         << " ms" << endl;
01443       if(userGroup_longest_held->reason)
01444         {
01445           report
01446             << "    slowest reason: "
01447             << userGroup_longest_held->reason->cchars() << endl;
01448         }
01449       report
01450         << "  release:" << endl
01451         << "    average: " << (userGroup_total_release.msecs() /
01452                                userGroup_count_acquired) << " ms" << endl
01453         << "    slowest: " << userGroup_longest_release->time_to_release.msecs()
01454         << " ms" << endl;
01455       if(userGroup_longest_release->reason)
01456         {
01457           report
01458             << "    slowest reason: "
01459             << userGroup_longest_release->reason->cchars() << endl;
01460         }
01461     }
01462 
01463   // Second pass: find all lock events that overlap with periods of
01464   // long acquire times.
01465 
01466   Lock_Event_List
01467     *stable_long_acquireRead_events = 0,
01468     *stable_long_acquireWrite_events = 0,
01469     *volatile_long_acquireRead_events = 0,
01470     *volatile_long_acquireWrite_events = 0,
01471     *userGroup_long_acquireRead_events = 0,
01472     *userGroup_long_acquireWrite_events = 0;
01473 
01474   if(!stable_long_acquireReads.empty())
01475     {
01476       stable_long_acquireRead_events =
01477         NEW_ARRAY(Lock_Event_List, stable_long_acquireReads.range_count());
01478     }
01479   if(!stable_long_acquireWrites.empty())
01480     {
01481       stable_long_acquireWrite_events =
01482         NEW_ARRAY(Lock_Event_List, stable_long_acquireWrites.range_count());
01483     }
01484   if(!volatile_long_acquireReads.empty())
01485     {
01486       volatile_long_acquireRead_events =
01487         NEW_ARRAY(Lock_Event_List, volatile_long_acquireReads.range_count());
01488     }
01489   if(!volatile_long_acquireWrites.empty())
01490     {
01491       volatile_long_acquireWrite_events =
01492         NEW_ARRAY(Lock_Event_List, volatile_long_acquireWrites.range_count());
01493     }
01494   if(!userGroup_long_acquireReads.empty())
01495     {
01496       userGroup_long_acquireRead_events =
01497         NEW_ARRAY(Lock_Event_List, userGroup_long_acquireReads.range_count());
01498     }
01499   if(!userGroup_long_acquireWrites.empty())
01500     {
01501       userGroup_long_acquireWrite_events =
01502         NEW_ARRAY(Lock_Event_List, userGroup_long_acquireWrites.range_count());
01503     }
01504 
01505   if((stable_long_acquireRead_events == 0) &&
01506      (stable_long_acquireWrite_events == 0) &&
01507      (volatile_long_acquireRead_events == 0) &&
01508      (volatile_long_acquireWrite_events == 0) &&
01509      (userGroup_long_acquireRead_events == 0) &&
01510      (userGroup_long_acquireWrite_events == 0))
01511     {
01512       cout << "No long acquire periods: skipping second pass" << endl;
01513       return 0;
01514     }
01515 
01516   cout << "Starting second pass..." << endl;
01517   for(int arg = optind; arg < argc; arg++)
01518     {
01519       OBufStream l_cmd;
01520       l_cmd << "gunzip -q -c " << argv[arg];
01521       FILE *stream = popen(l_cmd.str(), "r");
01522 
01523       Lock_Data *cur_stable = 0, *cur_volatile = 0, *cur_userGroup = 0;
01524       try
01525         {
01526           while(1)
01527             {
01528               int lock_byte = getc(stream);
01529               if(lock_byte == EOF)
01530                 {
01531                   break;
01532                 }
01533               // StableLock record
01534               else if(lock_byte == 1)
01535                 {
01536                   if(cur_stable == 0)
01537                     {
01538                       cur_stable = NEW_CONSTR(Lock_Data, (stable));
01539                     }
01540 
01541                   bool done = cur_stable->read_record(stream);
01542 
01543                   if(done)
01544                     {
01545                       Delta_Time total_delta;
01546                       if(cur_stable->acquired)
01547                         {
01548                           total_delta = (cur_stable->time_to_acquire +
01549                                          cur_stable->time_held +
01550                                          cur_stable->time_to_release);
01551                         }
01552                       else
01553                         {
01554                           total_delta = cur_stable->time_to_acquire;
01555                         }
01556 
01557                       unsigned int index = 0;
01558                       while(stable_long_acquireReads
01559                             .in_range(cur_stable->start_time, total_delta,
01560                                       index))
01561                         {
01562                           assert(stable_long_acquireRead_events != 0);
01563                           sorted_lock_insert
01564                             (stable_long_acquireRead_events[index],
01565                              cur_stable);
01566                           // Search next from the subsequent index.
01567                           index++;
01568                         }
01569                       index = 0;
01570                       while(stable_long_acquireWrites
01571                          .in_range(cur_stable->start_time, total_delta,
01572                                    index))
01573                         {
01574                           assert(stable_long_acquireWrite_events != 0);
01575                           sorted_lock_insert
01576                             (stable_long_acquireWrite_events[index],
01577                              cur_stable);
01578                           // Search next from the subsequent index.
01579                           index++;
01580                         }
01581 
01582                       cur_stable = 0;
01583                     }
01584                 }
01585               // VolatileRootLock record
01586               else if(lock_byte == 2)
01587                 {
01588                   if(cur_volatile == 0)
01589                     {
01590                       cur_volatile = NEW_CONSTR(Lock_Data, (volatileRoot));
01591                     }
01592 
01593                   bool done = cur_volatile->read_record(stream);
01594 
01595                   if(done)
01596                     {
01597                       Delta_Time total_delta;
01598                       if(cur_volatile->acquired)
01599                         {
01600                           total_delta = (cur_volatile->time_to_acquire +
01601                                          cur_volatile->time_held +
01602                                          cur_volatile->time_to_release);
01603                         }
01604                       else
01605                         {
01606                           total_delta = cur_volatile->time_to_acquire;
01607                         }
01608 
01609                       unsigned int index = 0;
01610                       while(volatile_long_acquireReads
01611                          .in_range(cur_volatile->start_time, total_delta,
01612                                    index))
01613                         {
01614                           assert(volatile_long_acquireRead_events != 0);
01615                           sorted_lock_insert
01616                             (volatile_long_acquireRead_events[index],
01617                              cur_volatile);
01618                           // Search next from the subsequent index.
01619                           index++;
01620                         }
01621                       index = 0;
01622                       while(volatile_long_acquireWrites
01623                          .in_range(cur_volatile->start_time, total_delta,
01624                                    index))
01625                         {
01626                           assert(volatile_long_acquireWrite_events != 0);
01627                           sorted_lock_insert
01628                             (volatile_long_acquireWrite_events[index],
01629                              cur_volatile);
01630                           // Search next from the subsequent index.
01631                           index++;
01632                         }
01633 
01634                       cur_volatile = 0;
01635                     }
01636                 }
01637               // userGroup_lock record
01638               else if(lock_byte == 3)
01639                 {
01640                   if(cur_userGroup == 0)
01641                     {
01642                       cur_userGroup = NEW_CONSTR(Lock_Data, (userGroup));
01643                     }
01644 
01645                   bool done = cur_userGroup->read_record(stream);
01646 
01647                   if(done)
01648                     {
01649                       Delta_Time total_delta;
01650                       if(cur_userGroup->acquired)
01651                         {
01652                           total_delta = (cur_userGroup->time_to_acquire +
01653                                          cur_userGroup->time_held +
01654                                          cur_userGroup->time_to_release);
01655                         }
01656                       else
01657                         {
01658                           total_delta = cur_userGroup->time_to_acquire;
01659                         }
01660 
01661                       unsigned int index = 0;
01662                       while(userGroup_long_acquireReads
01663                          .in_range(cur_userGroup->start_time, total_delta,
01664                                    index))
01665                         {
01666                           assert(userGroup_long_acquireRead_events != 0);
01667                           sorted_lock_insert
01668                             (userGroup_long_acquireRead_events[index],
01669                              cur_userGroup);
01670                           // Search next from the subsequent index.
01671                           index++;
01672                         }
01673                       index = 0;
01674                       while(userGroup_long_acquireWrites
01675                          .in_range(cur_userGroup->start_time, total_delta,
01676                                    index))
01677                         {
01678                           assert(userGroup_long_acquireWrite_events != 0);
01679                           sorted_lock_insert
01680                             (userGroup_long_acquireWrite_events[index],
01681                              cur_userGroup);
01682                           // Search next from the subsequent index.
01683                           index++;
01684                         }
01685 
01686                       cur_userGroup = 0;
01687                     }
01688                 }
01689             }
01690         }
01691       catch(FS::EndOfFile)
01692         {
01693           // We don't care
01694         }
01695       catch(Lock_Data::FileFormatError)
01696         {
01697           cerr << "File format error reading " << argv[arg] << endl;
01698         }
01699 
01700       int gunzip_status = pclose(stream);
01701     }
01702 
01703   // Print events for periods with long acquire waits.
01704 
01705   if(!stable_long_acquireReads.empty())
01706     {
01707       assert(stable_long_acquireRead_events != 0);
01708       report << "Long StableLock acquireRead periods:" << endl;
01709       stable_long_acquireReads.print(report, "  ",
01710                                      stable_long_acquireRead_events);
01711 
01712       Text plot_prefix(output_prefix);
01713       plot_prefix += ".long_StableLock_acquireRead";
01714       stable_long_acquireReads
01715         .gen_plot("Long StableLock acquireRead",
01716                   plot_prefix,
01717                   stable_long_acquireRead_events);
01718     }
01719   if(!stable_long_acquireWrites.empty())
01720     {
01721       assert(stable_long_acquireWrite_events != 0);
01722       report << "Long StableLock acquireWrite periods:" << endl;
01723       stable_long_acquireWrites.print(report, "  ",
01724                                       stable_long_acquireWrite_events);
01725 
01726       Text plot_prefix(output_prefix);
01727       plot_prefix += ".long_StableLock_acquireWrite";
01728       stable_long_acquireWrites
01729         .gen_plot("Long StableLock acquireWrite",
01730                   plot_prefix,
01731                   stable_long_acquireWrite_events);
01732     }
01733   if(!volatile_long_acquireReads.empty())
01734     {
01735       assert(volatile_long_acquireRead_events != 0);
01736       report << "Long VolatileRootLock acquireRead periods:" << endl;
01737       volatile_long_acquireReads.print(report, "  ",
01738                                        volatile_long_acquireRead_events);
01739 
01740       Text plot_prefix(output_prefix);
01741       plot_prefix += ".long_VolatileRootLock_acquireRead";
01742       volatile_long_acquireReads
01743         .gen_plot("Long VolatileRootLock acquireRead",
01744                   plot_prefix,
01745                   volatile_long_acquireRead_events);
01746     }
01747   if(!volatile_long_acquireWrites.empty())
01748     {
01749       assert(volatile_long_acquireWrite_events != 0);
01750       report << "Long VolatileRootLock acquireWrite periods:" << endl;
01751       volatile_long_acquireWrites.print(report, "  ",
01752                                         volatile_long_acquireWrite_events);
01753 
01754       Text plot_prefix(output_prefix);
01755       plot_prefix += ".long_VolatileRootLock_acquireWrite";
01756       volatile_long_acquireWrites
01757         .gen_plot("Long VolatileRootLock acquireWrite",
01758                   plot_prefix,
01759                   volatile_long_acquireWrite_events);
01760     }
01761   if(!userGroup_long_acquireReads.empty())
01762     {
01763       assert(userGroup_long_acquireRead_events != 0);
01764       report << "Long userGroup_lock acquireRead periods:" << endl;
01765       userGroup_long_acquireReads.print(report, "  ",
01766                                        userGroup_long_acquireRead_events);
01767 
01768       Text plot_prefix(output_prefix);
01769       plot_prefix += ".long_userGroup_acquireRead";
01770       userGroup_long_acquireReads
01771         .gen_plot("Long userGroup_lock acquireRead",
01772                   plot_prefix,
01773                   userGroup_long_acquireRead_events);
01774     }
01775   if(!userGroup_long_acquireWrites.empty())
01776     {
01777       assert(userGroup_long_acquireWrite_events != 0);
01778       report << "Long userGroup_lock acquireWrite periods:" << endl;
01779       userGroup_long_acquireWrites.print(report, "  ",
01780                                         userGroup_long_acquireWrite_events);
01781 
01782       Text plot_prefix(output_prefix);
01783       plot_prefix += ".long_userGroup_acquireWrite";
01784       userGroup_long_acquireWrites
01785         .gen_plot("Long userGroup_lock acquireWrite",
01786                   plot_prefix,
01787                   userGroup_long_acquireWrite_events);
01788     }
01789 
01790   return 0;
01791 }

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