#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 ACE_Timeprobe_Ex::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 ACE_Timeprobe_Ex:: 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 ACE_Timeprobe_Ex::ACE_Timeprobe_Ex (const ACE_Timeprobe_Ex &) { // // Stupid MSVC is forcing me to define this; please don't use it. // ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("ACE_NOTSUP: %N, line %l\n"))); errno = ENOTSUP; } template ACE_Timeprobe_Ex::~ACE_Timeprobe_Ex () { ACE_DES_ARRAY_FREE ((ACE_timeprobe_t *) (this->timeprobes_), this->max_size_, this->allocator ()->free, ACE_timeprobe_t); } template void ACE_Timeprobe_Ex::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 void ACE_Timeprobe_Ex::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 void ACE_Timeprobe_Ex::reset () { ACE_GUARD (ACE_LOCK, ace_mon, this->lock_); this->current_size_ = 0; this->report_buffer_full_ = 0; } template void ACE_Timeprobe_Ex::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 ACE_Unbounded_Set & ACE_Timeprobe_Ex::event_descriptions () { return this->event_descriptions_; } template ACE_Unbounded_Set & ACE_Timeprobe_Ex::sorted_event_descriptions () { return this->sorted_event_descriptions_; } template ACE_timeprobe_t * ACE_Timeprobe_Ex::timeprobes () { return this->timeprobes_; } template ACE_LOCK & ACE_Timeprobe_Ex::lock () { return this->lock_; } template u_long ACE_Timeprobe_Ex::max_size () { return this->max_size_; } template u_long ACE_Timeprobe_Ex::current_size () { return this->current_size_; } template int ACE_Timeprobe_Ex::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 void ACE_Timeprobe_Ex::print_times () { 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_; ACELIB_DEBUG ((LM_DEBUG, "\nACE_Timeprobe_Ex; %u timestamps were recorded:\n", size)); if (size == 0) return; ACELIB_DEBUG ((LM_DEBUG, "\n%-50.50s %8.8s %13.13s\n\n", "Event", "thread", "usec")); ACE_High_Res_Timer::global_scale_factor_type gsf = ACE_High_Res_Timer::global_scale_factor (); u_long i, j; // First element i = this->report_buffer_full_ ? this->current_size_ : 0; ACELIB_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; ACELIB_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; ACELIB_DEBUG ((LM_DEBUG, "\nWARNING: The timestamps recorded by gethrtime() on" " this platform are\n" "not monotonic across different threads.\n")); } } template void ACE_Timeprobe_Ex::print_absolute_times () { 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_; ACELIB_DEBUG ((LM_DEBUG, "\nACE_Timeprobe_Ex; %u timestamps were recorded:\n", size)); if (size == 0) return; ACELIB_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_); ACELIB_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 const char * ACE_Timeprobe_Ex::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 void ACE_Timeprobe_Ex::sort_event_descriptions_i () { 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 ALLOCATOR * ACE_Timeprobe_Ex::allocator () { return allocator_ ? allocator_ : ACE_Singleton::instance (); } template ACE_Function_Timeprobe::ACE_Function_Timeprobe (Timeprobe &timeprobe, u_long event) : timeprobe_ (timeprobe), event_ (event) { this->timeprobe_.timeprobe (this->event_); } template ACE_Function_Timeprobe::~ACE_Function_Timeprobe () { this->timeprobe_.timeprobe (this->event_ + 1); } ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_COMPILE_TIMEPROBES */ #endif /* ACE_TIMEPROBE_T_CPP */