Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / sync_file_system / sync_process_runner.cc
blobfa1f100038b656e6af3b89668a3a43f4133d1974
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync_file_system/sync_process_runner.h"
7 #include "base/format_macros.h"
8 #include "chrome/browser/sync_file_system/logger.h"
10 namespace sync_file_system {
12 const int64 SyncProcessRunner::kSyncDelayInMilliseconds =
13 1 * base::Time::kMillisecondsPerSecond; // 1 sec
14 const int64 SyncProcessRunner::kSyncDelayWithSyncError =
15 3 * base::Time::kMillisecondsPerSecond; // 3 sec
16 const int64 SyncProcessRunner::kSyncDelayFastInMilliseconds = 100; // 100 ms
17 const int SyncProcessRunner::kPendingChangeThresholdForFastSync = 10;
18 const int64 SyncProcessRunner::kSyncDelaySlowInMilliseconds =
19 30 * base::Time::kMillisecondsPerSecond; // 30 sec
20 const int64 SyncProcessRunner::kSyncDelayMaxInMilliseconds =
21 30 * 60 * base::Time::kMillisecondsPerSecond; // 30 min
23 namespace {
25 class BaseTimerHelper : public SyncProcessRunner::TimerHelper {
26 public:
27 BaseTimerHelper() {}
29 virtual bool IsRunning() override {
30 return timer_.IsRunning();
33 virtual void Start(const tracked_objects::Location& from_here,
34 const base::TimeDelta& delay,
35 const base::Closure& closure) override {
36 timer_.Start(from_here, delay, closure);
39 virtual base::TimeTicks Now() const override {
40 return base::TimeTicks::Now();
43 virtual ~BaseTimerHelper() {}
45 private:
46 base::OneShotTimer<SyncProcessRunner> timer_;
48 DISALLOW_COPY_AND_ASSIGN(BaseTimerHelper);
51 bool WasSuccessfulSync(SyncStatusCode status) {
52 return status == SYNC_STATUS_OK ||
53 status == SYNC_STATUS_HAS_CONFLICT ||
54 status == SYNC_STATUS_NO_CONFLICT ||
55 status == SYNC_STATUS_NO_CHANGE_TO_SYNC ||
56 status == SYNC_STATUS_UNKNOWN_ORIGIN ||
57 status == SYNC_STATUS_RETRY;
60 } // namespace
62 SyncProcessRunner::SyncProcessRunner(
63 const std::string& name,
64 Client* client,
65 scoped_ptr<TimerHelper> timer_helper,
66 size_t max_parallel_task)
67 : name_(name),
68 client_(client),
69 max_parallel_task_(max_parallel_task),
70 running_tasks_(0),
71 timer_helper_(timer_helper.Pass()),
72 service_state_(SYNC_SERVICE_RUNNING),
73 pending_changes_(0),
74 factory_(this) {
75 DCHECK_LE(1u, max_parallel_task_);
76 if (!timer_helper_)
77 timer_helper_.reset(new BaseTimerHelper);
80 SyncProcessRunner::~SyncProcessRunner() {}
82 void SyncProcessRunner::Schedule() {
83 if (pending_changes_ == 0) {
84 ScheduleInternal(kSyncDelayMaxInMilliseconds);
85 return;
88 SyncServiceState last_service_state = service_state_;
89 service_state_ = GetServiceState();
91 switch (service_state_) {
92 case SYNC_SERVICE_RUNNING:
93 ResetThrottling();
94 if (pending_changes_ > kPendingChangeThresholdForFastSync)
95 ScheduleInternal(kSyncDelayFastInMilliseconds);
96 else
97 ScheduleInternal(kSyncDelayInMilliseconds);
98 return;
100 case SYNC_SERVICE_TEMPORARY_UNAVAILABLE:
101 if (last_service_state != service_state_)
102 ThrottleSync(kSyncDelaySlowInMilliseconds);
103 ScheduleInternal(kSyncDelaySlowInMilliseconds);
104 return;
106 case SYNC_SERVICE_AUTHENTICATION_REQUIRED:
107 case SYNC_SERVICE_DISABLED:
108 if (last_service_state != service_state_)
109 ThrottleSync(kSyncDelaySlowInMilliseconds);
110 ScheduleInternal(kSyncDelayMaxInMilliseconds);
111 return;
114 NOTREACHED();
115 ScheduleInternal(kSyncDelayMaxInMilliseconds);
118 void SyncProcessRunner::ThrottleSync(int64 base_delay) {
119 base::TimeTicks now = timer_helper_->Now();
120 base::TimeDelta elapsed = std::min(now, throttle_until_) - throttle_from_;
121 DCHECK(base::TimeDelta() <= elapsed);
123 throttle_from_ = now;
124 // Extend throttling duration by twice the elapsed time.
125 // That is, if the backoff repeats in a short period, the throttling period
126 // doesn't grow exponentially. If the backoff happens on the end of
127 // throttling period, it causes another throttling period that is twice as
128 // long as previous.
129 base::TimeDelta base_delay_delta =
130 base::TimeDelta::FromMilliseconds(base_delay);
131 const base::TimeDelta max_delay =
132 base::TimeDelta::FromMilliseconds(kSyncDelayMaxInMilliseconds);
133 throttle_until_ =
134 std::min(now + max_delay,
135 std::max(now + base_delay_delta, throttle_until_ + 2 * elapsed));
138 void SyncProcessRunner::ResetOldThrottling() {
139 if (throttle_until_ < base::TimeTicks::Now())
140 ResetThrottling();
143 void SyncProcessRunner::ResetThrottling() {
144 throttle_from_ = base::TimeTicks();
145 throttle_until_ = base::TimeTicks();
148 SyncServiceState SyncProcessRunner::GetServiceState() {
149 return client_->GetSyncServiceState();
152 void SyncProcessRunner::OnChangesUpdated(
153 int64 pending_changes) {
154 DCHECK_GE(pending_changes, 0);
155 int64 old_pending_changes = pending_changes_;
156 pending_changes_ = pending_changes;
157 if (old_pending_changes != pending_changes) {
158 CheckIfIdle();
159 util::Log(logging::LOG_VERBOSE, FROM_HERE,
160 "[%s] pending_changes updated: %" PRId64,
161 name_.c_str(), pending_changes);
163 Schedule();
166 SyncFileSystemService* SyncProcessRunner::GetSyncService() {
167 return client_->GetSyncService();
170 void SyncProcessRunner::Finished(const base::TimeTicks& start_time,
171 SyncStatusCode status) {
172 DCHECK_LT(0u, running_tasks_);
173 DCHECK_LE(running_tasks_, max_parallel_task_);
174 --running_tasks_;
175 CheckIfIdle();
176 util::Log(logging::LOG_VERBOSE, FROM_HERE,
177 "[%s] * Finished (elapsed: %" PRId64 " ms)", name_.c_str(),
178 (timer_helper_->Now() - start_time).InMilliseconds());
180 if (status == SYNC_STATUS_NO_CHANGE_TO_SYNC ||
181 status == SYNC_STATUS_FILE_BUSY) {
182 ScheduleInternal(kSyncDelayMaxInMilliseconds);
183 return;
186 if (WasSuccessfulSync(status))
187 ResetOldThrottling();
188 else
189 ThrottleSync(kSyncDelayWithSyncError);
191 Schedule();
194 void SyncProcessRunner::Run() {
195 if (running_tasks_ >= max_parallel_task_)
196 return;
197 ++running_tasks_;
198 base::TimeTicks now = timer_helper_->Now();
199 last_run_ = now;
201 util::Log(logging::LOG_VERBOSE, FROM_HERE,
202 "[%s] * Started", name_.c_str());
204 StartSync(base::Bind(&SyncProcessRunner::Finished, factory_.GetWeakPtr(),
205 now));
206 if (running_tasks_ < max_parallel_task_)
207 Schedule();
210 void SyncProcessRunner::ScheduleInternal(int64 delay) {
211 base::TimeTicks now = timer_helper_->Now();
212 base::TimeTicks next_scheduled;
214 if (timer_helper_->IsRunning()) {
215 next_scheduled = last_run_ + base::TimeDelta::FromMilliseconds(delay);
216 if (next_scheduled < now) {
217 next_scheduled =
218 now + base::TimeDelta::FromMilliseconds(kSyncDelayFastInMilliseconds);
220 } else {
221 next_scheduled = now + base::TimeDelta::FromMilliseconds(delay);
224 if (next_scheduled < throttle_until_)
225 next_scheduled = throttle_until_;
227 if (timer_helper_->IsRunning() && last_scheduled_ == next_scheduled)
228 return;
230 util::Log(logging::LOG_VERBOSE, FROM_HERE,
231 "[%s] Scheduling task in %" PRId64 " ms",
232 name_.c_str(), (next_scheduled - now).InMilliseconds());
234 last_scheduled_ = next_scheduled;
236 timer_helper_->Start(
237 FROM_HERE, next_scheduled - now,
238 base::Bind(&SyncProcessRunner::Run, base::Unretained(this)));
241 void SyncProcessRunner::CheckIfIdle() {
242 if (pending_changes_ == 0 && running_tasks_ == 0)
243 client_->OnSyncIdle();
246 } // namespace sync_file_system