OLD | NEW |
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 #include "chrome/browser/metrics/thread_watcher.h" | 5 #include "chrome/browser/metrics/thread_watcher.h" |
6 | 6 |
7 #include <math.h> // ceil | 7 #include <math.h> // ceil |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/debug/alias.h" | 11 #include "base/debug/alias.h" |
12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/string_split.h" | 13 #include "base/string_split.h" |
| 14 #include "base/stringprintf.h" |
14 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/string_tokenizer.h" | 16 #include "base/strings/string_tokenizer.h" |
16 #include "base/threading/thread_restrictions.h" | 17 #include "base/threading/thread_restrictions.h" |
17 #include "build/build_config.h" | 18 #include "build/build_config.h" |
18 #include "chrome/browser/metrics/metrics_service.h" | 19 #include "chrome/browser/metrics/metrics_service.h" |
19 #include "chrome/common/chrome_switches.h" | 20 #include "chrome/common/chrome_switches.h" |
20 #include "chrome/common/chrome_version_info.h" | 21 #include "chrome/common/chrome_version_info.h" |
21 #include "chrome/common/dump_without_crashing.h" | 22 #include "chrome/common/dump_without_crashing.h" |
22 #include "chrome/common/logging_chrome.h" | 23 #include "chrome/common/logging_chrome.h" |
23 | 24 |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 ThreadWatcherList* ThreadWatcherList::g_thread_watcher_list_ = NULL; | 402 ThreadWatcherList* ThreadWatcherList::g_thread_watcher_list_ = NULL; |
402 // static | 403 // static |
403 const int ThreadWatcherList::kSleepSeconds = 1; | 404 const int ThreadWatcherList::kSleepSeconds = 1; |
404 // static | 405 // static |
405 const int ThreadWatcherList::kUnresponsiveSeconds = 2; | 406 const int ThreadWatcherList::kUnresponsiveSeconds = 2; |
406 // static | 407 // static |
407 const int ThreadWatcherList::kUnresponsiveCount = 9; | 408 const int ThreadWatcherList::kUnresponsiveCount = 9; |
408 // static | 409 // static |
409 const int ThreadWatcherList::kLiveThreadsThreshold = 3; | 410 const int ThreadWatcherList::kLiveThreadsThreshold = 3; |
410 | 411 |
| 412 ThreadWatcherList::CrashDataThresholds::CrashDataThresholds( |
| 413 uint32 live_threads_threshold, |
| 414 uint32 unresponsive_threshold) |
| 415 : live_threads_threshold(live_threads_threshold), |
| 416 unresponsive_threshold(unresponsive_threshold) { |
| 417 } |
| 418 |
| 419 ThreadWatcherList::CrashDataThresholds::CrashDataThresholds() |
| 420 : live_threads_threshold(kLiveThreadsThreshold), |
| 421 unresponsive_threshold(kUnresponsiveCount) { |
| 422 } |
| 423 |
411 // static | 424 // static |
412 void ThreadWatcherList::StartWatchingAll(const CommandLine& command_line) { | 425 void ThreadWatcherList::StartWatchingAll(const CommandLine& command_line) { |
413 uint32 unresponsive_threshold; | 426 uint32 unresponsive_threshold; |
414 CrashOnHangThreadMap crash_on_hang_threads; | 427 CrashOnHangThreadMap crash_on_hang_threads; |
415 ParseCommandLine(command_line, | 428 ParseCommandLine(command_line, |
416 &unresponsive_threshold, | 429 &unresponsive_threshold, |
417 &crash_on_hang_threads); | 430 &crash_on_hang_threads); |
418 | 431 |
419 ThreadWatcherObserver::SetupNotifications( | 432 ThreadWatcherObserver::SetupNotifications( |
420 base::TimeDelta::FromSeconds(kSleepSeconds * unresponsive_threshold)); | 433 base::TimeDelta::FromSeconds(kSleepSeconds * unresponsive_threshold)); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); | 504 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
492 DCHECK(this == g_thread_watcher_list_); | 505 DCHECK(this == g_thread_watcher_list_); |
493 g_thread_watcher_list_ = NULL; | 506 g_thread_watcher_list_ = NULL; |
494 } | 507 } |
495 | 508 |
496 // static | 509 // static |
497 void ThreadWatcherList::ParseCommandLine( | 510 void ThreadWatcherList::ParseCommandLine( |
498 const CommandLine& command_line, | 511 const CommandLine& command_line, |
499 uint32* unresponsive_threshold, | 512 uint32* unresponsive_threshold, |
500 CrashOnHangThreadMap* crash_on_hang_threads) { | 513 CrashOnHangThreadMap* crash_on_hang_threads) { |
501 // Determine |unresponsive_threshold| based on switches::kCrashOnHangSeconds. | 514 // Initialize |unresponsive_threshold| to a default value. |
502 *unresponsive_threshold = kUnresponsiveCount; | 515 *unresponsive_threshold = kUnresponsiveCount; |
503 | 516 |
504 // Increase the unresponsive_threshold on the Stable and Beta channels to | 517 // Increase the unresponsive_threshold on the Stable and Beta channels to |
505 // reduce the number of crashes due to ThreadWatcher. | 518 // reduce the number of crashes due to ThreadWatcher. |
506 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | 519 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
507 if (channel == chrome::VersionInfo::CHANNEL_STABLE) { | 520 if (channel == chrome::VersionInfo::CHANNEL_STABLE) { |
508 *unresponsive_threshold *= 4; | 521 *unresponsive_threshold *= 4; |
509 } else if (channel == chrome::VersionInfo::CHANNEL_BETA) { | 522 } else if (channel == chrome::VersionInfo::CHANNEL_BETA) { |
510 *unresponsive_threshold *= 2; | 523 *unresponsive_threshold *= 2; |
511 } | 524 } |
512 | 525 |
513 #if defined(OS_WIN) | 526 #if defined(OS_WIN) |
514 // For Windows XP (old systems), double the unresponsive_threshold to give | 527 // For Windows XP (old systems), double the unresponsive_threshold to give |
515 // the OS a chance to schedule UI/IO threads a time slice to respond with a | 528 // the OS a chance to schedule UI/IO threads a time slice to respond with a |
516 // pong message (to get around limitations with the OS). | 529 // pong message (to get around limitations with the OS). |
517 if (base::win::GetVersion() <= base::win::VERSION_XP) | 530 if (base::win::GetVersion() <= base::win::VERSION_XP) |
518 *unresponsive_threshold *= 2; | 531 *unresponsive_threshold *= 2; |
519 #endif | 532 #endif |
520 | 533 |
521 std::string crash_on_hang_seconds = | 534 uint32 crash_seconds = *unresponsive_threshold * kUnresponsiveSeconds; |
522 command_line.GetSwitchValueASCII(switches::kCrashOnHangSeconds); | |
523 if (!crash_on_hang_seconds.empty()) { | |
524 int crash_seconds = atoi(crash_on_hang_seconds.c_str()); | |
525 if (crash_seconds > 0) { | |
526 *unresponsive_threshold = static_cast<uint32>( | |
527 ceil(static_cast<float>(crash_seconds) / kUnresponsiveSeconds)); | |
528 } | |
529 } | |
530 | |
531 std::string crash_on_hang_thread_names; | 535 std::string crash_on_hang_thread_names; |
532 | |
533 // Default to crashing the browser if UI or IO threads are not responsive | |
534 // except in stable channel. | |
535 if (channel == chrome::VersionInfo::CHANNEL_STABLE) | |
536 crash_on_hang_thread_names = ""; | |
537 else | |
538 crash_on_hang_thread_names = "UI:3,IO:9"; | |
539 | |
540 bool has_command_line_overwrite = false; | 536 bool has_command_line_overwrite = false; |
541 if (command_line.HasSwitch(switches::kCrashOnHangThreads)) { | 537 if (command_line.HasSwitch(switches::kCrashOnHangThreads)) { |
542 crash_on_hang_thread_names = | 538 crash_on_hang_thread_names = |
543 command_line.GetSwitchValueASCII(switches::kCrashOnHangThreads); | 539 command_line.GetSwitchValueASCII(switches::kCrashOnHangThreads); |
544 has_command_line_overwrite = true; | 540 has_command_line_overwrite = true; |
| 541 } else if (channel != chrome::VersionInfo::CHANNEL_STABLE) { |
| 542 // Default to crashing the browser if UI or IO or FILE threads are not |
| 543 // responsive except in stable channel. |
| 544 crash_on_hang_thread_names = base::StringPrintf( |
| 545 "UI:%d:%d,IO:%d:%d,FILE:%d:%d", |
| 546 kLiveThreadsThreshold, crash_seconds, |
| 547 kLiveThreadsThreshold, crash_seconds, |
| 548 kLiveThreadsThreshold, crash_seconds * 5); |
545 } | 549 } |
546 base::StringTokenizer tokens(crash_on_hang_thread_names, ","); | 550 |
547 std::vector<std::string> values; | 551 ParseCommandLineCrashOnHangThreads(crash_on_hang_thread_names, |
548 while (tokens.GetNext()) { | 552 kLiveThreadsThreshold, |
549 const std::string& token = tokens.token(); | 553 crash_seconds, |
550 base::SplitString(token, ':', &values); | 554 crash_on_hang_threads); |
551 if (values.size() != 2) | |
552 continue; | |
553 std::string thread_name = values[0]; | |
554 uint32 live_threads_threshold; | |
555 if (!base::StringToUint(values[1], &live_threads_threshold)) | |
556 continue; | |
557 CrashOnHangThreadMap::iterator it = | |
558 crash_on_hang_threads->find(thread_name); | |
559 if (crash_on_hang_threads->end() == it) | |
560 (*crash_on_hang_threads)[thread_name] = live_threads_threshold; | |
561 } | |
562 | 555 |
563 if (channel != chrome::VersionInfo::CHANNEL_CANARY || | 556 if (channel != chrome::VersionInfo::CHANNEL_CANARY || |
564 has_command_line_overwrite) { | 557 has_command_line_overwrite) { |
565 return; | 558 return; |
566 } | 559 } |
567 | 560 |
568 // Set up a field trial for 10% of the users to crash if IO thread is not | 561 // Set up a field trial for 10% of the users to crash if IO thread is not |
569 // responsive. | 562 // responsive. |
570 CrashOnHangThreadMap::iterator it = crash_on_hang_threads->find("IO"); | 563 CrashOnHangThreadMap::iterator it = crash_on_hang_threads->find("IO"); |
571 if (crash_on_hang_threads->end() == it) | 564 if (crash_on_hang_threads->end() == it) |
572 return; | 565 return; |
573 | 566 |
574 scoped_refptr<base::FieldTrial> field_trial( | 567 scoped_refptr<base::FieldTrial> field_trial( |
575 base::FieldTrialList::FactoryGetFieldTrial( | 568 base::FieldTrialList::FactoryGetFieldTrial( |
576 "ThreadWatcher", 100, "default_hung_threads", | 569 "ThreadWatcher", 100, "default_hung_threads", |
577 2013, 10, 30, NULL)); | 570 2013, 10, 30, NULL)); |
578 int io_hung_thread_group = field_trial->AppendGroup("io_hung_thread", 10); | 571 int io_hung_thread_group = field_trial->AppendGroup("io_hung_thread", 10); |
579 if (field_trial->group() == io_hung_thread_group) | 572 if (field_trial->group() == io_hung_thread_group) { |
580 it->second = INT_MAX; // Crash anytime IO thread hangs. | 573 // Crash anytime IO thread hangs. |
| 574 it->second.live_threads_threshold = INT_MAX; |
| 575 } |
| 576 } |
| 577 |
| 578 // static |
| 579 void ThreadWatcherList::ParseCommandLineCrashOnHangThreads( |
| 580 const std::string& crash_on_hang_thread_names, |
| 581 uint32 default_live_threads_threshold, |
| 582 uint32 default_crash_seconds, |
| 583 CrashOnHangThreadMap* crash_on_hang_threads) { |
| 584 base::StringTokenizer tokens(crash_on_hang_thread_names, ","); |
| 585 std::vector<std::string> values; |
| 586 while (tokens.GetNext()) { |
| 587 const std::string& token = tokens.token(); |
| 588 base::SplitString(token, ':', &values); |
| 589 std::string thread_name = values[0]; |
| 590 |
| 591 uint32 live_threads_threshold = default_live_threads_threshold; |
| 592 uint32 crash_seconds = default_crash_seconds; |
| 593 if (values.size() >= 2 && |
| 594 (!base::StringToUint(values[1], &live_threads_threshold))) { |
| 595 continue; |
| 596 } |
| 597 if (values.size() >= 3 && |
| 598 (!base::StringToUint(values[2], &crash_seconds))) { |
| 599 continue; |
| 600 } |
| 601 uint32 unresponsive_threshold = static_cast<uint32>( |
| 602 ceil(static_cast<float>(crash_seconds) / kUnresponsiveSeconds)); |
| 603 |
| 604 CrashDataThresholds crash_data(live_threads_threshold, |
| 605 unresponsive_threshold); |
| 606 // Use the last specifier. |
| 607 (*crash_on_hang_threads)[thread_name] = crash_data; |
| 608 } |
581 } | 609 } |
582 | 610 |
583 // static | 611 // static |
584 void ThreadWatcherList::InitializeAndStartWatching( | 612 void ThreadWatcherList::InitializeAndStartWatching( |
585 uint32 unresponsive_threshold, | 613 uint32 unresponsive_threshold, |
586 const CrashOnHangThreadMap& crash_on_hang_threads) { | 614 const CrashOnHangThreadMap& crash_on_hang_threads) { |
587 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); | 615 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
588 | 616 |
589 ThreadWatcherList* thread_watcher_list = new ThreadWatcherList(); | 617 ThreadWatcherList* thread_watcher_list = new ThreadWatcherList(); |
590 CHECK(thread_watcher_list); | 618 CHECK(thread_watcher_list); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 uint32 unresponsive_threshold, | 651 uint32 unresponsive_threshold, |
624 const CrashOnHangThreadMap& crash_on_hang_threads) { | 652 const CrashOnHangThreadMap& crash_on_hang_threads) { |
625 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); | 653 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); |
626 | 654 |
627 CrashOnHangThreadMap::const_iterator it = | 655 CrashOnHangThreadMap::const_iterator it = |
628 crash_on_hang_threads.find(thread_name); | 656 crash_on_hang_threads.find(thread_name); |
629 bool crash_on_hang = false; | 657 bool crash_on_hang = false; |
630 uint32 live_threads_threshold = 0; | 658 uint32 live_threads_threshold = 0; |
631 if (it != crash_on_hang_threads.end()) { | 659 if (it != crash_on_hang_threads.end()) { |
632 crash_on_hang = true; | 660 crash_on_hang = true; |
633 live_threads_threshold = it->second; | 661 live_threads_threshold = it->second.live_threads_threshold; |
| 662 unresponsive_threshold = it->second.unresponsive_threshold; |
634 } | 663 } |
635 | 664 |
636 ThreadWatcher::StartWatching( | 665 ThreadWatcher::StartWatching( |
637 ThreadWatcher::WatchingParams(thread_id, | 666 ThreadWatcher::WatchingParams(thread_id, |
638 thread_name, | 667 thread_name, |
639 sleep_time, | 668 sleep_time, |
640 unresponsive_time, | 669 unresponsive_time, |
641 unresponsive_threshold, | 670 unresponsive_threshold, |
642 crash_on_hang, | 671 crash_on_hang, |
643 live_threads_threshold)); | 672 live_threads_threshold)); |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 | 969 |
941 #if defined(OS_WIN) | 970 #if defined(OS_WIN) |
942 // On Windows XP, give twice the time for shutdown. | 971 // On Windows XP, give twice the time for shutdown. |
943 if (base::win::GetVersion() <= base::win::VERSION_XP) | 972 if (base::win::GetVersion() <= base::win::VERSION_XP) |
944 actual_duration *= 2; | 973 actual_duration *= 2; |
945 #endif | 974 #endif |
946 | 975 |
947 shutdown_watchdog_ = new ShutdownWatchDogThread(actual_duration); | 976 shutdown_watchdog_ = new ShutdownWatchDogThread(actual_duration); |
948 shutdown_watchdog_->Arm(); | 977 shutdown_watchdog_->Arm(); |
949 } | 978 } |
OLD | NEW |