mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2025-11-29 17:38:24 +08:00
427 lines
12 KiB
C++
427 lines
12 KiB
C++
#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.
|
|
//
|
|
|
|
ACELIB_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_;
|
|
|
|
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 <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_;
|
|
|
|
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 <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 */
|