blob: 54dc1b56928c13d702fc2db0217c78a42656903f [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
#include <algorithm>
namespace blink {
namespace scheduler {
ThreadLoadTracker::ThreadLoadTracker(base::TimeTicks now,
const Callback& callback,
base::TimeDelta reporting_interval)
: time_(now),
thread_state_(ThreadState::kPaused),
last_state_change_time_(now),
reporting_interval_(reporting_interval),
callback_(callback) {
next_reporting_time_ = now + reporting_interval_;
}
ThreadLoadTracker::~ThreadLoadTracker() = default;
void ThreadLoadTracker::Pause(base::TimeTicks now) {
Advance(now, TaskState::kIdle);
thread_state_ = ThreadState::kPaused;
Reset(now);
}
void ThreadLoadTracker::Resume(base::TimeTicks now) {
Advance(now, TaskState::kIdle);
thread_state_ = ThreadState::kActive;
Reset(now);
}
void ThreadLoadTracker::Reset(base::TimeTicks now) {
last_state_change_time_ = now;
next_reporting_time_ = now + reporting_interval_;
run_time_inside_window_ = base::TimeDelta();
}
void ThreadLoadTracker::RecordTaskTime(base::TimeTicks start_time,
base::TimeTicks end_time) {
start_time = std::max(last_state_change_time_, start_time);
end_time = std::max(last_state_change_time_, end_time);
Advance(start_time, TaskState::kIdle);
Advance(end_time, TaskState::kTaskRunning);
}
void ThreadLoadTracker::RecordIdle(base::TimeTicks now) {
Advance(now, TaskState::kIdle);
}
namespace {
// Calculates length of intersection of two time intervals.
base::TimeDelta Intersection(base::TimeTicks left1,
base::TimeTicks right1,
base::TimeTicks left2,
base::TimeTicks right2) {
DCHECK_LT(left1, right1);
DCHECK_LT(left2, right2);
base::TimeTicks left = std::max(left1, left2);
base::TimeTicks right = std::min(right1, right2);
if (left <= right)
return right - left;
return base::TimeDelta();
}
} // namespace
void ThreadLoadTracker::Advance(base::TimeTicks now, TaskState task_state) {
// This function advances |time_| to now and calls |callback_|
// when appropriate.
DCHECK_LE(time_, now);
if (thread_state_ == ThreadState::kPaused) {
// If the load tracker is paused, bail out early.
time_ = now;
return;
}
while (time_ < now) {
// Advance time_ to the earliest of following:
// a) time to call |callback_|
// b) requested time to forward (|now|).
base::TimeTicks next_current_time = std::min(next_reporting_time_, now);
base::TimeDelta delta = next_current_time - time_;
// Keep a running total of the time spent running tasks within the window
// and the total time.
if (task_state == TaskState::kTaskRunning) {
run_time_inside_window_ +=
Intersection(next_reporting_time_ - reporting_interval_,
next_reporting_time_, time_, time_ + delta);
}
time_ = next_current_time;
if (time_ == next_reporting_time_) {
// Call |callback_| if need and update next callback time.
if (thread_state_ == ThreadState::kActive) {
callback_.Run(time_, Load());
DCHECK_EQ(thread_state_, ThreadState::kActive);
}
next_reporting_time_ += reporting_interval_;
run_time_inside_window_ = base::TimeDelta();
}
}
}
double ThreadLoadTracker::Load() {
return run_time_inside_window_.InSecondsF() /
reporting_interval_.InSecondsF();
}
} // namespace scheduler
} // namespace blink