Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <math.h> // ceil | |
|
jar (doing other things)
2011/06/18 15:04:16
nit: I'm not used to seeing mention of the functio
ramant (doing other things)
2011/06/19 21:18:16
Done.
| |
| 6 | |
| 5 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 6 #include "base/logging.h" | 8 #include "base/logging.h" |
| 7 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 9 #include "base/message_loop_proxy.h" | 11 #include "base/message_loop_proxy.h" |
| 12 #include "base/string_tokenizer.h" | |
| 10 #include "base/synchronization/condition_variable.h" | 13 #include "base/synchronization/condition_variable.h" |
| 11 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
| 12 #include "base/threading/platform_thread.h" | 15 #include "base/threading/platform_thread.h" |
| 13 #include "base/time.h" | 16 #include "base/time.h" |
| 14 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 15 #include "chrome/browser/metrics/thread_watcher.h" | 18 #include "chrome/browser/metrics/thread_watcher.h" |
| 19 #include "chrome/common/chrome_switches.h" | |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 17 #include "testing/platform_test.h" | 21 #include "testing/platform_test.h" |
| 18 | 22 |
| 19 using base::TimeDelta; | 23 using base::TimeDelta; |
| 20 using base::TimeTicks; | 24 using base::TimeTicks; |
| 21 | 25 |
| 22 enum State { | 26 enum State { |
| 23 INITIALIZED, // Created ThreadWatch object. | 27 INITIALIZED, // Created ThreadWatch object. |
| 24 ACTIVATED, // Thread watching activated. | 28 ACTIVATED, // Thread watching activated. |
| 25 SENT_PING, // Sent ping message to watched thread. | 29 SENT_PING, // Sent ping message to watched thread. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 uint64 pong_received_; | 61 uint64 pong_received_; |
| 58 uint64 success_response_; | 62 uint64 success_response_; |
| 59 uint64 failed_response_; | 63 uint64 failed_response_; |
| 60 base::TimeTicks saved_ping_time_; | 64 base::TimeTicks saved_ping_time_; |
| 61 uint64 saved_ping_sequence_number_; | 65 uint64 saved_ping_sequence_number_; |
| 62 | 66 |
| 63 CustomThreadWatcher(const BrowserThread::ID thread_id, | 67 CustomThreadWatcher(const BrowserThread::ID thread_id, |
| 64 const std::string thread_name, | 68 const std::string thread_name, |
| 65 const TimeDelta& sleep_time, | 69 const TimeDelta& sleep_time, |
| 66 const TimeDelta& unresponsive_time) | 70 const TimeDelta& unresponsive_time) |
| 67 : ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time), | 71 : ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time, |
| 72 ThreadWatcherList::kUnresponsiveCount, true, | |
| 73 ThreadWatcherList::kLiveThreadsThreshold), | |
| 68 state_changed_(&custom_lock_), | 74 state_changed_(&custom_lock_), |
| 69 thread_watcher_state_(INITIALIZED), | 75 thread_watcher_state_(INITIALIZED), |
| 70 wait_state_(UNINITIALIZED), | 76 wait_state_(UNINITIALIZED), |
| 71 check_response_state_(UNKNOWN), | 77 check_response_state_(UNKNOWN), |
| 72 ping_sent_(0), | 78 ping_sent_(0), |
| 73 pong_received_(0), | 79 pong_received_(0), |
| 74 success_response_(0), | 80 success_response_(0), |
| 75 failed_response_(0), | 81 failed_response_(0), |
| 76 saved_ping_time_(base::TimeTicks::Now()), | 82 saved_ping_time_(base::TimeTicks::Now()), |
| 77 saved_ping_sequence_number_(0) { | 83 saved_ping_sequence_number_(0) { |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 226 DISABLE_RUNNABLE_METHOD_REFCOUNT(CustomThreadWatcher); | 232 DISABLE_RUNNABLE_METHOD_REFCOUNT(CustomThreadWatcher); |
| 227 | 233 |
| 228 class ThreadWatcherTest : public ::testing::Test { | 234 class ThreadWatcherTest : public ::testing::Test { |
| 229 public: | 235 public: |
| 230 static const TimeDelta kSleepTime; | 236 static const TimeDelta kSleepTime; |
| 231 static const TimeDelta kUnresponsiveTime; | 237 static const TimeDelta kUnresponsiveTime; |
| 232 static const BrowserThread::ID io_thread_id; | 238 static const BrowserThread::ID io_thread_id; |
| 233 static const std::string io_thread_name; | 239 static const std::string io_thread_name; |
| 234 static const BrowserThread::ID webkit_thread_id; | 240 static const BrowserThread::ID webkit_thread_id; |
| 235 static const std::string webkit_thread_name; | 241 static const std::string webkit_thread_name; |
| 242 static const std::string crash_on_hang_seconds; | |
| 243 static const std::string crash_on_hang_threads; | |
| 244 static const std::string crash_on_live; | |
| 236 CustomThreadWatcher* io_watcher_; | 245 CustomThreadWatcher* io_watcher_; |
| 237 CustomThreadWatcher* webkit_watcher_; | 246 CustomThreadWatcher* webkit_watcher_; |
| 247 ThreadWatcherList* thread_watcher_list_; | |
| 238 | 248 |
| 239 ThreadWatcherTest() { | 249 ThreadWatcherTest() : setup_complete_(&lock_), |
|
jar (doing other things)
2011/06/18 15:04:16
style nit: I think you have to put the initializer
ramant (doing other things)
2011/06/19 21:18:16
Done.
| |
| 250 initialized_(false) { | |
| 240 webkit_thread_.reset(new BrowserThread(BrowserThread::WEBKIT)); | 251 webkit_thread_.reset(new BrowserThread(BrowserThread::WEBKIT)); |
| 241 io_thread_.reset(new BrowserThread(BrowserThread::IO)); | 252 io_thread_.reset(new BrowserThread(BrowserThread::IO)); |
| 242 watchdog_thread_.reset(new WatchDogThread()); | 253 watchdog_thread_.reset(new WatchDogThread()); |
| 243 webkit_thread_->Start(); | 254 webkit_thread_->Start(); |
| 244 io_thread_->Start(); | 255 io_thread_->Start(); |
| 245 watchdog_thread_->Start(); | 256 watchdog_thread_->Start(); |
| 246 | 257 |
| 258 WatchDogThread::PostTask( | |
| 259 FROM_HERE, | |
| 260 NewRunnableMethod(this, &ThreadWatcherTest::SetUpObjects)); | |
| 261 | |
| 262 WaitForSetUp(TimeDelta::FromMinutes(1)); | |
| 263 } | |
| 264 | |
| 265 void SetUpObjects() { | |
| 266 DCHECK(WatchDogThread::CurrentlyOnWatchDogThread()); | |
| 267 | |
| 247 // Setup the registry for thread watchers. | 268 // Setup the registry for thread watchers. |
| 248 thread_watcher_list_ = new ThreadWatcherList(); | 269 thread_watcher_list_ = new ThreadWatcherList(); |
| 249 | 270 |
| 250 // Create thread watcher object for the IO thread. | 271 // Create thread watcher object for the IO thread. |
| 251 io_watcher_ = new CustomThreadWatcher(io_thread_id, io_thread_name, | 272 io_watcher_ = new CustomThreadWatcher(io_thread_id, io_thread_name, |
| 252 kSleepTime, kUnresponsiveTime); | 273 kSleepTime, kUnresponsiveTime); |
| 274 EXPECT_EQ(io_watcher_, thread_watcher_list_->Find(io_thread_id)); | |
| 253 | 275 |
| 254 // Create thread watcher object for the WEBKIT thread. | 276 // Create thread watcher object for the WEBKIT thread. |
| 255 webkit_watcher_ = new CustomThreadWatcher( | 277 webkit_watcher_ = new CustomThreadWatcher( |
| 256 webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime); | 278 webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime); |
| 279 EXPECT_EQ(webkit_watcher_, thread_watcher_list_->Find(webkit_thread_id)); | |
| 280 | |
| 281 { | |
| 282 base::AutoLock lock(lock_); | |
| 283 initialized_ = true; | |
| 284 } | |
| 285 setup_complete_.Signal(); | |
| 286 } | |
| 287 | |
| 288 void WaitForSetUp(TimeDelta wait_time) { | |
| 289 DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread()); | |
| 290 TimeTicks end_time = TimeTicks::Now() + wait_time; | |
| 291 { | |
| 292 base::AutoLock auto_lock(lock_); | |
| 293 while (!initialized_ && TimeTicks::Now() < end_time) | |
| 294 setup_complete_.TimedWait(end_time - TimeTicks::Now()); | |
| 295 } | |
| 257 } | 296 } |
| 258 | 297 |
| 259 ~ThreadWatcherTest() { | 298 ~ThreadWatcherTest() { |
| 260 ThreadWatcherList::StopWatchingAll(); | 299 ThreadWatcherList::DeleteAll(); |
| 261 io_watcher_ = NULL; | 300 io_watcher_ = NULL; |
| 262 webkit_watcher_ = NULL; | 301 webkit_watcher_ = NULL; |
| 263 io_thread_.reset(); | 302 io_thread_.reset(); |
| 264 webkit_thread_.reset(); | 303 webkit_thread_.reset(); |
| 265 watchdog_thread_.reset(); | 304 watchdog_thread_.reset(); |
| 266 delete thread_watcher_list_; | 305 thread_watcher_list_ = NULL; |
| 267 } | 306 } |
| 268 | 307 |
| 269 private: | 308 private: |
| 309 base::Lock lock_; | |
| 310 base::ConditionVariable setup_complete_; | |
| 311 bool initialized_; | |
| 270 scoped_ptr<BrowserThread> webkit_thread_; | 312 scoped_ptr<BrowserThread> webkit_thread_; |
| 271 scoped_ptr<BrowserThread> io_thread_; | 313 scoped_ptr<BrowserThread> io_thread_; |
| 272 scoped_ptr<WatchDogThread> watchdog_thread_; | 314 scoped_ptr<WatchDogThread> watchdog_thread_; |
| 273 ThreadWatcherList* thread_watcher_list_; | |
| 274 }; | 315 }; |
| 275 | 316 |
| 317 // DISABLE_RUNNABLE_METHOD_REFCOUNT is a convenience macro for disabling | |
| 318 // refcounting of ThreadWatcherTest classes. | |
| 319 DISABLE_RUNNABLE_METHOD_REFCOUNT(ThreadWatcherTest); | |
| 320 | |
| 276 // Define static constants. | 321 // Define static constants. |
| 277 const TimeDelta ThreadWatcherTest::kSleepTime = | 322 const TimeDelta ThreadWatcherTest::kSleepTime = |
| 278 TimeDelta::FromMilliseconds(50); | 323 TimeDelta::FromMilliseconds(50); |
| 279 const TimeDelta ThreadWatcherTest::kUnresponsiveTime = | 324 const TimeDelta ThreadWatcherTest::kUnresponsiveTime = |
| 280 TimeDelta::FromMilliseconds(500); | 325 TimeDelta::FromMilliseconds(500); |
| 281 const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO; | 326 const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO; |
| 282 const std::string ThreadWatcherTest::io_thread_name = "IO"; | 327 const std::string ThreadWatcherTest::io_thread_name = "IO"; |
| 283 const BrowserThread::ID ThreadWatcherTest::webkit_thread_id = | 328 const BrowserThread::ID ThreadWatcherTest::webkit_thread_id = |
| 284 BrowserThread::WEBKIT; | 329 BrowserThread::WEBKIT; |
| 285 const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT"; | 330 const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT"; |
| 331 const std::string ThreadWatcherTest::crash_on_hang_seconds = "24"; | |
| 332 const std::string ThreadWatcherTest::crash_on_hang_threads = "IO,UI"; | |
| 333 const std::string ThreadWatcherTest::crash_on_live = "3"; | |
| 334 | |
| 335 TEST_F(ThreadWatcherTest, CommandLineArgs) { | |
| 336 // Setup command_line arguments. | |
| 337 CommandLine command_line(CommandLine::NO_PROGRAM); | |
| 338 command_line.AppendSwitchASCII(switches::kCrashOnHangSeconds, | |
| 339 crash_on_hang_seconds); | |
| 340 command_line.AppendSwitchASCII(switches::kCrashOnHangThreads, | |
| 341 crash_on_hang_threads); | |
| 342 command_line.AppendSwitchASCII(switches::kCrashOnLive, | |
| 343 crash_on_live); | |
| 344 | |
| 345 // Parse command_line arguments. | |
| 346 uint32 unresponsive_threshold; | |
| 347 std::set<std::string> crash_on_hang_thread_names; | |
| 348 uint32 live_threads_threshold; | |
| 349 ThreadWatcherList::ParseCommandLine(command_line, | |
| 350 &unresponsive_threshold, | |
| 351 &crash_on_hang_thread_names, | |
| 352 &live_threads_threshold); | |
| 353 | |
| 354 // Verify the data. | |
| 355 uint32 crash_on_unresponsive_seconds = | |
| 356 ThreadWatcherList::kUnresponsiveSeconds * unresponsive_threshold; | |
| 357 EXPECT_EQ(static_cast<int>(crash_on_unresponsive_seconds), | |
| 358 atoi(crash_on_hang_seconds.c_str())); | |
| 359 | |
| 360 // Check ThreadWatcherTestList has the right crash_on_hang_threads. | |
| 361 StringTokenizer tokens(crash_on_hang_threads, ","); | |
| 362 while (tokens.GetNext()) { | |
| 363 std::string thread_name = tokens.token(); | |
| 364 std::set<std::string>::iterator it = | |
| 365 crash_on_hang_thread_names.find(thread_name); | |
| 366 bool crash_on_hang = (it != crash_on_hang_thread_names.end()); | |
| 367 EXPECT_TRUE(crash_on_hang); | |
| 368 } | |
| 369 | |
| 370 EXPECT_EQ(static_cast<int>(live_threads_threshold), | |
| 371 atoi(crash_on_live.c_str())); | |
| 372 } | |
| 286 | 373 |
| 287 // Test registration. When thread_watcher_list_ goes out of scope after | 374 // Test registration. When thread_watcher_list_ goes out of scope after |
| 288 // TearDown, all thread watcher objects will be deleted. | 375 // TearDown, all thread watcher objects will be deleted. |
| 289 TEST_F(ThreadWatcherTest, Registration) { | 376 TEST_F(ThreadWatcherTest, Registration) { |
| 290 EXPECT_EQ(io_watcher_, ThreadWatcherList::Find(io_thread_id)); | |
| 291 EXPECT_EQ(webkit_watcher_, ThreadWatcherList::Find(webkit_thread_id)); | |
| 292 | |
| 293 // Check ThreadWatcher object has all correct parameters. | 377 // Check ThreadWatcher object has all correct parameters. |
| 294 EXPECT_EQ(io_thread_id, io_watcher_->thread_id()); | 378 EXPECT_EQ(io_thread_id, io_watcher_->thread_id()); |
| 295 EXPECT_EQ(io_thread_name, io_watcher_->thread_name()); | 379 EXPECT_EQ(io_thread_name, io_watcher_->thread_name()); |
| 296 EXPECT_EQ(kSleepTime, io_watcher_->sleep_time()); | 380 EXPECT_EQ(kSleepTime, io_watcher_->sleep_time()); |
| 297 EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time()); | 381 EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time()); |
| 298 EXPECT_FALSE(io_watcher_->active()); | 382 EXPECT_FALSE(io_watcher_->active()); |
| 299 | 383 |
| 300 // Check ThreadWatcher object of watched WEBKIT thread has correct data. | 384 // Check ThreadWatcher object of watched WEBKIT thread has correct data. |
| 301 EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id()); | 385 EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id()); |
| 302 EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name()); | 386 EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name()); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 456 FROM_HERE, | 540 FROM_HERE, |
| 457 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); | 541 NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching)); |
| 458 WatchDogThread::PostTask( | 542 WatchDogThread::PostTask( |
| 459 FROM_HERE, | 543 FROM_HERE, |
| 460 NewRunnableMethod( | 544 NewRunnableMethod( |
| 461 webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching)); | 545 webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching)); |
| 462 | 546 |
| 463 // Wait for the io_watcher_'s VeryLongMethod to finish. | 547 // Wait for the io_watcher_'s VeryLongMethod to finish. |
| 464 io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE); | 548 io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE); |
| 465 } | 549 } |
| OLD | NEW |