| Index: base/tracked_objects.cc
|
| diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
|
| index 56b44c10b2c389fbb053bee442769c0eda51941a..659d421017e7c7ce9e071b8554c927f2a35ec323 100644
|
| --- a/base/tracked_objects.cc
|
| +++ b/base/tracked_objects.cc
|
| @@ -237,6 +237,9 @@ void Births::Clear() { birth_count_ = 0; }
|
| // static
|
| NowFunction* ThreadData::now_function_ = NULL;
|
|
|
| +// static
|
| +bool ThreadData::now_function_is_time_ = false;
|
| +
|
| // A TLS slot which points to the ThreadData instance for the current thread. We
|
| // do a fake initialization here (zeroing out data), and then the real in-place
|
| // construction happens when we call tls_index_.Initialize().
|
| @@ -269,7 +272,8 @@ ThreadData::ThreadData(const std::string& suggested_name)
|
| : next_(NULL),
|
| next_retired_worker_(NULL),
|
| worker_thread_number_(0),
|
| - incarnation_count_for_pool_(-1) {
|
| + incarnation_count_for_pool_(-1),
|
| + current_stopwatch_(NULL) {
|
| DCHECK_GE(suggested_name.size(), 0u);
|
| thread_name_ = suggested_name;
|
| PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
|
| @@ -279,7 +283,8 @@ ThreadData::ThreadData(int thread_number)
|
| : next_(NULL),
|
| next_retired_worker_(NULL),
|
| worker_thread_number_(thread_number),
|
| - incarnation_count_for_pool_(-1) {
|
| + incarnation_count_for_pool_(-1),
|
| + current_stopwatch_(NULL) {
|
| CHECK_GT(thread_number, 0);
|
| base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
|
| PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
|
| @@ -434,7 +439,9 @@ Births* ThreadData::TallyABirth(const Location& location) {
|
|
|
| void ThreadData::TallyADeath(const Births& birth,
|
| int32 queue_duration,
|
| - int32 run_duration) {
|
| + const TaskStopwatch& stopwatch) {
|
| + int32 run_duration = stopwatch.RunDurationMs();
|
| +
|
| // Stir in some randomness, plus add constant in case durations are zero.
|
| const int32 kSomePrimeNumber = 2147483647;
|
| random_number_ += queue_duration + run_duration + kSomePrimeNumber;
|
| @@ -443,9 +450,13 @@ void ThreadData::TallyADeath(const Births& birth,
|
|
|
| // We don't have queue durations without OS timer. OS timer is automatically
|
| // used for task-post-timing, so the use of an alternate timer implies all
|
| - // queue times are invalid.
|
| - if (kAllowAlternateTimeSourceHandling && now_function_)
|
| + // queue times are invalid, unless it was explicitly said that we can trust
|
| + // the alternate timer.
|
| + if (kAllowAlternateTimeSourceHandling &&
|
| + now_function_ &&
|
| + !now_function_is_time_) {
|
| queue_duration = 0;
|
| + }
|
|
|
| DeathMap::iterator it = death_map_.find(&birth);
|
| DeathData* death_data;
|
| @@ -481,8 +492,7 @@ Births* ThreadData::TallyABirthIfActive(const Location& location) {
|
| // static
|
| void ThreadData::TallyRunOnNamedThreadIfTracking(
|
| const base::TrackingInfo& completed_task,
|
| - const TrackedTime& start_of_run,
|
| - const TrackedTime& end_of_run) {
|
| + const TaskStopwatch& stopwatch) {
|
| if (!kTrackAllTaskObjects)
|
| return; // Not compiled in.
|
|
|
| @@ -492,7 +502,7 @@ void ThreadData::TallyRunOnNamedThreadIfTracking(
|
| const Births* birth = completed_task.birth_tally;
|
| if (!birth)
|
| return;
|
| - ThreadData* current_thread_data = Get();
|
| + ThreadData* current_thread_data = stopwatch.GetThreadData();
|
| if (!current_thread_data)
|
| return;
|
|
|
| @@ -501,23 +511,20 @@ void ThreadData::TallyRunOnNamedThreadIfTracking(
|
| // get a time value since we "weren't tracking" and we were trying to be
|
| // efficient by not calling for a genuine time value. For simplicity, we'll
|
| // use a default zero duration when we can't calculate a true value.
|
| + TrackedTime start_of_run = stopwatch.StartTime();
|
| int32 queue_duration = 0;
|
| - int32 run_duration = 0;
|
| if (!start_of_run.is_null()) {
|
| queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
|
| .InMilliseconds();
|
| - if (!end_of_run.is_null())
|
| - run_duration = (end_of_run - start_of_run).InMilliseconds();
|
| }
|
| - current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
|
| + current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
|
| }
|
|
|
| // static
|
| void ThreadData::TallyRunOnWorkerThreadIfTracking(
|
| const Births* birth,
|
| const TrackedTime& time_posted,
|
| - const TrackedTime& start_of_run,
|
| - const TrackedTime& end_of_run) {
|
| + const TaskStopwatch& stopwatch) {
|
| if (!kTrackAllTaskObjects)
|
| return; // Not compiled in.
|
|
|
| @@ -536,25 +543,22 @@ void ThreadData::TallyRunOnWorkerThreadIfTracking(
|
| // other thread that might like to run). Also, the worker threads tasks are
|
| // generally longer, and hence the cost of the lock may perchance be amortized
|
| // over the long task's lifetime.
|
| - ThreadData* current_thread_data = Get();
|
| + ThreadData* current_thread_data = stopwatch.GetThreadData();
|
| if (!current_thread_data)
|
| return;
|
|
|
| + TrackedTime start_of_run = stopwatch.StartTime();
|
| int32 queue_duration = 0;
|
| - int32 run_duration = 0;
|
| if (!start_of_run.is_null()) {
|
| queue_duration = (start_of_run - time_posted).InMilliseconds();
|
| - if (!end_of_run.is_null())
|
| - run_duration = (end_of_run - start_of_run).InMilliseconds();
|
| }
|
| - current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
|
| + current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
|
| }
|
|
|
| // static
|
| void ThreadData::TallyRunInAScopedRegionIfTracking(
|
| const Births* birth,
|
| - const TrackedTime& start_of_run,
|
| - const TrackedTime& end_of_run) {
|
| + const TaskStopwatch& stopwatch) {
|
| if (!kTrackAllTaskObjects)
|
| return; // Not compiled in.
|
|
|
| @@ -564,15 +568,12 @@ void ThreadData::TallyRunInAScopedRegionIfTracking(
|
| if (!birth)
|
| return;
|
|
|
| - ThreadData* current_thread_data = Get();
|
| + ThreadData* current_thread_data = stopwatch.GetThreadData();
|
| if (!current_thread_data)
|
| return;
|
|
|
| int32 queue_duration = 0;
|
| - int32 run_duration = 0;
|
| - if (!start_of_run.is_null() && !end_of_run.is_null())
|
| - run_duration = (end_of_run - start_of_run).InMilliseconds();
|
| - current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
|
| + current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
|
| }
|
|
|
| // static
|
| @@ -758,18 +759,12 @@ bool ThreadData::TrackingParentChildStatus() {
|
| }
|
|
|
| // static
|
| -TrackedTime ThreadData::NowForStartOfRun(const Births* parent) {
|
| +void ThreadData::PrepareForStartOfRun(const Births* parent) {
|
| if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) {
|
| ThreadData* current_thread_data = Get();
|
| if (current_thread_data)
|
| current_thread_data->parent_stack_.push(parent);
|
| }
|
| - return Now();
|
| -}
|
| -
|
| -// static
|
| -TrackedTime ThreadData::NowForEndOfRun() {
|
| - return Now();
|
| }
|
|
|
| // static
|
| @@ -858,6 +853,85 @@ void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
|
| }
|
|
|
| //------------------------------------------------------------------------------
|
| +TaskStopwatch::TaskStopwatch()
|
| + : start_time_(ThreadData::Now()),
|
| + current_thread_data_(ThreadData::Get()),
|
| + excluded_duration_ms_(0),
|
| + parent_(NULL) {
|
| +#if DCHECK_IS_ON
|
| + state_ = RUNNING;
|
| + child_ = NULL;
|
| +#endif
|
| +
|
| + wallclock_duration_ms_ = 0;
|
| + if (!current_thread_data_)
|
| + return;
|
| +
|
| + parent_ = current_thread_data_->current_stopwatch_;
|
| +#if DCHECK_IS_ON
|
| + if (parent_) {
|
| + DCHECK(parent_->state_ == RUNNING);
|
| + DCHECK(parent_->child_ == NULL);
|
| + parent_->child_ = this;
|
| + }
|
| +#endif
|
| + current_thread_data_->current_stopwatch_ = this;
|
| +}
|
| +
|
| +TaskStopwatch::~TaskStopwatch() {
|
| +#if DCHECK_IS_ON
|
| + DCHECK(state_ != RUNNING);
|
| + DCHECK(child_ == NULL);
|
| +#endif
|
| +}
|
| +
|
| +void TaskStopwatch::Stop() {
|
| + const TrackedTime end_time = ThreadData::Now();
|
| +#if DCHECK_IS_ON
|
| + DCHECK(state_ == RUNNING);
|
| + state_ = STOPPED;
|
| + DCHECK(child_ == NULL);
|
| +#endif
|
| +
|
| + if (!start_time_.is_null() && !end_time.is_null()) {
|
| + wallclock_duration_ms_ = (end_time - start_time_).InMilliseconds();
|
| + }
|
| +
|
| + if (!current_thread_data_)
|
| + return;
|
| +
|
| + DCHECK(current_thread_data_->current_stopwatch_ == this);
|
| + current_thread_data_->current_stopwatch_ = parent_;
|
| + if (!parent_)
|
| + return;
|
| +
|
| +#if DCHECK_IS_ON
|
| + DCHECK(parent_->state_ == RUNNING);
|
| + DCHECK(parent_->child_ == this);
|
| + parent_->child_ = NULL;
|
| +#endif
|
| + parent_->excluded_duration_ms_ +=
|
| + wallclock_duration_ms_;
|
| + parent_ = NULL;
|
| +}
|
| +
|
| +TrackedTime TaskStopwatch::StartTime() const {
|
| + return start_time_;
|
| +}
|
| +
|
| +int32 TaskStopwatch::RunDurationMs() const {
|
| +#if DCHECK_IS_ON
|
| + DCHECK(state_ == STOPPED);
|
| +#endif
|
| +
|
| + return wallclock_duration_ms_ - excluded_duration_ms_;
|
| +}
|
| +
|
| +ThreadData* TaskStopwatch::GetThreadData() const {
|
| + return current_thread_data_;
|
| +}
|
| +
|
| +//------------------------------------------------------------------------------
|
| TaskSnapshot::TaskSnapshot() {
|
| }
|
|
|
|
|