diff options
author | coryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2007-02-18 22:13:57 +0000 |
---|---|---|
committer | coryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2007-02-18 22:13:57 +0000 |
commit | 8eb818c9a9577e14a5e9099ae1d5e1a183449155 (patch) | |
tree | c3e71971008017d288a5e4e1b2b1ce3b3871f60d | |
parent | 2ec6fc334991e336149c36ce4e61fc516c1c9a28 (diff) | |
download | ATCD-8eb818c9a9577e14a5e9099ae1d5e1a183449155.tar.gz |
Sun Feb 18 21:13:41 UTC 2007 coryan <coryan@atdesk.com>
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | tests/Bug_2815_Regression_Test.cpp | 416 | ||||
-rw-r--r-- | tests/tests.mpc | 7 |
3 files changed, 431 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog index d9ef7ca67ec..c88a23cf9bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Feb 18 21:13:41 UTC 2007 coryan <coryan@atdesk.com> + + * tests/tests.mpc: + * tests/Bug_2815_Regression_Test.cpp: + Add new regression test for bug 2815. I have not added the test + to the automated test suite because (1) it fails, and (2) it is + a test to reproduce performance + Fri Feb 16 23:48:55 UTC 2007 Iliyan Jeliazkov <iliyan@ociweb.com> * ace/Service_Config.cpp: diff --git a/tests/Bug_2815_Regression_Test.cpp b/tests/Bug_2815_Regression_Test.cpp new file mode 100644 index 00000000000..654846b71e3 --- /dev/null +++ b/tests/Bug_2815_Regression_Test.cpp @@ -0,0 +1,416 @@ +/** + * @file Bug_2815_Regression_Test.cpp + * + * $Id$ + * + * Verify that the notification queue can be used with large numbers + * of event handlers. + * + * Normally the ACE_Reactor uses a pipe to implement the notify() + * methods. ACE can be compiled with + * ACE_HAS_REACTOR_NOTIFICATION_QUEUE, with this configuration flag + * the Reactor uses a user-space queue to contain the notifications. + * A single message is sent through the pipe to indicate "pipe not + * empty." + * + * In this configuration, if an event handler is removed + * from the Reactor the user-space queue has to be searched for + * pending notifications and the notifications must be removed. + * + * The original implementation used a naive algorithm to search and + * remove the handlers, which resulted in very high overhead when + * removing handlers while having a very long notification queue. + * + * @author Carlos O'Ryan <coryan@atdesk.com> + * + */ + +#include "test_config.h" +#include "ace/Reactor.h" +#include "ace/TP_Reactor.h" +#include "ace/Select_Reactor.h" + +ACE_RCSID(tests, + Bug_2815_Regression_Test, "$Id$") + +class One_Shot_Handler; + +/** + * @class Driver + * + * @brief Main driver for the test, generates notification events and + * verifies they are received correctly. + * + */ +class Driver +{ +public: + Driver(ACE_Reactor * reactor, + int max_notifications, + char const *test_name); + + /// Run the test + void run (void); + + /// One of the sub-handlers has received a notification + void notification_received (); + + /// One of the sub-handlers has decided to skip several notifications + void notifications_skipped (int skip_count); + + /** + * @brief Return the reactor configured for this test + */ + ACE_Reactor * reactor (); + +private: + /** + * @brief Implement a single iteration. + * + * Each iteration of the test consists of sending multiple + * notifications simultaneously. + */ + void send_notifications (void); + + /** + * @brief Return true if the test is finished. + */ + bool done (void) const; + + /** + * @brief Return true if there are more iterations to run. + */ + bool more_iterations () const; + + /** + * @brief Return true if the current iteration is completed. + */ + bool current_iteration_done () const; + + /** + * @brief Run one iteration of the test, each iteration doubles + * the number of events. + */ + int run_one_iteration (void); + + /** + * @brief Initialize a bunch of One_Shot_Handlers + */ + void initialize_handlers( + int nhandlers, One_Shot_Handler ** handlers); + + /** + * @brief Dispatch events to the One_Shot_Handlers + */ + void notify_handlers( + int nhandlers, One_Shot_Handler ** handlers); + +private: + /** + * @brief The reactor used in this test + */ + ACE_Reactor * reactor_; + + /** + * @brief The maximum number of notifications in any single + * iteration. + */ + int max_notifications_; + + /** + * @brief The name of the test + */ + char const * test_name_; + + /** + * @brief Number of notifications received + */ + int notifications_sent_; + + /** + * @brief Number of notifications sent + */ + int notifications_recv_; + + /** + * @brief Number of notifications skipped because + * the handler was removed + */ + int notifications_skipped_; + + /** + * @brief Number of notifications sent on each iteration + */ + int notifications_curr_; +}; + +/** + * @class One_Shot_Handler + * + * @brief A handler that removes itself from the reactor + * after its first notification. + * + * To demonstrate the problems with the first implementation of + * the notification queue we generate multiple event handlers. + * Then we generate multiple notifications for each, but the handlers + * remove themselves from the reactor when the first notification + * is delivered. This causes a lot of activity in the notification + * queue. + * + */ +class One_Shot_Handler : public ACE_Event_Handler +{ +public: + One_Shot_Handler( + Driver * master_handler, + char const * test_name, + int id); + + /// Increase the number of expected notifications + void notification_queued(); + + /// Receive the notifications, but remove itself from the reactor on + /// on the first one. + virtual int handle_exception(ACE_HANDLE); + +private: + /// The driver for this test, communicate results to it + Driver * master_handler_; + + /// The number of expected notifications + int expected_notifications_; + + /// Identify the test and handler for debugging and better error output + char const * test_name_; + int id_; +}; + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Bug_2815_Regression_Test")); + +#if !defined(ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Notification queue disabled, ") + ACE_TEXT ("small test version, ") + ACE_TEXT ("which is of no practical use\n"))); + + int max_notifications = 16; +#else + int max_notifications = 1024 * 1024; +#endif /* ACE_HAS_THREADS */ + + { + ACE_Reactor select_reactor ( + new ACE_Select_Reactor, + 1); + + Driver handler(&select_reactor, + max_notifications, + "Select_Reactor"); + + handler.run (); + } + + { + ACE_Reactor tp_reactor (new ACE_TP_Reactor, + 1); + Driver handler(&tp_reactor, + max_notifications, + "TP_Reactor"); + handler.run(); + } + + ACE_END_TEST; + + return 0; +} + +Driver::Driver ( + ACE_Reactor * reactor, + int max_notifications, + char const * test_name) + : reactor_(reactor) + , max_notifications_(max_notifications) + , test_name_(test_name) + , notifications_sent_(0) + , notifications_recv_(0) + , notifications_skipped_(0) + , notifications_curr_(1) +{ +} + +void +Driver::run (void) +{ + while(more_iterations()) + { + if(run_one_iteration() == -1) + { + return; + } + + notifications_curr_ *= 2; + } + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Test %C passed sent=%d, recv=%d, skip=%d\n"), + test_name_, + notifications_sent_, + notifications_recv_, + notifications_skipped_)); +} + +void +Driver::notification_received () +{ + ++notifications_recv_; +} + +void +Driver::notifications_skipped (int skip_count) +{ + notifications_skipped_ += skip_count; +} + +ACE_Reactor * +Driver::reactor() +{ + return reactor_; +} + +void +Driver::send_notifications (void) +{ + int const nhandlers = 16; + One_Shot_Handler * handlers[nhandlers]; + initialize_handlers(nhandlers, handlers); + + for (int i = 0; i != notifications_curr_; ++i) + { + notify_handlers(nhandlers, handlers); + } +} + +bool +Driver::done (void) const +{ + return !more_iterations() && current_iteration_done(); +} + +bool +Driver::more_iterations() const +{ + return notifications_curr_ < max_notifications_; +} + +bool +Driver::current_iteration_done() const +{ + return notifications_sent_ == (notifications_recv_ + notifications_skipped_); +} + +int +Driver::run_one_iteration (void) +{ + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Running iteration with %d events for %C test\n"), + notifications_curr_, + test_name_)); + + send_notifications (); + + // Run for 30 seconds or until the test is done. + + ACE_Time_Value const timeout(30,0); + + while (!current_iteration_done()) + { + ACE_Time_Value start = ACE_OS::gettimeofday(); + ACE_Time_Value interval(1,0); + reactor()->run_reactor_event_loop(interval); + ACE_Time_Value end = ACE_OS::gettimeofday(); + + if (end - start >= timeout) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Test %C failed due to timeout ") + ACE_TEXT (" sent=%d,recv=%d,skip=%d\n"), + test_name_, + notifications_sent_, + notifications_recv_, + notifications_skipped_)); + return -1; + } + } + + return 0; +} + +void +Driver::initialize_handlers( + int nhandlers, One_Shot_Handler ** handlers) +{ + for (int j = 0; j != nhandlers; ++j) + { + handlers[j] = new One_Shot_Handler(this, test_name_, j); + } +} + +void +Driver::notify_handlers( + int nhandlers, One_Shot_Handler ** handlers) +{ + for(int i = 0; i != nhandlers; ++i) + { + if(reactor()->notify (handlers[i]) == -1) + { + ACE_ERROR((LM_ERROR, + ACE_TEXT ("Cannot send notifications in %C test (%d/%d)\n"), + test_name_, i, notifications_curr_)); + return; + } + handlers[i]->notification_queued(); + + ++notifications_sent_; + } +} + +// ============================================ + +One_Shot_Handler::One_Shot_Handler( + Driver * master_handler, + char const * test_name, int id) + : ACE_Event_Handler(master_handler->reactor()) + , master_handler_(master_handler) + , expected_notifications_(0) + , test_name_(test_name) + , id_(id) +{ +} + +void One_Shot_Handler:: +notification_queued() +{ + ++expected_notifications_; +} + +int One_Shot_Handler:: +handle_exception(ACE_HANDLE) +{ + --expected_notifications_; + master_handler_->notification_received(); + + int r = reactor()->purge_pending_notifications(this); + if (r >= 0) + { + master_handler_->notifications_skipped(r); + return 0; + } + + ACE_ERROR((LM_ERROR, + ACE_TEXT ("Cannot remove handler %d in %C test\n"), + id_, test_name_)); + return -1; +} diff --git a/tests/tests.mpc b/tests/tests.mpc index 64b74caa8aa..a42b0749f53 100644 --- a/tests/tests.mpc +++ b/tests/tests.mpc @@ -234,6 +234,13 @@ project(Bug_2653_Regression_Test) : acetest { } } +project(Bug_2815_Regression_Test) : acetest { + exename = Bug_2815_Regression_Test + Source_Files { + Bug_2815_Regression_Test.cpp + } +} + project(Cache Map Manager Test) : acetest { exename = Cache_Map_Manager_Test Source_Files { |