forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[scheduler] Monitor renderer main thread load level.
Add monitoring of main thread load level for background and foreground renderers. BUG=639852 Review-Url: https://codereview.chromium.org/2265873004 Cr-Commit-Position: refs/heads/master@{#413783}
- Loading branch information
altimin
authored and
Commit bot
committed
Aug 23, 2016
1 parent
9383a84
commit 3ab9c0b
Showing
7 changed files
with
336 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
third_party/WebKit/Source/platform/scheduler/base/thread_load_tracker.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// 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 "platform/scheduler/base/thread_load_tracker.h" | ||
|
||
#include <algorithm> | ||
|
||
namespace blink { | ||
namespace scheduler { | ||
|
||
namespace { | ||
|
||
const int kLoadReportingIntervalInSeconds = 1; | ||
const int kWaitingPeriodBeforeReportingInSeconds = 10; | ||
|
||
} // namespace | ||
|
||
ThreadLoadTracker::ThreadLoadTracker(base::TimeTicks now, | ||
const Callback& callback) | ||
: time_(now), | ||
next_reporting_time_(now), | ||
thread_state_(ThreadState::ACTIVE), | ||
last_state_change_time_(now), | ||
waiting_period_( | ||
base::TimeDelta::FromSeconds(kWaitingPeriodBeforeReportingInSeconds)), | ||
reporting_interval_( | ||
base::TimeDelta::FromSeconds(kLoadReportingIntervalInSeconds)), | ||
callback_(callback) {} | ||
|
||
ThreadLoadTracker::~ThreadLoadTracker() {} | ||
|
||
void ThreadLoadTracker::Pause(base::TimeTicks now) { | ||
Advance(now, TaskState::IDLE); | ||
thread_state_ = ThreadState::PAUSED; | ||
last_state_change_time_ = now; | ||
} | ||
|
||
void ThreadLoadTracker::Resume(base::TimeTicks now) { | ||
Advance(now, TaskState::IDLE); | ||
thread_state_ = ThreadState::ACTIVE; | ||
last_state_change_time_ = now; | ||
} | ||
|
||
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::IDLE); | ||
Advance(end_time, TaskState::TASK_RUNNING); | ||
} | ||
|
||
void ThreadLoadTracker::RecordIdle(base::TimeTicks now) { | ||
Advance(now, TaskState::IDLE); | ||
} | ||
|
||
void ThreadLoadTracker::Advance(base::TimeTicks now, TaskState task_state) { | ||
// This function advances |time_| to now and calls |callback_| | ||
// when appropriate. | ||
if (time_ > now) { | ||
return; | ||
} | ||
|
||
if (thread_state_ == ThreadState::PAUSED) { | ||
// If the load tracker is paused, bail out early. | ||
time_ = now; | ||
next_reporting_time_ = now + reporting_interval_; | ||
return; | ||
} | ||
|
||
while (time_ < now) { | ||
// Forward 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_; | ||
|
||
// Forward time and recalculate |total_time_| and |total_runtime_|. | ||
if (thread_state_ == ThreadState::ACTIVE) { | ||
total_time_ += delta; | ||
if (task_state == TaskState::TASK_RUNNING) { | ||
total_runtime_ += delta; | ||
} | ||
} | ||
time_ = next_current_time; | ||
|
||
if (time_ == next_reporting_time_) { | ||
// Call |callback_| if need and update next callback time. | ||
if (thread_state_ == ThreadState::ACTIVE && | ||
total_time_ >= waiting_period_) { | ||
callback_.Run(time_, Load()); | ||
} | ||
next_reporting_time_ += reporting_interval_; | ||
} | ||
} | ||
} | ||
|
||
double ThreadLoadTracker::Load() { | ||
if (total_time_.is_zero()) { | ||
return 0; | ||
} | ||
return total_runtime_.InSecondsF() / total_time_.InSecondsF(); | ||
} | ||
|
||
} // namespace scheduler | ||
} // namespace blink |
69 changes: 69 additions & 0 deletions
69
third_party/WebKit/Source/platform/scheduler/base/thread_load_tracker.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// 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. | ||
|
||
#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_LOAD_TRACKER_H_ | ||
#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_LOAD_TRACKER_H_ | ||
|
||
#include "base/callback.h" | ||
#include "base/macros.h" | ||
#include "base/time/time.h" | ||
#include "public/platform/WebCommon.h" | ||
|
||
namespace blink { | ||
namespace scheduler { | ||
|
||
// This class tracks thread load level, i.e. percentage of wall time spent | ||
// running tasks. | ||
// In order to avoid bias it reports load level at regular intervals. | ||
class BLINK_PLATFORM_EXPORT ThreadLoadTracker { | ||
public: | ||
// Callback is called with (current_time, load_level) parameters. | ||
using Callback = base::Callback<void(base::TimeTicks, double)>; | ||
|
||
ThreadLoadTracker(base::TimeTicks now, const Callback& callback); | ||
~ThreadLoadTracker(); | ||
|
||
void Pause(base::TimeTicks now); | ||
void Resume(base::TimeTicks now); | ||
|
||
void RecordTaskTime(base::TimeTicks start_time, base::TimeTicks end_time); | ||
|
||
void RecordIdle(base::TimeTicks now); | ||
|
||
// TODO(altimin): Count wakeups. | ||
|
||
private: | ||
enum class ThreadState { ACTIVE, PAUSED }; | ||
|
||
enum class TaskState { TASK_RUNNING, IDLE }; | ||
|
||
// This function advances |time_| to |now|, calling |callback_| | ||
// in the process (multiple times if needed). | ||
void Advance(base::TimeTicks now, TaskState task_state); | ||
|
||
double Load(); | ||
|
||
// |time_| is the last timestamp LoadTracker knows about. | ||
base::TimeTicks time_; | ||
base::TimeTicks next_reporting_time_; | ||
|
||
ThreadState thread_state_; | ||
base::TimeTicks last_state_change_time_; | ||
|
||
base::TimeDelta total_time_; | ||
base::TimeDelta total_runtime_; | ||
|
||
// Start reporting values after |waiting_period_|. | ||
base::TimeDelta waiting_period_; | ||
base::TimeDelta reporting_interval_; | ||
|
||
Callback callback_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(ThreadLoadTracker); | ||
}; | ||
|
||
} // namespace scheduler | ||
} // namespace blink | ||
|
||
#endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_RENDERER_RENDERER_LOAD_TRACKER_H_ |
73 changes: 73 additions & 0 deletions
73
third_party/WebKit/Source/platform/scheduler/base/thread_load_tracker_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include "platform/scheduler/base/thread_load_tracker.h" | ||
|
||
#include "base/bind.h" | ||
#include "testing/gmock/include/gmock/gmock.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
namespace blink { | ||
namespace scheduler { | ||
|
||
namespace { | ||
|
||
void AddToVector(std::vector<std::pair<base::TimeTicks, double>>* vector, | ||
base::TimeTicks time, | ||
double load) { | ||
vector->push_back({time, load}); | ||
} | ||
|
||
base::TimeTicks SecondsToTime(int seconds) { | ||
return base::TimeTicks() + base::TimeDelta::FromSeconds(seconds); | ||
} | ||
|
||
double Divide(int a, int b) { | ||
return static_cast<double>(a) / b; | ||
} | ||
|
||
} // namespace | ||
|
||
TEST(ThreadLoadTrackerTest, RecordTasks) { | ||
std::vector<std::pair<base::TimeTicks, double>> result; | ||
|
||
ThreadLoadTracker thread_load_tracker( | ||
SecondsToTime(1), base::Bind(&AddToVector, base::Unretained(&result))); | ||
|
||
thread_load_tracker.RecordTaskTime(SecondsToTime(3), SecondsToTime(5)); | ||
thread_load_tracker.RecordTaskTime(SecondsToTime(7), SecondsToTime(9)); | ||
thread_load_tracker.RecordTaskTime(SecondsToTime(10), SecondsToTime(13)); | ||
thread_load_tracker.RecordTaskTime(SecondsToTime(15), SecondsToTime(18)); | ||
|
||
// Because of 10-second delay we're getting information starting with 11s. | ||
std::vector<std::pair<base::TimeTicks, double>> expected_result{ | ||
{SecondsToTime(11), Divide(5, 10)}, {SecondsToTime(12), Divide(6, 11)}, | ||
{SecondsToTime(13), Divide(7, 12)}, {SecondsToTime(14), Divide(7, 13)}, | ||
{SecondsToTime(15), Divide(7, 14)}, {SecondsToTime(16), Divide(8, 15)}, | ||
{SecondsToTime(17), Divide(9, 16)}, {SecondsToTime(18), Divide(10, 17)}}; | ||
|
||
EXPECT_EQ(result, expected_result); | ||
} | ||
|
||
TEST(ThreadLoadTrackerTest, PauseAndResume) { | ||
std::vector<std::pair<base::TimeTicks, double>> result; | ||
|
||
ThreadLoadTracker thread_load_tracker( | ||
SecondsToTime(1), base::Bind(&AddToVector, base::Unretained(&result))); | ||
|
||
thread_load_tracker.RecordTaskTime(SecondsToTime(3), SecondsToTime(4)); | ||
thread_load_tracker.Pause(SecondsToTime(5)); | ||
// This task should be ignored. | ||
thread_load_tracker.RecordTaskTime(SecondsToTime(10), SecondsToTime(11)); | ||
thread_load_tracker.Resume(SecondsToTime(15)); | ||
// We're counting only last second. | ||
thread_load_tracker.RecordTaskTime(SecondsToTime(14), SecondsToTime(16)); | ||
thread_load_tracker.RecordTaskTime(SecondsToTime(22), SecondsToTime(23)); | ||
|
||
std::vector<std::pair<base::TimeTicks, double>> expected_result{ | ||
{SecondsToTime(21), Divide(2, 10)}, | ||
{SecondsToTime(22), Divide(2, 11)}, | ||
{SecondsToTime(23), Divide(3, 12)}}; | ||
|
||
EXPECT_EQ(result, expected_result); | ||
} | ||
|
||
} // namespace scheduler | ||
} // namespace blink |
Oops, something went wrong.