summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcoryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2007-02-18 22:13:57 +0000
committercoryan <coryan@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2007-02-18 22:13:57 +0000
commit8eb818c9a9577e14a5e9099ae1d5e1a183449155 (patch)
treec3e71971008017d288a5e4e1b2b1ce3b3871f60d
parent2ec6fc334991e336149c36ce4e61fc516c1c9a28 (diff)
downloadATCD-8eb818c9a9577e14a5e9099ae1d5e1a183449155.tar.gz
Sun Feb 18 21:13:41 UTC 2007 coryan <coryan@atdesk.com>
-rw-r--r--ChangeLog8
-rw-r--r--tests/Bug_2815_Regression_Test.cpp416
-rw-r--r--tests/tests.mpc7
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 {