OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 #include "components/startup_metric_utils/startup_metric_utils.h" | 5 #include "components/startup_metric_utils/startup_metric_utils.h" |
6 | 6 |
7 #include "base/containers/hash_tables.h" | 7 #include "base/containers/hash_tables.h" |
8 #include "base/environment.h" | 8 #include "base/environment.h" |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "base/sys_info.h" | 13 #include "base/sys_info.h" |
14 #include "base/trace_event/trace_event.h" | |
14 | 15 |
15 #if defined(OS_WIN) | 16 #if defined(OS_WIN) |
16 #include <winternl.h> | 17 #include <winternl.h> |
17 #include "base/win/windows_version.h" | 18 #include "base/win/windows_version.h" |
18 #endif | 19 #endif |
19 | 20 |
20 namespace startup_metric_utils { | 21 namespace startup_metric_utils { |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 // Helper macro for splitting out an UMA histogram based on cold or warm start. | 156 // Helper macro for splitting out an UMA histogram based on cold or warm start. |
156 // |type| is the histogram type, and corresponds to an UMA macro like | 157 // |type| is the histogram type, and corresponds to an UMA macro like |
157 // UMA_HISTOGRAM_LONG_TIMES. It must be itself be a macro that only takes two | 158 // UMA_HISTOGRAM_LONG_TIMES. It must be itself be a macro that only takes two |
158 // parameters. | 159 // parameters. |
159 // |basename| is the basename of the histogram. A histogram of this name will | 160 // |basename| is the basename of the histogram. A histogram of this name will |
160 // always be recorded to. If the startup is either cold or warm then a value | 161 // always be recorded to. If the startup is either cold or warm then a value |
161 // will also be recorded to the histogram with name |basename| and suffix | 162 // will also be recorded to the histogram with name |basename| and suffix |
162 // ".ColdStart" or ".WarmStart", as appropriate. | 163 // ".ColdStart" or ".WarmStart", as appropriate. |
163 // |value_expr| is an expression evaluating to the value to be recorded. This | 164 // |value_expr| is an expression evaluating to the value to be recorded. This |
164 // will be evaluated exactly once and cached, so side effects are not an issue. | 165 // will be evaluated exactly once and cached, so side effects are not an issue. |
165 #define UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE(type, basename, value_expr) { \ | 166 #define UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(type, basename, value_expr) \ |
166 const auto kValue = value_expr; \ | 167 { \ |
167 /* Always record to the base histogram. */ \ | 168 const auto kValue = value_expr; \ |
168 type(basename, kValue); \ | 169 /* Always record to the base histogram. */ \ |
169 /* Record to the cold/warm suffixed histogram as appropriate. */ \ | 170 type(basename, kValue); \ |
170 if (g_startup_temperature == COLD_STARTUP_TEMPERATURE) { \ | 171 /* Record to the cold/warm suffixed histogram as appropriate. */ \ |
171 type(basename ".ColdStartup", kValue); \ | 172 if (g_startup_temperature == COLD_STARTUP_TEMPERATURE) { \ |
172 } else if (g_startup_temperature == WARM_STARTUP_TEMPERATURE) { \ | 173 type(basename ".ColdStartup", kValue); \ |
173 type(basename ".WarmStartup", kValue); \ | 174 } else if (g_startup_temperature == WARM_STARTUP_TEMPERATURE) { \ |
174 } \ | 175 type(basename ".WarmStartup", kValue); \ |
175 } | 176 } \ |
177 } | |
176 | 178 |
179 #define UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE(type, basename, \ | |
180 begin_time, end_time) \ | |
181 { \ | |
182 UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(type, basename, \ | |
183 end_time - begin_time) \ | |
184 TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( \ | |
185 "startup", basename, 0, \ | |
186 StartupTimeToTraceTicks(begin_time).ToInternalValue(), "Temperature", \ | |
187 g_startup_temperature); \ | |
188 TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1( \ | |
189 "startup", basename, 0, \ | |
190 StartupTimeToTraceTicks(end_time).ToInternalValue(), "Temperature", \ | |
191 g_startup_temperature); \ | |
192 } | |
177 | 193 |
178 // On Windows, records the number of hard-faults that have occurred in the | 194 // On Windows, records the number of hard-faults that have occurred in the |
179 // current chrome.exe process since it was started. This is a nop on other | 195 // current chrome.exe process since it was started. This is a nop on other |
180 // platforms. | 196 // platforms. |
181 // crbug.com/476923 | 197 // crbug.com/476923 |
182 // TODO(chrisha): If this proves useful, use it to split startup stats in two. | 198 // TODO(chrisha): If this proves useful, use it to split startup stats in two. |
183 void RecordHardFaultHistogram(bool is_first_run) { | 199 void RecordHardFaultHistogram(bool is_first_run) { |
184 #if defined(OS_WIN) | 200 #if defined(OS_WIN) |
185 uint32_t hard_fault_count = 0; | 201 uint32_t hard_fault_count = 0; |
186 bool has_os_support = false; | 202 bool has_os_support = false; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 } else if (hard_fault_count >= COLD_START_HARD_FAULT_COUNT_THRESHOLD) { | 238 } else if (hard_fault_count >= COLD_START_HARD_FAULT_COUNT_THRESHOLD) { |
223 g_startup_temperature = COLD_STARTUP_TEMPERATURE; | 239 g_startup_temperature = COLD_STARTUP_TEMPERATURE; |
224 } | 240 } |
225 | 241 |
226 // Record the startup 'temperature'. | 242 // Record the startup 'temperature'. |
227 UMA_HISTOGRAM_ENUMERATION( | 243 UMA_HISTOGRAM_ENUMERATION( |
228 "Startup.Temperature", g_startup_temperature, STARTUP_TEMPERATURE_MAX); | 244 "Startup.Temperature", g_startup_temperature, STARTUP_TEMPERATURE_MAX); |
229 #endif // defined(OS_WIN) | 245 #endif // defined(OS_WIN) |
230 } | 246 } |
231 | 247 |
248 // Converts a base::Time value to a base::TraceTicks value. The conversion isn't | |
249 // exact, but is within the time delta taken to synchronously resolve | |
250 // base::Time::Now() and base::TraceTicks::Now() which in practice is pretty | |
251 // much instant compared to multi-seconds startup timings. | |
252 base::TraceTicks StartupTimeToTraceTicks(const base::Time& time) { | |
253 // First get a base which represents the same point in time in both units. | |
254 // The wall clock time it takes to gather both of these is the precision of | |
255 // this method. | |
256 static const base::Time time_base = base::Time::Now(); | |
257 static const base::TraceTicks trace_ticks_base = base::TraceTicks::Now(); | |
258 | |
259 // Then use the TimeDelta common ground between the two units to make the | |
260 // conversion. | |
261 const base::TimeDelta delta_since_base = time_base - time; | |
nduca
2015/10/16 00:22:48
actually, now that i look at this, my lg is only c
gab
2015/10/16 14:39:16
Not sure I understand what you mean here?
| |
262 return trace_ticks_base - delta_since_base; | |
263 } | |
264 | |
232 // Record time of main entry so it can be read from Telemetry performance tests. | 265 // Record time of main entry so it can be read from Telemetry performance tests. |
233 // TODO(jeremy): Remove once crbug.com/317481 is fixed. | 266 // TODO(jeremy): Remove once crbug.com/317481 is fixed. |
234 void RecordMainEntryTimeHistogram() { | 267 void RecordMainEntryTimeHistogram() { |
235 const int kLowWordMask = 0xFFFFFFFF; | 268 const int kLowWordMask = 0xFFFFFFFF; |
236 const int kLower31BitsMask = 0x7FFFFFFF; | 269 const int kLower31BitsMask = 0x7FFFFFFF; |
237 DCHECK(!MainEntryPointTime().is_null()); | 270 DCHECK(!MainEntryPointTime().is_null()); |
238 base::TimeDelta browser_main_entry_time_absolute = | 271 base::TimeDelta browser_main_entry_time_absolute = |
239 MainEntryPointTime() - base::Time::UnixEpoch(); | 272 MainEntryPointTime() - base::Time::UnixEpoch(); |
240 | 273 |
241 uint64 browser_main_entry_time_raw_ms = | 274 uint64 browser_main_entry_time_raw_ms = |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
300 env->SetVar(kChromeMainTimeEnvVar, exe_load_time); | 333 env->SetVar(kChromeMainTimeEnvVar, exe_load_time); |
301 } | 334 } |
302 | 335 |
303 void RecordBrowserMainMessageLoopStart(const base::Time& time, | 336 void RecordBrowserMainMessageLoopStart(const base::Time& time, |
304 bool is_first_run) { | 337 bool is_first_run) { |
305 RecordHardFaultHistogram(is_first_run); | 338 RecordHardFaultHistogram(is_first_run); |
306 RecordMainEntryTimeHistogram(); | 339 RecordMainEntryTimeHistogram(); |
307 | 340 |
308 const base::Time& process_creation_time = g_process_creation_time.Get(); | 341 const base::Time& process_creation_time = g_process_creation_time.Get(); |
309 if (!is_first_run && !process_creation_time.is_null()) { | 342 if (!is_first_run && !process_creation_time.is_null()) { |
310 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 343 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
311 UMA_HISTOGRAM_LONG_TIMES_100, | 344 UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserMessageLoopStartTime", |
312 "Startup.BrowserMessageLoopStartTime", | 345 process_creation_time, time); |
313 time - process_creation_time); | |
314 } | 346 } |
315 | 347 |
316 // Bail if uptime < 7 minutes, to filter out cases where Chrome may have been | 348 // Bail if uptime < 7 minutes, to filter out cases where Chrome may have been |
317 // autostarted and the machine is under io pressure. | 349 // autostarted and the machine is under io pressure. |
318 const int64 kSevenMinutesInMilliseconds = | 350 const int64 kSevenMinutesInMilliseconds = |
319 base::TimeDelta::FromMinutes(7).InMilliseconds(); | 351 base::TimeDelta::FromMinutes(7).InMilliseconds(); |
320 if (base::SysInfo::Uptime() < kSevenMinutesInMilliseconds) | 352 if (base::SysInfo::Uptime() < kSevenMinutesInMilliseconds) |
321 return; | 353 return; |
322 | 354 |
323 // The Startup.BrowserMessageLoopStartTime histogram exhibits instability in | 355 // The Startup.BrowserMessageLoopStartTime histogram exhibits instability in |
324 // the field which limits its usefulness in all scenarios except when we have | 356 // the field which limits its usefulness in all scenarios except when we have |
325 // a very large sample size. Attempt to mitigate this with a new metric: | 357 // a very large sample size. Attempt to mitigate this with a new metric: |
326 // * Measure time from main entry rather than the OS' notion of process start. | 358 // * Measure time from main entry rather than the OS' notion of process start. |
327 // * Only measure launches that occur 7 minutes after boot to try to avoid | 359 // * Only measure launches that occur 7 minutes after boot to try to avoid |
328 // cases where Chrome is auto-started and IO is heavily loaded. | 360 // cases where Chrome is auto-started and IO is heavily loaded. |
329 const base::Time dll_main_time = MainEntryPointTime(); | 361 const base::Time dll_main_time = MainEntryPointTime(); |
330 base::TimeDelta startup_time_from_main_entry = time - dll_main_time; | |
331 if (is_first_run) { | 362 if (is_first_run) { |
332 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 363 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
333 UMA_HISTOGRAM_LONG_TIMES, | 364 UMA_HISTOGRAM_LONG_TIMES, |
334 "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun", | 365 "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun", |
335 startup_time_from_main_entry); | 366 dll_main_time, time); |
336 } else { | 367 } else { |
337 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 368 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
338 UMA_HISTOGRAM_LONG_TIMES, | 369 UMA_HISTOGRAM_LONG_TIMES, |
339 "Startup.BrowserMessageLoopStartTimeFromMainEntry", | 370 "Startup.BrowserMessageLoopStartTimeFromMainEntry", dll_main_time, |
340 startup_time_from_main_entry); | 371 time); |
341 } | 372 } |
342 | 373 |
343 // Record timings between process creation, the main() in the executable being | 374 // Record timings between process creation, the main() in the executable being |
344 // reached and the main() in the shared library being reached. | 375 // reached and the main() in the shared library being reached. |
345 if (!process_creation_time.is_null()) { | 376 if (!process_creation_time.is_null()) { |
346 const base::Time exe_main_time = ExeMainEntryPointTime(); | 377 const base::Time exe_main_time = ExeMainEntryPointTime(); |
347 if (!exe_main_time.is_null()) { | 378 if (!exe_main_time.is_null()) { |
348 // Process create to chrome.exe:main(). | 379 // Process create to chrome.exe:main(). |
349 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 380 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
350 UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToExeMain", | 381 UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToExeMain", |
351 exe_main_time - process_creation_time); | 382 process_creation_time, exe_main_time); |
352 | 383 |
353 // chrome.exe:main() to chrome.dll:main(). | 384 // chrome.exe:main() to chrome.dll:main(). |
354 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 385 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
355 UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ExeMainToDllMain", | 386 UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ExeMainToDllMain", |
356 dll_main_time - exe_main_time); | 387 exe_main_time, dll_main_time); |
357 | 388 |
358 // Process create to chrome.dll:main(). | 389 // Process create to chrome.dll:main(). Reported as a histogram only as |
359 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 390 // the other two events above are sufficient for tracing purposes. |
391 UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE( | |
360 UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToDllMain", | 392 UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToDllMain", |
361 dll_main_time - process_creation_time); | 393 dll_main_time - process_creation_time); |
362 } | 394 } |
363 } | 395 } |
364 } | 396 } |
365 | 397 |
366 void RecordBrowserWindowDisplay(const base::Time& time) { | 398 void RecordBrowserWindowDisplay(const base::Time& time) { |
367 static bool is_first_call = true; | 399 static bool is_first_call = true; |
368 if (!is_first_call || time.is_null()) | 400 if (!is_first_call || time.is_null()) |
369 return; | 401 return; |
370 is_first_call = false; | 402 is_first_call = false; |
371 if (WasNonBrowserUIDisplayed() || g_process_creation_time.Get().is_null()) | 403 if (WasNonBrowserUIDisplayed() || g_process_creation_time.Get().is_null()) |
372 return; | 404 return; |
373 | 405 |
374 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 406 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
375 UMA_HISTOGRAM_LONG_TIMES, "Startup.BrowserWindowDisplay", | 407 UMA_HISTOGRAM_LONG_TIMES, "Startup.BrowserWindowDisplay", |
376 time - g_process_creation_time.Get()); | 408 g_process_creation_time.Get(), time); |
377 } | 409 } |
378 | 410 |
379 void RecordBrowserOpenTabsDelta(const base::TimeDelta& delta) { | 411 void RecordBrowserOpenTabsDelta(const base::TimeDelta& delta) { |
380 static bool is_first_call = true; | 412 static bool is_first_call = true; |
381 if (!is_first_call) | 413 if (!is_first_call) |
382 return; | 414 return; |
383 is_first_call = false; | 415 is_first_call = false; |
384 | 416 |
385 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 417 UMA_HISTOGRAM_WITH_STARTUP_TEMPERATURE(UMA_HISTOGRAM_LONG_TIMES_100, |
386 UMA_HISTOGRAM_LONG_TIMES_100, "Startup.BrowserOpenTabs", delta); | 418 "Startup.BrowserOpenTabs", delta); |
387 } | 419 } |
388 | 420 |
389 void RecordFirstWebContentsMainFrameLoad(const base::Time& time) { | 421 void RecordFirstWebContentsMainFrameLoad(const base::Time& time) { |
390 static bool is_first_call = true; | 422 static bool is_first_call = true; |
391 if (!is_first_call || time.is_null()) | 423 if (!is_first_call || time.is_null()) |
392 return; | 424 return; |
393 is_first_call = false; | 425 is_first_call = false; |
394 if (WasNonBrowserUIDisplayed() || g_process_creation_time.Get().is_null()) | 426 if (WasNonBrowserUIDisplayed() || g_process_creation_time.Get().is_null()) |
395 return; | 427 return; |
396 | 428 |
397 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 429 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
398 UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.MainFrameLoad", | 430 UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.MainFrameLoad", |
399 time - g_process_creation_time.Get()); | 431 g_process_creation_time.Get(), time); |
400 } | 432 } |
401 | 433 |
402 void RecordFirstWebContentsNonEmptyPaint(const base::Time& time) { | 434 void RecordFirstWebContentsNonEmptyPaint(const base::Time& time) { |
403 static bool is_first_call = true; | 435 static bool is_first_call = true; |
404 if (!is_first_call || time.is_null()) | 436 if (!is_first_call || time.is_null()) |
405 return; | 437 return; |
406 is_first_call = false; | 438 is_first_call = false; |
407 if (WasNonBrowserUIDisplayed() || g_process_creation_time.Get().is_null()) | 439 if (WasNonBrowserUIDisplayed() || g_process_creation_time.Get().is_null()) |
408 return; | 440 return; |
409 | 441 |
410 UMA_HISTOGRAM_BY_STARTUP_TEMPERATURE( | 442 UMA_HISTOGRAM_AND_TRACE_WITH_STARTUP_TEMPERATURE( |
411 UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.NonEmptyPaint", | 443 UMA_HISTOGRAM_LONG_TIMES_100, "Startup.FirstWebContents.NonEmptyPaint", |
412 time - g_process_creation_time.Get()); | 444 g_process_creation_time.Get(), time); |
413 } | 445 } |
414 | 446 |
415 base::Time MainEntryPointTime() { | 447 base::Time MainEntryPointTime() { |
416 return g_main_entry_point_time.Get(); | 448 return g_main_entry_point_time.Get(); |
417 } | 449 } |
418 | 450 |
419 StartupTemperature GetStartupTemperature() { | 451 StartupTemperature GetStartupTemperature() { |
420 return g_startup_temperature; | 452 return g_startup_temperature; |
421 } | 453 } |
422 | 454 |
423 } // namespace startup_metric_utils | 455 } // namespace startup_metric_utils |
OLD | NEW |