diff options
Diffstat (limited to 'ACE/ace/Timeprobe_T.cpp')
-rw-r--r-- | ACE/ace/Timeprobe_T.cpp | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/ACE/ace/Timeprobe_T.cpp b/ACE/ace/Timeprobe_T.cpp new file mode 100644 index 00000000000..dcb1edbb791 --- /dev/null +++ b/ACE/ace/Timeprobe_T.cpp @@ -0,0 +1,427 @@ +// $Id$ + +#ifndef ACE_TIMEPROBE_T_CPP +#define ACE_TIMEPROBE_T_CPP + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_COMPILE_TIMEPROBES) + +#include "ace/Timeprobe.h" +#include "ace/High_Res_Timer.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template <class ACE_LOCK, class ALLOCATOR> +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::ACE_Timeprobe_Ex (u_long size) + : timeprobes_ (0), + lock_ (), + max_size_ (size), + current_size_ (0), + report_buffer_full_ (0), + allocator_ (0) +{ + ACE_timeprobe_t *temp; + //FUZZ: disable check_for_lack_ACE_OS + ACE_NEW_MALLOC_ARRAY (temp, + (ACE_timeprobe_t *) this->allocator ()-> + malloc (this->max_size_*sizeof(ACE_timeprobe_t)), + ACE_timeprobe_t, + this->max_size_); + //FUZZ: enable check_for_lack_ACE_OS + this->timeprobes_ = temp; + +} + +template <class ACE_LOCK, class ALLOCATOR> +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>:: +ACE_Timeprobe_Ex (ALLOCATOR *allocator, + u_long size) + : timeprobes_ (0), + lock_ (), + max_size_ (size), + current_size_ (0), + report_buffer_full_ (0), + allocator_ (allocator) +{ + ACE_timeprobe_t *temp = 0; + //FUZZ: disable check_for_lack_ACE_OS + ACE_NEW_MALLOC_ARRAY (temp, + (ACE_timeprobe_t *) this->allocator ()-> + malloc (this->max_size_*sizeof(ACE_timeprobe_t)), + ACE_timeprobe_t, + this->max_size_); + //FUZZ: enable check_for_lack_ACE_OS + this->timeprobes_ = temp; + +} + +template <class ACE_LOCK, class ALLOCATOR> +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::ACE_Timeprobe_Ex (const ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR> &) +{ + // + // Stupid MSVC is forcing me to define this; please don't use it. + // + + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("ACE_NOTSUP: %N, line %l\n"))); + errno = ENOTSUP; +} + +template <class ACE_LOCK, class ALLOCATOR> +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::~ACE_Timeprobe_Ex (void) +{ + ACE_DES_ARRAY_FREE ((ACE_timeprobe_t *) (this->timeprobes_), + this->max_size_, + this->allocator ()->free, + ACE_timeprobe_t); +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::timeprobe (u_long event) +{ + ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); + + this->timeprobes_[this->current_size_].event_.event_number_ = event; + this->timeprobes_[this->current_size_].event_type_ = ACE_timeprobe_t::NUMBER; + this->timeprobes_[this->current_size_].time_ = ACE_OS::gethrtime (); + this->timeprobes_[this->current_size_].thread_ = ACE_OS::thr_self (); + + ++this->current_size_; + +#if !defined (ACE_TIMEPROBE_ASSERTS_FIXED_SIZE) + // wrap around to the beginning on overflow + if (this->current_size_ >= this->max_size_) + { + this->current_size_ = 0; + this->report_buffer_full_ = 1; + } +#endif /* ACE_TIMEPROBE_ASSERTS_FIXED_SIZE */ + + ACE_ASSERT (this->current_size_ < this->max_size_); +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::timeprobe (const char *event) +{ + ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); + + this->timeprobes_[this->current_size_].event_.event_description_ = event; + this->timeprobes_[this->current_size_].event_type_ = ACE_timeprobe_t::STRING; + this->timeprobes_[this->current_size_].time_ = ACE_OS::gethrtime (); + this->timeprobes_[this->current_size_].thread_ = ACE_OS::thr_self (); + + ++this->current_size_; + +#if !defined (ACE_TIMEPROBE_ASSERTS_FIXED_SIZE) + // wrap around to the beginning on overflow + if (this->current_size_ >= this->max_size_) + { + this->current_size_ = 0; + this->report_buffer_full_ = 1; + } +#endif /* ACE_TIMEPROBE_ASSERTS_FIXED_SIZE */ + + ACE_ASSERT (this->current_size_ < this->max_size_); +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::reset (void) +{ + ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); + + this->current_size_ = 0; + this->report_buffer_full_ = 0; +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::increase_size (u_long size) +{ + ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); + + if (size > this->max_size_) + { + ACE_timeprobe_t *temp = 0; + //FUZZ: disable check_for_lack_ACE_OS + ACE_NEW_MALLOC_ARRAY (temp, + (ACE_timeprobe_t *) this->allocator ()-> + malloc (this->max_size_ + * sizeof (ACE_timeprobe_t)), + ACE_timeprobe_t, + size); + //FUZZ: enable check_for_lack_ACE_OS + + if (this->max_size_ > 0) + { + ACE_OS::memcpy (temp, + this->timeprobes_, + this->max_size_ * sizeof (ACE_timeprobe_t)); + + // Iterates over the array explicitly calling the destructor for + // each probe instance, then deallocates the memory + + ACE_DES_ARRAY_FREE ((ACE_timeprobe_t *)(this->timeprobes_), + this->max_size_, + this->allocator ()->free, + ACE_timeprobe_t); + } + this->timeprobes_ = temp; + this->max_size_ = size; + } +} + +template <class ACE_LOCK, class ALLOCATOR> ACE_Unbounded_Set<ACE_Event_Descriptions> & +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::event_descriptions (void) +{ + return this->event_descriptions_; +} + +template <class ACE_LOCK, class ALLOCATOR> ACE_Unbounded_Set<ACE_Event_Descriptions> & +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::sorted_event_descriptions (void) +{ + return this->sorted_event_descriptions_; +} + +template <class ACE_LOCK, class ALLOCATOR> ACE_timeprobe_t * +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::timeprobes (void) +{ + return this->timeprobes_; +} + +template <class ACE_LOCK, class ALLOCATOR> ACE_LOCK & +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::lock (void) +{ + return this->lock_; +} + +template <class ACE_LOCK, class ALLOCATOR> u_long +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::max_size (void) +{ + return this->max_size_; +} + +template <class ACE_LOCK, class ALLOCATOR> u_long +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::current_size (void) +{ + return this->current_size_; +} + +template <class ACE_LOCK, class ALLOCATOR> int +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::event_descriptions (const char **descriptions, + u_long minimum_id) +{ + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1); + + ACE_Event_Descriptions events; + events.descriptions_ = descriptions; + events.minimum_id_ = minimum_id; + + this->event_descriptions_.insert (events); + + return 0; +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::print_times (void) +{ + ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); + + // Sort the event descriptions + this->sort_event_descriptions_i (); + + u_long size = this->report_buffer_full_ ? this->max_size_ + : this->current_size_; + + ACE_DEBUG ((LM_DEBUG, + "\nACE_Timeprobe_Ex; %u timestamps were recorded:\n", + size)); + + if (size == 0) + return; + + ACE_DEBUG ((LM_DEBUG, + "\n%-50.50s %8.8s %13.13s\n\n", + "Event", + "thread", + "usec")); + + double gsf = ACE_High_Res_Timer::global_scale_factor (); + u_long i, j; + + // First element + i = this->report_buffer_full_ ? this->current_size_ : 0; + + ACE_DEBUG ((LM_DEBUG, + "%-50.50s %8.8x %13.13s\n", + this->find_description_i (i), + this->timeprobes_[i].thread_, + "START")); + + if (size == 1) + return; + + bool has_timestamp_inversion = false; + + j = i; + i = (i + 1) % this->max_size_; + + do + { + // When reusing the same ACE_Timeprobe from multiple threads + // with Linux on Intel SMP, it sometimes happens that the + // recorded times go backward in time if they are recorded from + // different threads (see bugzilla #2342). To obtain the + // correct signed difference between consecutive recorded times, + // one has to cast the time difference to an intermediate signed + // integral type of the same size as ACE_hrtime_t. + + double time_difference = + (ACE_INT64) (this->timeprobes_[i].time_ - this->timeprobes_[j].time_); + + if (time_difference < 0) + has_timestamp_inversion = true; + + // Convert to microseconds. + time_difference /= gsf; + + ACE_DEBUG ((LM_DEBUG, + "%-50.50s %8.8x %14.3f\n", + this->find_description_i (i), + this->timeprobes_[i].thread_, + time_difference)); + + j = i; + i = (i + 1) % this->max_size_; + } + while (i != this->current_size_); + + static bool inversion_warning_printed = false; + if (!inversion_warning_printed && has_timestamp_inversion) + { + inversion_warning_printed = true; + ACE_DEBUG ((LM_DEBUG, + "\nWARNING: The timestamps recorded by gethrtime() on" + " this platform are\n" + "not monotonic across different threads.\n")); + } +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::print_absolute_times (void) +{ + ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); + + // Sort the event descriptions + this->sort_event_descriptions_i (); + + u_long size = this->report_buffer_full_ ? this->max_size_ + : this->current_size_; + + ACE_DEBUG ((LM_DEBUG, + "\nACE_Timeprobe_Ex; %u timestamps were recorded:\n", + size)); + + if (size == 0) + return; + + ACE_DEBUG ((LM_DEBUG, + "\n%-50.50s %8.8s %13.13s\n\n", + "Event", + "thread", + "stamp")); + + u_long i = this->report_buffer_full_ ? this->current_size_ : 0; + + ACE_Time_Value tv; // to convert ACE_hrtime_t + do + { + ACE_High_Res_Timer::hrtime_to_tv (tv, this->timeprobes_ [i].time_); + + ACE_DEBUG ((LM_DEBUG, + "%-50.50s %8.8x %12.12u\n", + this->find_description_i (i), + this->timeprobes_ [i].thread_, + tv.sec () * 1000000 + + tv.usec ())); + + // Modulus increment: loops around at the end. + i = (i + 1) % this->max_size_; + } + while (i != this->current_size_); +} + +template <class ACE_LOCK, class ALLOCATOR> const char * +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::find_description_i (u_long i) +{ + if (this->timeprobes_[i].event_type_ == ACE_timeprobe_t::STRING) + return this->timeprobes_[i].event_.event_description_; + else + { + EVENT_DESCRIPTIONS::iterator iterator = this->sorted_event_descriptions_.begin (); + for (u_long j = 0; + j < this->sorted_event_descriptions_.size () - 1; + iterator++, j++) + { + EVENT_DESCRIPTIONS::iterator next_event_descriptions = iterator; + ++next_event_descriptions; + + if (this->timeprobes_[i].event_.event_number_ < (*next_event_descriptions).minimum_id_) + break; + } + return (*iterator).descriptions_[this->timeprobes_[i].event_.event_number_ - (*iterator).minimum_id_]; + } +} + +template <class ACE_LOCK, class ALLOCATOR> void +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::sort_event_descriptions_i (void) +{ + size_t total_elements = this->event_descriptions_.size (); + + for (size_t i = 0; + i < total_elements; + i++) + { + EVENT_DESCRIPTIONS::iterator iterator = this->event_descriptions_.begin (); + ACE_Event_Descriptions min_entry = *iterator; + + for (; + iterator != this->event_descriptions_.end (); + iterator++) + if ((*iterator).minimum_id_ < min_entry.minimum_id_) + min_entry = *iterator; + + this->sorted_event_descriptions_.insert (min_entry); + this->event_descriptions_.remove (min_entry); + } +} + +template <class ACE_LOCK, class ALLOCATOR> ALLOCATOR * +ACE_Timeprobe_Ex<ACE_LOCK, ALLOCATOR>::allocator (void) +{ + return allocator_ ? allocator_ : ACE_Singleton<ALLOCATOR, ACE_LOCK>::instance (); +} + +template <class Timeprobe> +ACE_Function_Timeprobe<Timeprobe>::ACE_Function_Timeprobe (Timeprobe &timeprobe, + u_long event) + : timeprobe_ (timeprobe), + event_ (event) +{ + this->timeprobe_.timeprobe (this->event_); +} + +template <class Timeprobe> +ACE_Function_Timeprobe<Timeprobe>::~ACE_Function_Timeprobe (void) +{ + this->timeprobe_.timeprobe (this->event_ + 1); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_COMPILE_TIMEPROBES */ +#endif /* ACE_TIMEPROBE_T_CPP */ |