Timeprobe_T.cpp

Go to the documentation of this file.
00001 // $Id: Timeprobe_T.cpp 80826 2008-03-04 14:51:23Z wotte $
00002 
00003 #ifndef ACE_TIMEPROBE_T_CPP
00004 #define ACE_TIMEPROBE_T_CPP
00005 
00006 #include "ace/config-all.h"
00007 
00008 #if !defined (ACE_LACKS_PRAGMA_ONCE)
00009 # pragma once
00010 #endif /* ACE_LACKS_PRAGMA_ONCE */
00011 
00012 #if defined (ACE_COMPILE_TIMEPROBES)
00013 
00014 #include "ace/Timeprobe.h"
00015 #include "ace/High_Res_Timer.h"
00016 #include "ace/OS_NS_string.h"
00017 
00018 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00019 
00020 template <class ACE_LOCK, class ALLOCATOR>
00021 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::ACE_Timeprobe_Ex (u_long size)
00022   : timeprobes_ (0),
00023     lock_ (),
00024     max_size_ (size),
00025     current_size_ (0),
00026     report_buffer_full_ (0),
00027     allocator_ (0)
00028 {
00029   ACE_timeprobe_t *temp;
00030   //FUZZ: disable check_for_lack_ACE_OS
00031   ACE_NEW_MALLOC_ARRAY (temp,
00032                         (ACE_timeprobe_t *) this->allocator ()->
00033                         malloc (this->max_size_*sizeof(ACE_timeprobe_t)),
00034                         ACE_timeprobe_t,
00035                         this->max_size_);
00036   //FUZZ: enable check_for_lack_ACE_OS
00037   this->timeprobes_ = temp;
00038 
00039 }
00040 
00041 template <class ACE_LOCK, class ALLOCATOR>
00042 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::
00043 ACE_Timeprobe_Ex (ALLOCATOR *allocator,
00044                u_long size)
00045   : timeprobes_ (0),
00046     lock_ (),
00047     max_size_ (size),
00048     current_size_ (0),
00049     report_buffer_full_ (0),
00050     allocator_ (allocator)
00051 {
00052   ACE_timeprobe_t *temp = 0;
00053   //FUZZ: disable check_for_lack_ACE_OS
00054   ACE_NEW_MALLOC_ARRAY (temp,
00055                         (ACE_timeprobe_t *) this->allocator ()->
00056                         malloc (this->max_size_*sizeof(ACE_timeprobe_t)),
00057                         ACE_timeprobe_t,
00058                         this->max_size_);
00059   //FUZZ: enable check_for_lack_ACE_OS
00060   this->timeprobes_ = temp;
00061 
00062 }
00063 
00064 template <class ACE_LOCK, class ALLOCATOR>
00065 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::ACE_Timeprobe_Ex (const ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR> &)
00066 {
00067   //
00068   // Stupid MSVC is forcing me to define this; please don't use it.
00069   //
00070 
00071   ACE_ERROR ((LM_ERROR,
00072               ACE_TEXT ("ACE_NOTSUP: %N, line %l\n")));
00073   errno = ENOTSUP;
00074 }
00075 
00076 template <class ACE_LOCK, class ALLOCATOR>
00077 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::~ACE_Timeprobe_Ex (void)
00078 {
00079   ACE_DES_ARRAY_FREE ((ACE_timeprobe_t *) (this->timeprobes_),
00080                       this->max_size_,
00081                       this->allocator ()->free,
00082                       ACE_timeprobe_t);
00083 }
00084 
00085 template <class ACE_LOCK, class ALLOCATOR> void
00086 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::timeprobe (u_long event)
00087 {
00088   ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
00089 
00090   this->timeprobes_[this->current_size_].event_.event_number_ = event;
00091   this->timeprobes_[this->current_size_].event_type_ = ACE_timeprobe_t::NUMBER;
00092   this->timeprobes_[this->current_size_].time_ = ACE_OS::gethrtime ();
00093   this->timeprobes_[this->current_size_].thread_ = ACE_OS::thr_self ();
00094 
00095   ++this->current_size_;
00096 
00097 #if !defined (ACE_TIMEPROBE_ASSERTS_FIXED_SIZE)
00098   // wrap around to the beginning on overflow
00099   if (this->current_size_ >= this->max_size_)
00100     {
00101       this->current_size_ = 0;
00102       this->report_buffer_full_ = 1;
00103     }
00104 #endif /* ACE_TIMEPROBE_ASSERTS_FIXED_SIZE */
00105 
00106   ACE_ASSERT (this->current_size_ < this->max_size_);
00107 }
00108 
00109 template <class ACE_LOCK, class ALLOCATOR> void
00110 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::timeprobe (const char *event)
00111 {
00112   ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
00113 
00114   this->timeprobes_[this->current_size_].event_.event_description_ = event;
00115   this->timeprobes_[this->current_size_].event_type_ = ACE_timeprobe_t::STRING;
00116   this->timeprobes_[this->current_size_].time_ = ACE_OS::gethrtime ();
00117   this->timeprobes_[this->current_size_].thread_ = ACE_OS::thr_self ();
00118 
00119   ++this->current_size_;
00120 
00121 #if !defined (ACE_TIMEPROBE_ASSERTS_FIXED_SIZE)
00122   // wrap around to the beginning on overflow
00123   if (this->current_size_ >= this->max_size_)
00124     {
00125       this->current_size_ = 0;
00126       this->report_buffer_full_ = 1;
00127     }
00128 #endif /* ACE_TIMEPROBE_ASSERTS_FIXED_SIZE */
00129 
00130   ACE_ASSERT (this->current_size_ < this->max_size_);
00131 }
00132 
00133 template <class ACE_LOCK, class ALLOCATOR> void
00134 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::reset (void)
00135 {
00136   ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
00137 
00138   this->current_size_ = 0;
00139   this->report_buffer_full_ = 0;
00140 }
00141 
00142 template <class ACE_LOCK, class ALLOCATOR> void
00143 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::increase_size (u_long size)
00144 {
00145   ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
00146 
00147   if (size > this->max_size_)
00148     {
00149       ACE_timeprobe_t *temp = 0;
00150       //FUZZ: disable check_for_lack_ACE_OS
00151       ACE_NEW_MALLOC_ARRAY (temp,
00152                             (ACE_timeprobe_t *) this->allocator ()->
00153                             malloc (this->max_size_
00154                                     * sizeof (ACE_timeprobe_t)),
00155                             ACE_timeprobe_t,
00156                             size);
00157       //FUZZ: enable check_for_lack_ACE_OS
00158 
00159       if (this->max_size_ > 0)
00160         {
00161           ACE_OS::memcpy (temp,
00162                           this->timeprobes_,
00163                           this->max_size_ * sizeof (ACE_timeprobe_t));
00164 
00165           // Iterates over the array explicitly calling the destructor for
00166           // each probe instance, then deallocates the memory
00167 
00168           ACE_DES_ARRAY_FREE ((ACE_timeprobe_t *)(this->timeprobes_),
00169                               this->max_size_,
00170                               this->allocator ()->free,
00171                               ACE_timeprobe_t);
00172         }
00173       this->timeprobes_ = temp;
00174       this->max_size_ = size;
00175     }
00176 }
00177 
00178 template <class ACE_LOCK, class ALLOCATOR> ACE_Unbounded_Set<ACE_Event_Descriptions> &
00179 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::event_descriptions (void)
00180 {
00181   return this->event_descriptions_;
00182 }
00183 
00184 template <class ACE_LOCK, class ALLOCATOR> ACE_Unbounded_Set<ACE_Event_Descriptions> &
00185 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::sorted_event_descriptions (void)
00186 {
00187   return this->sorted_event_descriptions_;
00188 }
00189 
00190 template <class ACE_LOCK, class ALLOCATOR> ACE_timeprobe_t *
00191 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::timeprobes (void)
00192 {
00193   return this->timeprobes_;
00194 }
00195 
00196 template <class ACE_LOCK, class ALLOCATOR> ACE_LOCK &
00197 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::lock (void)
00198 {
00199   return this->lock_;
00200 }
00201 
00202 template <class ACE_LOCK, class ALLOCATOR> u_long
00203 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::max_size (void)
00204 {
00205   return this->max_size_;
00206 }
00207 
00208 template <class ACE_LOCK, class ALLOCATOR> u_long
00209 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::current_size (void)
00210 {
00211   return this->current_size_;
00212 }
00213 
00214 template <class ACE_LOCK, class ALLOCATOR> int
00215 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::event_descriptions (const char **descriptions,
00216                                              u_long minimum_id)
00217 {
00218   ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
00219 
00220   ACE_Event_Descriptions events;
00221   events.descriptions_ = descriptions;
00222   events.minimum_id_ = minimum_id;
00223 
00224   this->event_descriptions_.insert (events);
00225 
00226   return 0;
00227 }
00228 
00229 template <class ACE_LOCK, class ALLOCATOR> void
00230 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::print_times (void)
00231 {
00232   ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
00233 
00234   // Sort the event descriptions
00235   this->sort_event_descriptions_i ();
00236 
00237   u_long size = this->report_buffer_full_ ? this->max_size_
00238                                           : this->current_size_;
00239 
00240   ACE_DEBUG ((LM_DEBUG,
00241               "\nACE_Timeprobe_Ex; %u timestamps were recorded:\n",
00242               size));
00243 
00244   if (size == 0)
00245     return;
00246 
00247   ACE_DEBUG ((LM_DEBUG,
00248               "\n%-50.50s %8.8s %13.13s\n\n",
00249               "Event",
00250               "thread",
00251               "usec"));
00252 
00253   double gsf = ACE_High_Res_Timer::global_scale_factor ();
00254   u_long i, j;
00255 
00256   // First element
00257   i = this->report_buffer_full_ ? this->current_size_ : 0;
00258 
00259   ACE_DEBUG ((LM_DEBUG,
00260               "%-50.50s %8.8x %13.13s\n",
00261               this->find_description_i (i),
00262               this->timeprobes_[i].thread_,
00263               "START"));
00264 
00265   if (size == 1)
00266     return;
00267 
00268   bool has_timestamp_inversion = false;
00269 
00270   j = i;
00271   i = (i + 1) % this->max_size_;
00272 
00273   do
00274     {
00275       // When reusing the same ACE_Timeprobe from multiple threads
00276       // with Linux on Intel SMP, it sometimes happens that the
00277       // recorded times go backward in time if they are recorded from
00278       // different threads (see bugzilla #2342).  To obtain the
00279       // correct signed difference between consecutive recorded times,
00280       // one has to cast the time difference to an intermediate signed
00281       // integral type of the same size as ACE_hrtime_t.
00282 
00283       double time_difference =
00284         (ACE_INT64) (this->timeprobes_[i].time_ - this->timeprobes_[j].time_);
00285 
00286       if (time_difference < 0)
00287         has_timestamp_inversion = true;
00288 
00289       // Convert to microseconds.
00290       time_difference /= gsf;
00291 
00292       ACE_DEBUG ((LM_DEBUG,
00293                   "%-50.50s %8.8x %14.3f\n",
00294                   this->find_description_i (i),
00295                   this->timeprobes_[i].thread_,
00296                   time_difference));
00297 
00298       j = i;
00299       i = (i + 1) % this->max_size_;
00300     }
00301   while (i != this->current_size_);
00302 
00303   static bool inversion_warning_printed = false;
00304   if (!inversion_warning_printed && has_timestamp_inversion)
00305     {
00306       inversion_warning_printed = true;
00307       ACE_DEBUG ((LM_DEBUG,
00308                   "\nWARNING: The timestamps recorded by gethrtime() on"
00309                   " this platform are\n"
00310                   "not monotonic across different threads.\n"));
00311     }
00312 }
00313 
00314 template <class ACE_LOCK, class ALLOCATOR> void
00315 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::print_absolute_times (void)
00316 {
00317   ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
00318 
00319   // Sort the event descriptions
00320   this->sort_event_descriptions_i ();
00321 
00322   u_long size = this->report_buffer_full_ ? this->max_size_
00323                                           : this->current_size_;
00324 
00325   ACE_DEBUG ((LM_DEBUG,
00326               "\nACE_Timeprobe_Ex; %u timestamps were recorded:\n",
00327               size));
00328 
00329   if (size == 0)
00330     return;
00331 
00332   ACE_DEBUG ((LM_DEBUG,
00333               "\n%-50.50s %8.8s %13.13s\n\n",
00334               "Event",
00335               "thread",
00336               "stamp"));
00337 
00338   u_long i = this->report_buffer_full_ ? this->current_size_ : 0;
00339 
00340   ACE_Time_Value tv; // to convert ACE_hrtime_t
00341   do
00342     {
00343       ACE_High_Res_Timer::hrtime_to_tv (tv, this->timeprobes_ [i].time_);
00344 
00345       ACE_DEBUG ((LM_DEBUG,
00346                   "%-50.50s %8.8x %12.12u\n",
00347                   this->find_description_i (i),
00348                   this->timeprobes_ [i].thread_,
00349                   tv.sec () * 1000000
00350                    + tv.usec ()));
00351 
00352       // Modulus increment: loops around at the end.
00353       i = (i + 1) % this->max_size_;
00354     }
00355   while (i != this->current_size_);
00356 }
00357 
00358 template <class ACE_LOCK, class ALLOCATOR> const char *
00359 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::find_description_i (u_long i)
00360 {
00361   if (this->timeprobes_[i].event_type_ == ACE_timeprobe_t::STRING)
00362     return this->timeprobes_[i].event_.event_description_;
00363   else
00364     {
00365       EVENT_DESCRIPTIONS::iterator iterator = this->sorted_event_descriptions_.begin ();
00366       for (u_long j = 0;
00367            j < this->sorted_event_descriptions_.size () - 1;
00368            iterator++, j++)
00369         {
00370           EVENT_DESCRIPTIONS::iterator next_event_descriptions = iterator;
00371           ++next_event_descriptions;
00372 
00373           if (this->timeprobes_[i].event_.event_number_ < (*next_event_descriptions).minimum_id_)
00374             break;
00375         }
00376       return (*iterator).descriptions_[this->timeprobes_[i].event_.event_number_ - (*iterator).minimum_id_];
00377     }
00378 }
00379 
00380 template <class ACE_LOCK, class ALLOCATOR> void
00381 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::sort_event_descriptions_i (void)
00382 {
00383   size_t total_elements = this->event_descriptions_.size ();
00384 
00385   for (size_t i = 0;
00386        i < total_elements;
00387        i++)
00388     {
00389       EVENT_DESCRIPTIONS::iterator iterator = this->event_descriptions_.begin ();
00390       ACE_Event_Descriptions min_entry = *iterator;
00391 
00392       for (;
00393            iterator != this->event_descriptions_.end ();
00394            iterator++)
00395         if ((*iterator).minimum_id_ < min_entry.minimum_id_)
00396           min_entry = *iterator;
00397 
00398       this->sorted_event_descriptions_.insert (min_entry);
00399       this->event_descriptions_.remove (min_entry);
00400     }
00401 }
00402 
00403 template <class ACE_LOCK, class ALLOCATOR> ALLOCATOR *
00404 ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::allocator (void)
00405 {
00406   return allocator_ ? allocator_ : ACE_Singleton<ALLOCATOR, ACE_LOCK>::instance ();
00407 }
00408 
00409 template <class Timeprobe>
00410 ACE_Function_Timeprobe<Timeprobe>::ACE_Function_Timeprobe (Timeprobe &timeprobe,
00411                                                            u_long event)
00412   : timeprobe_ (timeprobe),
00413     event_ (event)
00414 {
00415   this->timeprobe_.timeprobe (this->event_);
00416 }
00417 
00418 template <class Timeprobe>
00419 ACE_Function_Timeprobe<Timeprobe>::~ACE_Function_Timeprobe (void)
00420 {
00421   this->timeprobe_.timeprobe (this->event_ + 1);
00422 }
00423 
00424 ACE_END_VERSIONED_NAMESPACE_DECL
00425 
00426 #endif /* ACE_COMPILE_TIMEPROBES */
00427 #endif /* ACE_TIMEPROBE_T_CPP */

Generated on Tue Feb 2 17:18:43 2010 for ACE by  doxygen 1.4.7