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

Side by Side Diff: base/time/time_win.cc

Issue 489793003: Fix logic on high Windows resolution timer and have (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months 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
« no previous file with comments | « base/time/time.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 5
6 // Windows Timer Primer 6 // Windows Timer Primer
7 // 7 //
8 // A good article: http://www.ddj.com/windows/184416651 8 // A good article: http://www.ddj.com/windows/184416651
9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
10 // 10 //
(...skipping 11 matching lines...) Expand all
22 // 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other 22 // 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
23 // applications on the system. By default, precision is only 15.5ms. 23 // applications on the system. By default, precision is only 15.5ms.
24 // Unfortunately, we don't want to call timeBeginPeriod because we don't 24 // Unfortunately, we don't want to call timeBeginPeriod because we don't
25 // want to affect other applications. Further, on mobile platforms, use of 25 // want to affect other applications. Further, on mobile platforms, use of
26 // faster multimedia timers can hurt battery life. See the intel 26 // faster multimedia timers can hurt battery life. See the intel
27 // article about this here: 27 // article about this here:
28 // http://softwarecommunity.intel.com/articles/eng/1086.htm 28 // http://softwarecommunity.intel.com/articles/eng/1086.htm
29 // 29 //
30 // To work around all this, we're going to generally use timeGetTime(). We 30 // To work around all this, we're going to generally use timeGetTime(). We
31 // will only increase the system-wide timer if we're not running on battery 31 // will only increase the system-wide timer if we're not running on battery
32 // power. Using timeBeginPeriod(1) is a requirement in order to make our 32 // power.
33 // message loop waits have the same resolution that our time measurements
34 // do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
35 // there is nothing else to waken the Wait.
36 33
37 #include "base/time/time.h" 34 #include "base/time/time.h"
38 35
39 #pragma comment(lib, "winmm.lib") 36 #pragma comment(lib, "winmm.lib")
40 #include <windows.h> 37 #include <windows.h>
41 #include <mmsystem.h> 38 #include <mmsystem.h>
42 39
43 #include "base/basictypes.h" 40 #include "base/basictypes.h"
44 #include "base/cpu.h" 41 #include "base/cpu.h"
45 #include "base/lazy_instance.h" 42 #include "base/lazy_instance.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; 77 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
81 78
82 int64 initial_time = 0; 79 int64 initial_time = 0;
83 TimeTicks initial_ticks; 80 TimeTicks initial_ticks;
84 81
85 void InitializeClock() { 82 void InitializeClock() {
86 initial_ticks = TimeTicks::Now(); 83 initial_ticks = TimeTicks::Now();
87 initial_time = CurrentWallclockMicroseconds(); 84 initial_time = CurrentWallclockMicroseconds();
88 } 85 }
89 86
87 // The two values that ActivateHighResolutionTimer uses to set the systemwide
88 // timer interrupt frequency on Windows. It controls how precise timers are
89 // but also has a big impact on battery life.
90 const int kMinTimerIntervalHighResMs = 1;
91 const int kMinTimerIntervalLowResMs = 4;
jamesr 2014/08/26 05:03:17 since these 2 vars always go into a UINT can we ju
92 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active.
93 bool g_high_res_timer_enabled = false;
94 // How many times the high resolution timer has been called.
95 int g_high_res_timer_count = 0;
96 // The lock to control access to the above two variables.
97 base::LazyInstance<base::Lock> g_high_res_lock = LAZY_INSTANCE_INITIALIZER;
98
90 } // namespace 99 } // namespace
91 100
92 // Time ----------------------------------------------------------------------- 101 // Time -----------------------------------------------------------------------
93 102
94 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 103 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
95 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the 104 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
96 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding 105 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
97 // 1700, 1800, and 1900. 106 // 1700, 1800, and 1900.
98 // static 107 // static
99 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000); 108 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
100 109
101 bool Time::high_resolution_timer_enabled_ = false;
102 int Time::high_resolution_timer_activated_ = 0;
103
104 // static 110 // static
105 Time Time::Now() { 111 Time Time::Now() {
106 if (initial_time == 0) 112 if (initial_time == 0)
107 InitializeClock(); 113 InitializeClock();
108 114
109 // We implement time using the high-resolution timers so that we can get 115 // We implement time using the high-resolution timers so that we can get
110 // timeouts which are smaller than 10-15ms. If we just used 116 // timeouts which are smaller than 10-15ms. If we just used
111 // CurrentWallclockMicroseconds(), we'd have the less-granular timer. 117 // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
112 // 118 //
113 // To make this work, we initialize the clock (initial_time) and the 119 // To make this work, we initialize the clock (initial_time) and the
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 result.dwLowDateTime = std::numeric_limits<DWORD>::max(); 164 result.dwLowDateTime = std::numeric_limits<DWORD>::max();
159 return result; 165 return result;
160 } 166 }
161 FILETIME utc_ft; 167 FILETIME utc_ft;
162 MicrosecondsToFileTime(us_, &utc_ft); 168 MicrosecondsToFileTime(us_, &utc_ft);
163 return utc_ft; 169 return utc_ft;
164 } 170 }
165 171
166 // static 172 // static
167 void Time::EnableHighResolutionTimer(bool enable) { 173 void Time::EnableHighResolutionTimer(bool enable) {
168 // Test for single-threaded access. 174 {
169 static PlatformThreadId my_thread = PlatformThread::CurrentId(); 175 base::AutoLock lock(g_high_res_lock.Get());
170 DCHECK(PlatformThread::CurrentId() == my_thread); 176 if (g_high_res_timer_enabled == enable)
171 177 return;
172 if (high_resolution_timer_enabled_ == enable) 178 g_high_res_timer_enabled = enable;
173 return; 179 if (!g_high_res_timer_count)
174 180 return;
175 high_resolution_timer_enabled_ = enable; 181 }
182 if (enable) {
jamesr 2014/08/26 05:03:17 let's say we're in high resolution mode with no ac
183 timeEndPeriod(kMinTimerIntervalLowResMs);
184 timeBeginPeriod(kMinTimerIntervalHighResMs);
185 } else {
186 timeEndPeriod(kMinTimerIntervalHighResMs);
187 timeBeginPeriod(kMinTimerIntervalLowResMs);
188 }
176 } 189 }
177 190
178 // static 191 // static
179 bool Time::ActivateHighResolutionTimer(bool activating) { 192 bool Time::ActivateHighResolutionTimer(bool activating) {
180 if (!high_resolution_timer_enabled_ && activating) 193 // We only do work on the transition from zero to one or one to zero so we
181 return false; 194 // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
182 195 // called.
183 // Using anything other than 1ms makes timers granular 196 int high_res_count;
184 // to that interval. 197 UINT period;
185 const int kMinTimerIntervalMs = 1; 198 {
186 MMRESULT result; 199 base::AutoLock lock(g_high_res_lock.Get());
200 period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
201 : kMinTimerIntervalLowResMs;
202 high_res_count =
203 activating ? ++g_high_res_timer_count : --g_high_res_timer_count;
204 }
187 if (activating) { 205 if (activating) {
188 result = timeBeginPeriod(kMinTimerIntervalMs); 206 if (high_res_count == 1)
189 high_resolution_timer_activated_++; 207 timeBeginPeriod(period);
190 } else { 208 } else {
191 result = timeEndPeriod(kMinTimerIntervalMs); 209 if (high_res_count == 0)
192 high_resolution_timer_activated_--; 210 timeEndPeriod(period);
193 } 211 }
194 return result == TIMERR_NOERROR; 212 return (period == kMinTimerIntervalHighResMs);
195 } 213 }
196 214
197 // static 215 // static
198 bool Time::IsHighResolutionTimerInUse() { 216 bool Time::IsHighResolutionTimerInUse() {
199 // Note: we should track the high_resolution_timer_activated_ value 217 base::AutoLock lock(g_high_res_lock.Get());
200 // under a lock if we want it to be accurate in a system with multiple 218 return g_high_res_timer_enabled && g_high_res_timer_count > 0;
201 // message loops. We don't do that - because we don't want to take the
202 // expense of a lock for this. We *only* track this value so that unit
203 // tests can see if the high resolution timer is on or off.
204 return high_resolution_timer_enabled_ &&
205 high_resolution_timer_activated_ > 0;
206 } 219 }
207 220
208 // static 221 // static
209 Time Time::FromExploded(bool is_local, const Exploded& exploded) { 222 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
210 // Create the system struct representing our exploded time. It will either be 223 // Create the system struct representing our exploded time. It will either be
211 // in local time or UTC. 224 // in local time or UTC.
212 SYSTEMTIME st; 225 SYSTEMTIME st;
213 st.wYear = exploded.year; 226 st.wYear = exploded.year;
214 st.wMonth = exploded.month; 227 st.wMonth = exploded.month;
215 st.wDayOfWeek = exploded.day_of_week; 228 st.wDayOfWeek = exploded.day_of_week;
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); 544 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime());
532 } 545 }
533 } 546 }
534 547
535 // TimeDelta ------------------------------------------------------------------ 548 // TimeDelta ------------------------------------------------------------------
536 549
537 // static 550 // static
538 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { 551 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
539 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); 552 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
540 } 553 }
OLDNEW
« no previous file with comments | « base/time/time.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698