Home | History | Annotate | Download | only in metrics
      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
      3 // found in the LICENSE file.
      4 
      5 #include "base/basictypes.h"
      6 #include "base/logging.h"
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/message_loop.h"
      9 #include "base/message_loop_proxy.h"
     10 #include "base/synchronization/condition_variable.h"
     11 #include "base/synchronization/lock.h"
     12 #include "base/threading/platform_thread.h"
     13 #include "base/time.h"
     14 #include "build/build_config.h"
     15 #include "chrome/browser/metrics/thread_watcher.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 #include "testing/platform_test.h"
     18 
     19 using base::TimeDelta;
     20 using base::TimeTicks;
     21 
     22 enum State {
     23   INITIALIZED,        // Created ThreadWatch object.
     24   ACTIVATED,          // Thread watching activated.
     25   SENT_PING,          // Sent ping message to watched thread.
     26   RECEIVED_PONG,      // Received Pong message.
     27   DEACTIVATED,        // Thread watching de-activated.
     28 };
     29 
     30 enum WaitState {
     31   UNINITIALIZED,
     32   STARTED_WAITING,    // Start waiting for state_ to change to expected_state.
     33   STOPPED_WAITING,    // Done with the waiting.
     34   ALL_DONE,           // Done with waiting for STOPPED_WAITING.
     35 };
     36 
     37 enum CheckResponseState {
     38   UNKNOWN,
     39   SUCCESSFUL,         // CheckResponse was successful.
     40   FAILED,             // CheckResponse has failed.
     41 };
     42 
     43 // This class helps to track and manipulate thread state during tests. This
     44 // class also has utility method to simulate hanging of watched thread by making
     45 // the watched thread wait for a very long time by posting a task on watched
     46 // thread that keeps it busy. It also has an utility method to block running of
     47 // tests until ThreadWatcher object's post-condition state changes to an
     48 // expected state.
     49 class CustomThreadWatcher : public ThreadWatcher {
     50  public:
     51   base::Lock custom_lock_;
     52   base::ConditionVariable state_changed_;
     53   State thread_watcher_state_;
     54   WaitState wait_state_;
     55   CheckResponseState check_response_state_;
     56   uint64 ping_sent_;
     57   uint64 pong_received_;
     58   uint64 success_response_;
     59   uint64 failed_response_;
     60   base::TimeTicks saved_ping_time_;
     61   uint64 saved_ping_sequence_number_;
     62 
     63   CustomThreadWatcher(const BrowserThread::ID thread_id,
     64                       const std::string thread_name,
     65                       const TimeDelta& sleep_time,
     66                       const TimeDelta& unresponsive_time)
     67       : ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time),
     68         state_changed_(&custom_lock_),
     69         thread_watcher_state_(INITIALIZED),
     70         wait_state_(UNINITIALIZED),
     71         check_response_state_(UNKNOWN),
     72         ping_sent_(0),
     73         pong_received_(0),
     74         success_response_(0),
     75         failed_response_(0),
     76         saved_ping_time_(base::TimeTicks::Now()),
     77         saved_ping_sequence_number_(0) {
     78   }
     79 
     80   State UpdateState(State new_state) {
     81     State old_state;
     82     {
     83       base::AutoLock auto_lock(custom_lock_);
     84       old_state = thread_watcher_state_;
     85       if (old_state != DEACTIVATED)
     86         thread_watcher_state_ = new_state;
     87       if (new_state == SENT_PING)
     88         ++ping_sent_;
     89       if (new_state == RECEIVED_PONG)
     90         ++pong_received_;
     91       saved_ping_time_ = ping_time();
     92       saved_ping_sequence_number_ = ping_sequence_number();
     93     }
     94     state_changed_.Broadcast();
     95     return old_state;
     96   }
     97 
     98   WaitState UpdateWaitState(WaitState new_state) {
     99     WaitState old_state;
    100     {
    101       base::AutoLock auto_lock(custom_lock_);
    102       old_state = wait_state_;
    103       wait_state_ = new_state;
    104     }
    105     state_changed_.Broadcast();
    106     return old_state;
    107   }
    108 
    109   void ActivateThreadWatching() {
    110     State old_state = UpdateState(ACTIVATED);
    111     EXPECT_EQ(old_state, INITIALIZED);
    112     ThreadWatcher::ActivateThreadWatching();
    113   }
    114 
    115   void DeActivateThreadWatching() {
    116     State old_state = UpdateState(DEACTIVATED);
    117     EXPECT_TRUE(old_state == ACTIVATED || old_state == SENT_PING ||
    118                 old_state == RECEIVED_PONG);
    119     ThreadWatcher::DeActivateThreadWatching();
    120   }
    121 
    122   void PostPingMessage() {
    123     State old_state = UpdateState(SENT_PING);
    124     EXPECT_TRUE(old_state == ACTIVATED || old_state == RECEIVED_PONG);
    125     ThreadWatcher::PostPingMessage();
    126   }
    127 
    128   void OnPongMessage(uint64 ping_sequence_number) {
    129     State old_state = UpdateState(RECEIVED_PONG);
    130     EXPECT_TRUE(old_state == SENT_PING || old_state == DEACTIVATED);
    131     ThreadWatcher::OnPongMessage(ping_sequence_number);
    132   }
    133 
    134   bool OnCheckResponsiveness(uint64 ping_sequence_number) {
    135     bool responsive =
    136         ThreadWatcher::OnCheckResponsiveness(ping_sequence_number);
    137     {
    138       base::AutoLock auto_lock(custom_lock_);
    139       if (responsive) {
    140         ++success_response_;
    141         check_response_state_ = SUCCESSFUL;
    142       } else {
    143         ++failed_response_;
    144         check_response_state_ = FAILED;
    145       }
    146     }
    147     // Broadcast to indicate we have checked responsiveness of the thread that
    148     // is watched.
    149     state_changed_.Broadcast();
    150     return responsive;
    151   }
    152 
    153   void WaitForWaitStateChange(TimeDelta wait_time, WaitState expected_state) {
    154     DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread());
    155     TimeTicks end_time = TimeTicks::Now() + wait_time;
    156     {
    157       base::AutoLock auto_lock(custom_lock_);
    158       while (wait_state_ != expected_state && TimeTicks::Now() < end_time)
    159         state_changed_.TimedWait(end_time - TimeTicks::Now());
    160     }
    161   }
    162 
    163   void VeryLongMethod(TimeDelta wait_time) {
    164     DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread());
    165     WaitForWaitStateChange(wait_time, STOPPED_WAITING);
    166     UpdateWaitState(ALL_DONE);
    167   }
    168 
    169   State WaitForStateChange(const TimeDelta& wait_time, State expected_state) {
    170     DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread());
    171     UpdateWaitState(STARTED_WAITING);
    172 
    173     State exit_state;
    174     // Keep the thread that is running the tests waiting until ThreadWatcher
    175     // object's state changes to the expected_state or until wait_time elapses.
    176     for (int i = 0; i < 3; ++i) {
    177         TimeTicks end_time = TimeTicks::Now() + wait_time;
    178         {
    179           base::AutoLock auto_lock(custom_lock_);
    180           while (thread_watcher_state_ != expected_state &&
    181                  TimeTicks::Now() < end_time) {
    182             TimeDelta state_change_wait_time = end_time - TimeTicks::Now();
    183             state_changed_.TimedWait(state_change_wait_time);
    184           }
    185           // Capture the thread_watcher_state_ before it changes and return it
    186           // to the caller.
    187           exit_state = thread_watcher_state_;
    188           if (exit_state == expected_state)
    189             break;
    190         }
    191     }
    192     UpdateWaitState(STOPPED_WAITING);
    193     return exit_state;
    194   }
    195 
    196   CheckResponseState WaitForCheckResponse(const TimeDelta& wait_time,
    197                                           CheckResponseState expected_state) {
    198     DCHECK(!WatchDogThread::CurrentlyOnWatchDogThread());
    199     UpdateWaitState(STARTED_WAITING);
    200 
    201     CheckResponseState exit_state;
    202     // Keep the thread that is running the tests waiting until ThreadWatcher
    203     // object's check_response_state_ changes to the expected_state or until
    204     // wait_time elapses.
    205     for (int i = 0; i < 3; ++i) {
    206         TimeTicks end_time = TimeTicks::Now() + wait_time;
    207         {
    208           base::AutoLock auto_lock(custom_lock_);
    209           while (check_response_state_ != expected_state &&
    210                  TimeTicks::Now() < end_time) {
    211             TimeDelta state_change_wait_time = end_time - TimeTicks::Now();
    212             state_changed_.TimedWait(state_change_wait_time);
    213           }
    214           // Capture the check_response_state_ before it changes and return it
    215           // to the caller.
    216           exit_state = check_response_state_;
    217           if (exit_state == expected_state)
    218             break;
    219         }
    220     }
    221     UpdateWaitState(STOPPED_WAITING);
    222     return exit_state;
    223   }
    224 };
    225 
    226 DISABLE_RUNNABLE_METHOD_REFCOUNT(CustomThreadWatcher);
    227 
    228 class ThreadWatcherTest : public ::testing::Test {
    229  public:
    230   static const TimeDelta kSleepTime;
    231   static const TimeDelta kUnresponsiveTime;
    232   static const BrowserThread::ID io_thread_id;
    233   static const std::string io_thread_name;
    234   static const BrowserThread::ID webkit_thread_id;
    235   static const std::string webkit_thread_name;
    236   CustomThreadWatcher* io_watcher_;
    237   CustomThreadWatcher* webkit_watcher_;
    238 
    239   ThreadWatcherTest() {
    240     webkit_thread_.reset(new BrowserThread(BrowserThread::WEBKIT));
    241     io_thread_.reset(new BrowserThread(BrowserThread::IO));
    242     watchdog_thread_.reset(new WatchDogThread());
    243     webkit_thread_->Start();
    244     io_thread_->Start();
    245     watchdog_thread_->Start();
    246 
    247     // Setup the registry for thread watchers.
    248     thread_watcher_list_ = new ThreadWatcherList();
    249 
    250     // Create thread watcher object for the IO thread.
    251     io_watcher_ = new CustomThreadWatcher(io_thread_id, io_thread_name,
    252                                           kSleepTime, kUnresponsiveTime);
    253 
    254     // Create thread watcher object for the WEBKIT thread.
    255     webkit_watcher_ = new CustomThreadWatcher(
    256         webkit_thread_id, webkit_thread_name, kSleepTime, kUnresponsiveTime);
    257   }
    258 
    259   ~ThreadWatcherTest() {
    260     ThreadWatcherList::StopWatchingAll();
    261     io_watcher_ = NULL;
    262     webkit_watcher_ = NULL;
    263     io_thread_.reset();
    264     webkit_thread_.reset();
    265     watchdog_thread_.reset();
    266     delete thread_watcher_list_;
    267   }
    268 
    269  private:
    270   scoped_ptr<BrowserThread> webkit_thread_;
    271   scoped_ptr<BrowserThread> io_thread_;
    272   scoped_ptr<WatchDogThread> watchdog_thread_;
    273   ThreadWatcherList* thread_watcher_list_;
    274 };
    275 
    276 // Define static constants.
    277 const TimeDelta ThreadWatcherTest::kSleepTime =
    278     TimeDelta::FromMilliseconds(50);
    279 const TimeDelta ThreadWatcherTest::kUnresponsiveTime =
    280     TimeDelta::FromMilliseconds(500);
    281 const BrowserThread::ID ThreadWatcherTest::io_thread_id = BrowserThread::IO;
    282 const std::string ThreadWatcherTest::io_thread_name = "IO";
    283 const BrowserThread::ID ThreadWatcherTest::webkit_thread_id =
    284     BrowserThread::WEBKIT;
    285 const std::string ThreadWatcherTest::webkit_thread_name = "WEBKIT";
    286 
    287 // Test registration. When thread_watcher_list_ goes out of scope after
    288 // TearDown, all thread watcher objects will be deleted.
    289 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.
    294   EXPECT_EQ(io_thread_id, io_watcher_->thread_id());
    295   EXPECT_EQ(io_thread_name, io_watcher_->thread_name());
    296   EXPECT_EQ(kSleepTime, io_watcher_->sleep_time());
    297   EXPECT_EQ(kUnresponsiveTime, io_watcher_->unresponsive_time());
    298   EXPECT_FALSE(io_watcher_->active());
    299 
    300   // Check ThreadWatcher object of watched WEBKIT thread has correct data.
    301   EXPECT_EQ(webkit_thread_id, webkit_watcher_->thread_id());
    302   EXPECT_EQ(webkit_thread_name, webkit_watcher_->thread_name());
    303   EXPECT_EQ(kSleepTime, webkit_watcher_->sleep_time());
    304   EXPECT_EQ(kUnresponsiveTime, webkit_watcher_->unresponsive_time());
    305   EXPECT_FALSE(webkit_watcher_->active());
    306 }
    307 
    308 // Test ActivateThreadWatching and DeActivateThreadWatching of IO thread. This
    309 // method also checks that pong message was sent by the watched thread and pong
    310 // message was received by the WatchDogThread. It also checks that
    311 // OnCheckResponsiveness has verified the ping-pong mechanism and the watched
    312 // thread is not hung.
    313 TEST_F(ThreadWatcherTest, ThreadResponding) {
    314   TimeTicks time_before_ping = TimeTicks::Now();
    315   // Activate watching IO thread.
    316   WatchDogThread::PostTask(
    317       FROM_HERE,
    318       NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching));
    319 
    320   // Activate would have started ping/pong messaging. Expect atleast one
    321   // ping/pong messaging sequence to happen.
    322   io_watcher_->WaitForStateChange(kSleepTime + TimeDelta::FromMinutes(1),
    323                                   RECEIVED_PONG);
    324   EXPECT_GT(io_watcher_->ping_sent_, static_cast<uint64>(0));
    325   EXPECT_GT(io_watcher_->pong_received_, static_cast<uint64>(0));
    326   EXPECT_TRUE(io_watcher_->active());
    327   EXPECT_GE(io_watcher_->saved_ping_time_, time_before_ping);
    328   EXPECT_GE(io_watcher_->saved_ping_sequence_number_, static_cast<uint64>(0));
    329 
    330   // Verify watched thread is responding with ping/pong messaging.
    331   io_watcher_->WaitForCheckResponse(
    332       kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
    333   EXPECT_GT(io_watcher_->success_response_, static_cast<uint64>(0));
    334   EXPECT_EQ(io_watcher_->failed_response_, static_cast<uint64>(0));
    335 
    336   // DeActivate thread watching for shutdown.
    337   WatchDogThread::PostTask(
    338       FROM_HERE,
    339       NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching));
    340 }
    341 
    342 // This test posts a task on watched thread that takes very long time (this is
    343 // to simulate hanging of watched thread). It then checks for
    344 // OnCheckResponsiveness raising an alert (OnCheckResponsiveness returns false
    345 // if the watched thread is not responding).
    346 TEST_F(ThreadWatcherTest, ThreadNotResponding) {
    347   // Simulate hanging of watched thread by making the watched thread wait for a
    348   // very long time by posting a task on watched thread that keeps it busy.
    349   BrowserThread::PostTask(
    350       io_thread_id,
    351       FROM_HERE,
    352       NewRunnableMethod(
    353           io_watcher_,
    354           &CustomThreadWatcher::VeryLongMethod,
    355           kUnresponsiveTime * 10));
    356 
    357   // Activate thread watching.
    358   WatchDogThread::PostTask(
    359       FROM_HERE,
    360       NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching));
    361 
    362   // Verify watched thread is not responding for ping messages.
    363   io_watcher_->WaitForCheckResponse(
    364       kUnresponsiveTime + TimeDelta::FromMinutes(1), FAILED);
    365   EXPECT_EQ(io_watcher_->success_response_, static_cast<uint64>(0));
    366   EXPECT_GT(io_watcher_->failed_response_, static_cast<uint64>(0));
    367 
    368   // DeActivate thread watching for shutdown.
    369   WatchDogThread::PostTask(
    370       FROM_HERE,
    371       NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching));
    372 
    373   // Wait for the io_watcher_'s VeryLongMethod to finish.
    374   io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE);
    375 }
    376 
    377 // Test watching of multiple threads with all threads not responding.
    378 TEST_F(ThreadWatcherTest, MultipleThreadsResponding) {
    379   // Check for WEBKIT thread to perform ping/pong messaging.
    380   WatchDogThread::PostTask(
    381       FROM_HERE,
    382       NewRunnableMethod(
    383           webkit_watcher_, &ThreadWatcher::ActivateThreadWatching));
    384 
    385   // Check for IO thread to perform ping/pong messaging.
    386   WatchDogThread::PostTask(
    387       FROM_HERE,
    388       NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching));
    389 
    390   // Verify WEBKIT thread is responding with ping/pong messaging.
    391   webkit_watcher_->WaitForCheckResponse(
    392       kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
    393   EXPECT_GT(webkit_watcher_->ping_sent_, static_cast<uint64>(0));
    394   EXPECT_GT(webkit_watcher_->pong_received_, static_cast<uint64>(0));
    395   EXPECT_GE(webkit_watcher_->ping_sequence_number_, static_cast<uint64>(0));
    396   EXPECT_GT(webkit_watcher_->success_response_, static_cast<uint64>(0));
    397   EXPECT_EQ(webkit_watcher_->failed_response_, static_cast<uint64>(0));
    398 
    399   // Verify IO thread is responding with ping/pong messaging.
    400   io_watcher_->WaitForCheckResponse(
    401       kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
    402   EXPECT_GT(io_watcher_->ping_sent_, static_cast<uint64>(0));
    403   EXPECT_GT(io_watcher_->pong_received_, static_cast<uint64>(0));
    404   EXPECT_GE(io_watcher_->ping_sequence_number_, static_cast<uint64>(0));
    405   EXPECT_GT(io_watcher_->success_response_, static_cast<uint64>(0));
    406   EXPECT_EQ(io_watcher_->failed_response_, static_cast<uint64>(0));
    407 
    408   // DeActivate thread watching for shutdown.
    409   WatchDogThread::PostTask(
    410       FROM_HERE,
    411       NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching));
    412 
    413   WatchDogThread::PostTask(
    414       FROM_HERE,
    415       NewRunnableMethod(
    416           webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching));
    417 }
    418 
    419 // Test watching of multiple threads with one of the threads not responding.
    420 TEST_F(ThreadWatcherTest, MultipleThreadsNotResponding) {
    421   // Simulate hanging of watched thread by making the watched thread wait for a
    422   // very long time by posting a task on watched thread that keeps it busy.
    423   BrowserThread::PostTask(
    424       io_thread_id,
    425       FROM_HERE,
    426       NewRunnableMethod(
    427           io_watcher_,
    428           &CustomThreadWatcher::VeryLongMethod,
    429           kUnresponsiveTime * 10));
    430 
    431   // Activate watching of WEBKIT thread.
    432   WatchDogThread::PostTask(
    433       FROM_HERE,
    434       NewRunnableMethod(
    435           webkit_watcher_, &ThreadWatcher::ActivateThreadWatching));
    436 
    437   // Activate watching of IO thread.
    438   WatchDogThread::PostTask(
    439       FROM_HERE,
    440       NewRunnableMethod(io_watcher_, &ThreadWatcher::ActivateThreadWatching));
    441 
    442   // Verify WEBKIT thread is responding with ping/pong messaging.
    443   webkit_watcher_->WaitForCheckResponse(
    444       kUnresponsiveTime + TimeDelta::FromMinutes(1), SUCCESSFUL);
    445   EXPECT_GT(webkit_watcher_->success_response_, static_cast<uint64>(0));
    446   EXPECT_EQ(webkit_watcher_->failed_response_, static_cast<uint64>(0));
    447 
    448   // Verify IO thread is not responding for ping messages.
    449   io_watcher_->WaitForCheckResponse(
    450       kUnresponsiveTime + TimeDelta::FromMinutes(1), FAILED);
    451   EXPECT_EQ(io_watcher_->success_response_, static_cast<uint64>(0));
    452   EXPECT_GT(io_watcher_->failed_response_, static_cast<uint64>(0));
    453 
    454   // DeActivate thread watching for shutdown.
    455   WatchDogThread::PostTask(
    456       FROM_HERE,
    457       NewRunnableMethod(io_watcher_, &ThreadWatcher::DeActivateThreadWatching));
    458   WatchDogThread::PostTask(
    459       FROM_HERE,
    460       NewRunnableMethod(
    461           webkit_watcher_, &ThreadWatcher::DeActivateThreadWatching));
    462 
    463   // Wait for the io_watcher_'s VeryLongMethod to finish.
    464   io_watcher_->WaitForWaitStateChange(kUnresponsiveTime * 10, ALL_DONE);
    465 }
    466