Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Side by Side Diff: media/base/android/media_service_throttler.cc

Issue 2471903002: Add MediaServiceThrottler (Closed)
Patch Set: Integrate throttler into MediaPlayerRender Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "media/base/android/media_service_throttler.h"
6
7 #include "base/bind.h"
8 #include "base/threading/thread_task_runner_handle.h"
9 #include "base/time/default_tick_clock.h"
10 #include "media/base/android/media_server_crash_listener.h"
11
12 namespace media {
13
14 // Elapsed time between crashes needed to completely reset the media server
15 // crash count.
16 const base::TimeDelta kTimeUntilCrashReset = base::TimeDelta::FromMinutes(1);
DaleCurtis 2016/11/08 22:35:41 constexpr on all base::TimeDelta? Otherwise I thin
sandersd (OOO until July 31) 2016/11/08 22:53:44 These should probably all be in an anonymous names
tguilbert 2016/11/11 03:50:29 Done.
17
18 // Elapsed time between schedule calls needed to completely reset the
19 // scheduling clock.
20 const base::TimeDelta kTimeUntilScheduleReset = base::TimeDelta::FromMinutes(1);
21
22 // Decay rate of server crashes, corresponding to a tolerable 'normal' crash
23 // rate. This means that we will decrement our crash rate by ~1 crash/minute.
24 const uint kCrashDecayRateInMs = 60000;
sandersd (OOO until July 31) 2016/11/08 22:53:44 This is a period (as opposed to a rate).
tguilbert 2016/11/11 03:50:29 Done.
25
26 // Rate at which client creations will be exponentially throttled based on the
27 // number of media server crashes.
28 // NOTE: Since our exponential delay formula is 2^(server crashes), 0 server
29 // crashes still result in this delay being added once.
sandersd (OOO until July 31) 2016/11/08 22:53:44 An alternative would be to use |n ? 2^(n-1) : 0|.
tguilbert 2016/11/11 03:50:29 That was how I had originally written it, but I fo
30 const base::TimeDelta kBaseExponentialDelay =
31 base::TimeDelta::FromMilliseconds(120);
32
33 // Base rate at which we schedule client creations.
34 // The minimal delay is |kLinearThrottlingRate| + |kBaseExponentialDelay|.
35 // This corresponds to 0.2s.
36 const base::TimeDelta kLinearThrottlingRate =
37 base::TimeDelta::FromMilliseconds(80);
sandersd (OOO until July 31) 2016/11/08 22:53:44 Also a period ("delay" and other synonyms are fine
tguilbert 2016/11/11 03:50:29 Done.
38
39 // Max exponential throttling rate from media server crashes.
40 // The max delay will still be |kLinearThrottlingRate| + |kMaxExponentialDelay|.
41 // This corresponds to 3s.
42 const base::TimeDelta kMaxExponentialDelay =
43 base::TimeDelta::FromMilliseconds(2920);
44
45 // Max number of clients to schedule immediately (e.g when loading a new page).
46 const uint kMaxBurstClients = 10;
47
48 // Sliding window of time during which we allow clients to be scheduled
49 // immediately, to accomodate for a "bursts" of requests when loading new pages.
50 const base::TimeDelta kMinDelayWindow =
51 (kLinearThrottlingRate + kBaseExponentialDelay) * kMaxBurstClients;
52
53 // The throttling progression based on number of crashes looks as follows:
54 //
55 // | # crashes | period | clients/sec | clients/mins | # burst clients
56 // | 0 | 200 ms | 5.0 | 300 | 10
57 // | 1 | 320 ms | 3.1 | 188 | 6
58 // | 2 | 560 ms | 1.8 | 107 | 4
59 // | 3 | 1040 ms | 1.0 | 58 | 2
60 // | 4 | 2000 ms | 0.5 | 30 | 1
61 // | 5 | 3000 ms | 0.3 | 20 | 1
62 // | 6 | 3000 ms | 0.3 | 20 | 1
63 //
64 // NOTE: Since we use the floor function and a decay rate of 1 crash/minute when
65 // calculating the effective # of crashes, a single crash per minute will result
66 // in 0 effective crashes (since floor(1.0 - 'tiny decay') is 0). If we
67 // experience slightly more than 1 crash per 60 seconds, the effective number of
68 // crashes will go up as expected.
69
70 // static
71 MediaServiceThrottler* MediaServiceThrottler::GetInstance() {
72 return base::Singleton<
DaleCurtis 2016/11/08 22:35:41 Hmm, why do both classes need a singleton? Seems o
tguilbert 2016/11/11 03:50:29 Updated. The MediaServiceThrottler is now a lazy i
73 MediaServiceThrottler,
74 base::LeakySingletonTraits<MediaServiceThrottler>>::get();
75 }
76
77 MediaServiceThrottler::~MediaServiceThrottler() {}
78
79 MediaServiceThrottler::MediaServiceThrottler()
80 : clock_(new base::DefaultTickClock()), current_crashes_(0.0) {
81 // base::Unretained is safe here because both the MediaServiceThrottler and
82 // the MediaServerCrashListener live until the process is terminated.
83 MediaServerCrashListener::GetInstance()->SetOnServerCrashCallback(
84 base::Bind(&MediaServiceThrottler::OnMediaServerCrash,
85 base::Unretained(this)),
86 base::ThreadTaskRunnerHandle::Get());
87
88 EnsureCrashListenerStarted();
89 }
90
91 void MediaServiceThrottler::SetTickClockForTesting(base::TickClock* clock) {
92 clock_.reset(clock);
93 }
94
95 base::TimeDelta MediaServiceThrottler::GetBaseThrottlingRateForTesting() {
96 return kBaseExponentialDelay + kLinearThrottlingRate;
97 }
98
99 void MediaServiceThrottler::ResetInternalStateForTesting() {
100 last_server_crash_ = base::TimeTicks();
101 last_schedule_call_ = base::TimeTicks();
102 next_schedulable_slot_ = clock_->NowTicks();
103 last_update_time_ = clock_->NowTicks();
104 current_crashes_ = 0.0;
105 }
106
107 base::TimeDelta MediaServiceThrottler::ScheduleClientCreation() {
DaleCurtis 2016/11/08 22:35:41 I'd rename this to GetCreationDelay() or something
tguilbert 2016/11/11 03:50:29 Done.
108 // Make sure the listener is started and the crashes decayed.
109 EnsureCrashListenerStarted();
110 UpdateServerCrashes();
111
112 base::TimeTicks now = clock_->NowTicks();
113
114 // If we are passed the next time slot or if it has been 1 minute since the
115 // last call to ScheduleClientCreation(), reset the next time to now.
116 if (now > next_schedulable_slot_ ||
DaleCurtis 2016/11/08 22:35:41 {} for multi-line if.
tguilbert 2016/11/11 03:50:29 Done.
117 (now - last_schedule_call_) > kTimeUntilScheduleReset)
118 next_schedulable_slot_ = now;
119
120 last_schedule_call_ = now;
121
122 // Increment the next scheduled time between 0.2s and 3s, which allows the
123 // creation of between 50 and 3 clients per 10s.
124 next_schedulable_slot_ +=
125 kLinearThrottlingRate + GetThrottlingDelayFromServerCrashes();
126
127 // Calculate how long to delay the creation so it isn't scheduled before
128 // |next_schedulable_slot_|.
129 base::TimeDelta delay = next_schedulable_slot_ - now;
130
131 // If the scheduling delay is low enough, schedule it immediately instead.
132 // This allows up to kMaxBurstClients clients to be scheduled immediately.
133 if (delay <= kMinDelayWindow)
134 return base::TimeDelta();
135
136 return delay;
137 }
138
139 base::TimeDelta MediaServiceThrottler::GetThrottlingDelayFromServerCrashes() {
140 // The combination of rounding down the number of crashes down and decaying
141 // at the rate of 1 crash / min means that a single crash will very quickly be
142 // rounded down to 0. Effectively, this means that we only start exponentially
143 // backing off if we have more than 1 crash in a 60 second window.
144 uint number_crashes = std::floor(current_crashes_);
DaleCurtis 2016/11/08 22:35:41 No uint. Specify an actual type.
tguilbert 2016/11/11 03:50:29 Done.
145 DCHECK(number_crashes >= 0);
DaleCurtis 2016/11/08 22:35:41 DCHECK_GE
tguilbert 2016/11/11 03:50:29 Done.
146
147 // Prevents overflow/undefined behavior. We already reach kMaxExponentialDelay
148 // at 5 crashes in any case.
149 number_crashes = std::min(number_crashes, (uint)10);
DaleCurtis 2016/11/08 22:35:41 No c style cast. static_cast<> if you need. This s
tguilbert 2016/11/11 03:50:29 Done.
150
151 return std::min(kBaseExponentialDelay * (1 << number_crashes),
152 kMaxExponentialDelay);
153 }
154
155 void MediaServiceThrottler::OnMediaServerCrash() {
156 UpdateServerCrashes();
157
158 last_server_crash_ = clock_->NowTicks();
159 current_crashes_ += 1.0;
160 }
161
162 void MediaServiceThrottler::UpdateServerCrashes() {
163 base::TimeTicks now = clock_->NowTicks();
164 base::TimeDelta time_since_last_crash = now - last_server_crash_;
165
166 if (time_since_last_crash > kTimeUntilCrashReset) {
167 // Reset the number of crashes if we haven't had a crash in the past minute.
168 current_crashes_ = 0.0;
DaleCurtis 2016/11/08 22:35:41 Just 0 is fine.
tguilbert 2016/11/11 03:50:29 Done.
169 } else {
170 // Decay at the rate of 1 crash/minute otherwise.
171 double decay =
172 (now - last_update_time_).InMillisecondsF() / kCrashDecayRateInMs;
173 current_crashes_ = std::max(0.0, current_crashes_ - decay);
174 }
175
176 last_update_time_ = now;
177 }
178
179 void MediaServiceThrottler::EnsureCrashListenerStarted() {
DaleCurtis 2016/11/08 22:35:41 Seems is_media_server_crash_listener_running_ is k
tguilbert 2016/11/11 03:50:29 Updated.
180 if (!is_media_server_crash_listener_running_) {
181 is_media_server_crash_listener_running_ =
182 MediaServerCrashListener::GetInstance()->StartListening();
183 }
184 }
185
186 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698