You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2010/01/13 20:48:09 UTC

svn commit: r898919 - in /incubator/trafficserver/traffic/branches/dev: ./ iocore/cache/ iocore/eventsystem/ iocore/hostdb/ iocore/net/

Author: jplevyak
Date: Wed Jan 13 19:48:07 2010
New Revision: 898919

URL: http://svn.apache.org/viewvc?rev=898919&view=rev
Log:
TS-96: should use eventfd or pipes to signal threads waiting on poll()
TS-86: HTTP cache miss latency
This checkin uses eventfd if available and otherwise uses pipes to knock
a thread off waiting poll if an event arrives.
It also reduces the number of cross thread events for DNS and cache syncing
by scheduling on the current thread if possible.
With this check TS is now capable of 1400+ misses per second with a single client
(latency less than 1ms on a cache miss).

Modified:
    incubator/trafficserver/traffic/branches/dev/configure.ac
    incubator/trafficserver/traffic/branches/dev/iocore/cache/CacheDir.cc
    incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/I_EThread.h
    incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/ProtectedQueue.cc
    incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/UnixEThread.cc
    incubator/trafficserver/traffic/branches/dev/iocore/hostdb/HostDB.cc
    incubator/trafficserver/traffic/branches/dev/iocore/net/P_UnixNet.h
    incubator/trafficserver/traffic/branches/dev/iocore/net/UnixNet.cc

Modified: incubator/trafficserver/traffic/branches/dev/configure.ac
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/configure.ac?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/configure.ac (original)
+++ incubator/trafficserver/traffic/branches/dev/configure.ac Wed Jan 13 19:48:07 2010
@@ -466,7 +466,7 @@
     AC_MSG_FAILURE([No DB interface found])
 fi
 
-AC_CHECK_FUNCS([clock_gettime kqueue epoll_ctl posix_memalign lrand48_r srand48_r])
+AC_CHECK_FUNCS([clock_gettime kqueue epoll_ctl posix_memalign lrand48_r srand48_r eventfd])
 
 if test "x$enable_libev" = "xyes"; then
    AC_DEFINE([USE_LIBEV])
@@ -481,6 +481,7 @@
    AC_MSG_FAILURE([No suitable polling interface found])
 fi
 
+
 # For SunPro 5.2 - we need the demangle symbol for
 #  ink_stack_trace.cc in libinktomi++.  Because this
 #  library is part of the SunPro distribution, we need

Modified: incubator/trafficserver/traffic/branches/dev/iocore/cache/CacheDir.cc
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/cache/CacheDir.cc?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/cache/CacheDir.cc (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/cache/CacheDir.cc Wed Jan 13 19:48:07 2010
@@ -1027,7 +1027,10 @@
       buflen = 0;
     }
     Debug("cache_dir_sync", "sync done");
-    trigger = eventProcessor.schedule_in(this, HRTIME_SECONDS(cache_config_dir_sync_frequency));
+    if (event == EVENT_INTERVAL)
+      trigger = e->ethread->schedule_in(this, HRTIME_SECONDS(cache_config_dir_sync_frequency));
+    else
+      trigger = eventProcessor.schedule_in(this, HRTIME_SECONDS(cache_config_dir_sync_frequency));
     return EVENT_CONT;
   }
   if (event == AIO_EVENT_DONE) {

Modified: incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/I_EThread.h
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/I_EThread.h?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/I_EThread.h (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/I_EThread.h Wed Jan 13 19:48:07 2010
@@ -29,7 +29,6 @@
 #include "I_Thread.h"
 #include "I_PriorityEventQueue.h"
 #include "I_ProxyAllocator.h"
-
 #include "I_ProtectedQueue.h"
 
 #define PER_THREAD_DATA (1024*1024)
@@ -46,6 +45,7 @@
 struct LogEventForwarder;
 struct Event;
 struct SessionBucket;
+struct EventIO;
 
 class IOBufferData;
 class IOBufferBlock;
@@ -331,6 +331,14 @@
   void execute();
   void process_event(Event * e, int calling_code);
   void free_event(Event * e);
+  void (*signal_hook)(EThread *);
+
+#ifdef HAVE_EVENTFD
+  int evfd;
+#else
+  int evpipe[2];
+#endif
+  EventIO *ep;
 
   ThreadType tt;
   Event *oneevent;              // For dedicated event thread

Modified: incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/ProtectedQueue.cc
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/ProtectedQueue.cc?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/ProtectedQueue.cc (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/ProtectedQueue.cc Wed Jan 13 19:48:07 2010
@@ -123,6 +123,8 @@
   for (i = 0; i < n; i++) {
     if (thr->ethreads_to_be_signalled[i]) {
       thr->ethreads_to_be_signalled[i]->EventQueueExternal.signal();
+      if (thr->ethreads_to_be_signalled[i]->signal_hook)
+        thr->ethreads_to_be_signalled[i]->signal_hook(thr->ethreads_to_be_signalled[i]);
       thr->ethreads_to_be_signalled[i] = 0;
     }
   }

Modified: incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/UnixEThread.cc
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/UnixEThread.cc?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/UnixEThread.cc (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/eventsystem/UnixEThread.cc Wed Jan 13 19:48:07 2010
@@ -29,6 +29,8 @@
 #include "ink_unused.h"      /* MAGIC_EDITING_TAG */
 #include "P_EventSystem.h"
 
+extern "C" int eventfd(unsigned int initval, int flags);
+
 struct AIOCallback;
 
 #define MAX_HEARTBEATS_MISSED         	10
@@ -41,7 +43,9 @@
    ethreads_to_be_signalled(NULL),
    n_ethreads_to_be_signalled(0),
    main_accept_index(-1),
-   id(NO_ETHREAD_ID), event_types(0), tt(REGULAR), eventsem(NULL)
+   id(NO_ETHREAD_ID), event_types(0), 
+   signal_hook(0),
+   tt(REGULAR), eventsem(NULL)
 {
   memset(thread_private, 0, PER_THREAD_DATA);
 }
@@ -53,12 +57,26 @@
     main_accept_index(-1),
     id(anid),
     event_types(0),
+    signal_hook(0),
     tt(att),
     eventsem(NULL)
 {
   ethreads_to_be_signalled = (EThread **) xmalloc(MAX_EVENT_THREADS * sizeof(EThread *));
   memset((char *) ethreads_to_be_signalled, 0, MAX_EVENT_THREADS * sizeof(EThread *));
   memset(thread_private, 0, PER_THREAD_DATA);
+#ifdef HAVE_EVENTFD
+  evfd = eventfd(0, O_NONBLOCK | O_CLOEXEC);
+  if (evfd < 0)
+    ink_release_assert((evfd = eventfd(0,0)) >= 0);
+  fcntl(evfd, F_SETFD, O_CLOEXEC);
+  fcntl(evfd, F_SETFL, O_NONBLOCK);
+#else
+  ink_release_assert(pipe(evpipe) >= 0); 
+  fcntl(evpipe[0], F_SETFD, O_CLOEXEC);
+  fcntl(evpipe[0], F_SETFL, O_NONBLOCK);
+  fcntl(evpipe[1], F_SETFD, O_CLOEXEC);
+  fcntl(evpipe[1], F_SETFL, O_NONBLOCK);
+#endif
 }
 
 EThread::EThread(ThreadType att, Event * e, ink_sem * sem)
@@ -66,7 +84,9 @@
    ethreads_to_be_signalled(NULL),
    n_ethreads_to_be_signalled(0),
    main_accept_index(-1),
-   id(NO_ETHREAD_ID), event_types(0), tt(att), oneevent(e), eventsem(sem)
+   id(NO_ETHREAD_ID), event_types(0), 
+   signal_hook(0),
+   tt(att), oneevent(e), eventsem(sem)
 {
   ink_assert(att == DEDICATED);
   memset(thread_private, 0, PER_THREAD_DATA);

Modified: incubator/trafficserver/traffic/branches/dev/iocore/hostdb/HostDB.cc
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/hostdb/HostDB.cc?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/hostdb/HostDB.cc (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/hostdb/HostDB.cc Wed Jan 13 19:48:07 2010
@@ -944,11 +944,15 @@
   // Since ProxyMutexPtr has a cast operator, gcc-3.x get upset
   // about ambiguity when doing this comparison, so by reversing
   // the operands, I force it to pick the cast operation /leif.
+#ifdef USE_NCA
   if (thread->mutex == cont->mutex) {
     thread->schedule_in(c, MUTEX_RETRY_DELAY);
   } else {
     dnsProcessor.thread->schedule_imm(c);
   }
+#else
+  thread->schedule_in(c, MUTEX_RETRY_DELAY);
+#endif
 
   return &c->action;
 }

Modified: incubator/trafficserver/traffic/branches/dev/iocore/net/P_UnixNet.h
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/net/P_UnixNet.h?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/net/P_UnixNet.h (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/net/P_UnixNet.h Wed Jan 13 19:48:07 2010
@@ -114,6 +114,7 @@
 #define EVENTIO_READWRITE_VC		2
 #define EVENTIO_DNS_CONNECTION		3
 #define EVENTIO_UDP_CONNECTION		4
+#define EVENTIO_ASYNC_SIGNAL		5
 
 #if defined(USE_LIBEV)
 #define EVENTIO_READ EV_READ
@@ -192,8 +193,7 @@
 #define MAX_NET_BUCKETS                           256
 #define MAX_EPOLL_ARRAY_SIZE                      (1024*16)
 #define MAX_EPOLL_TIMEOUT                         50    /* mseconds */
-#define DEFAULT_EPOLL_TIMEOUT                     10    /* mseconds */
-#define REAL_DEFAULT_EPOLL_TIMEOUT                3     /* the define above is old code [ebalsa] -- this directly effects latency of the connections. */
+#define DEFAULT_POLL_TIMEOUT                      10    /* mseconds */
 
 #define NET_THROTTLE_DELAY                        50    /* mseconds */
 #define INK_MIN_PRIORITY                          0
@@ -655,34 +655,4 @@
 
 #endif
 
-
-#ifndef INACTIVITY_TIMEOUT
-// INKqa10496
-// One Inactivity cop runs on each thread once every second and
-// loops through the list of NetVCs and calls the timeouts
-struct InactivityCop:public Continuation
-{
-  InactivityCop(ProxyMutex * m):Continuation(m)
-  {
-    SET_HANDLER(&InactivityCop::check_inactivity);
-  }
-  int check_inactivity(int event, Event * e)
-  {
-    (void) event;
-    ink_hrtime now = ink_get_hrtime();
-    NetHandler *nh = get_NetHandler(this_ethread());
-    UnixNetVConnection * vc = nh->open_list.head, *vc_next = 0;
-    while (vc) {
-      vc_next = (UnixNetVConnection*)vc->link.next;
-      if (vc->inactivity_timeout_in && vc->next_inactivity_timeout_at && vc->next_inactivity_timeout_at < now)
-        vc->handleEvent(EVENT_IMMEDIATE, e);
-      else
-        if (vc->closed)
-          close_UnixNetVConnection(vc, e->ethread);
-      vc = vc_next;
-    }
-    return 0;
-  }
-};
-#endif
 #endif

Modified: incubator/trafficserver/traffic/branches/dev/iocore/net/UnixNet.cc
URL: http://svn.apache.org/viewvc/incubator/trafficserver/traffic/branches/dev/iocore/net/UnixNet.cc?rev=898919&r1=898918&r2=898919&view=diff
==============================================================================
--- incubator/trafficserver/traffic/branches/dev/iocore/net/UnixNet.cc (original)
+++ incubator/trafficserver/traffic/branches/dev/iocore/net/UnixNet.cc Wed Jan 13 19:48:07 2010
@@ -33,15 +33,46 @@
 
 extern "C" void fd_reify(struct ev_loop *);
 
-PollCont::PollCont(ProxyMutex * m):Continuation(m), net_handler(NULL), poll_timeout(REAL_DEFAULT_EPOLL_TIMEOUT)
+
+#ifndef INACTIVITY_TIMEOUT
+// INKqa10496
+// One Inactivity cop runs on each thread once every second and
+// loops through the list of NetVCs and calls the timeouts
+struct InactivityCop:public Continuation
+{
+  InactivityCop(ProxyMutex *m):Continuation(m)
+  {
+    SET_HANDLER(&InactivityCop::check_inactivity);
+  }
+  int check_inactivity(int event, Event *e)
+  {
+    (void) event;
+    ink_hrtime now = ink_get_hrtime();
+    NetHandler *nh = get_NetHandler(this_ethread());
+    UnixNetVConnection *vc = nh->open_list.head, *vc_next = 0;
+    while (vc) {
+      vc_next = (UnixNetVConnection*)vc->link.next;
+      if (vc->inactivity_timeout_in && vc->next_inactivity_timeout_at && vc->next_inactivity_timeout_at < now)
+        vc->handleEvent(EVENT_IMMEDIATE, e);
+      else
+        if (vc->closed)
+          close_UnixNetVConnection(vc, e->ethread);
+      vc = vc_next;
+    }
+    return 0;
+  }
+};
+#endif
+
+PollCont::PollCont(ProxyMutex *m):Continuation(m), net_handler(NULL), poll_timeout(DEFAULT_POLL_TIMEOUT)
 {
   pollDescriptor = NEW(new PollDescriptor);
   pollDescriptor->init();
   SET_HANDLER(&PollCont::pollEvent);
 }
 
-PollCont::PollCont(ProxyMutex * m, NetHandler * nh):Continuation(m), net_handler(nh),
-poll_timeout(REAL_DEFAULT_EPOLL_TIMEOUT)
+PollCont::PollCont(ProxyMutex *m, NetHandler *nh):Continuation(m), net_handler(nh),
+poll_timeout(DEFAULT_POLL_TIMEOUT)
 {
   pollDescriptor = NEW(new PollDescriptor);
   pollDescriptor->init();
@@ -59,7 +90,7 @@
 // and stores the resultant events in ePoll_Triggered_Events
 //
 int
-PollCont::pollEvent(int event, Event * e)
+PollCont::pollEvent(int event, Event *e)
 {
   (void) event;
   (void) e;
@@ -74,7 +105,7 @@
             net_handler->write_enable_list.empty());
       poll_timeout = 0;         //poll immediately returns -- we have triggered stuff to process right now
     } else {
-      poll_timeout = REAL_DEFAULT_EPOLL_TIMEOUT;
+      poll_timeout = DEFAULT_POLL_TIMEOUT;
     }
   }
   // wait for fd's to tigger, or don't wait if timeout is 0
@@ -106,8 +137,30 @@
   return EVENT_CONT;
 }
 
+static void
+net_signal_hook_callback(EThread *thread) {
+#if HAVE_EVENTFD
+  inku64 counter;
+  read(thread->evfd, &counter, sizeof(inku64));
+#else
+  char dummy;
+  read(thread->evpipe[0], &dummy, 1);
+#endif  
+}
+
+static void
+net_signal_hook_function(EThread *thread) {
+#if HAVE_EVENTFD
+  inku64 counter = 1;
+  write(thread->evfd, &counter, sizeof(inku64));
+#else
+  char dummy;
+  write(thread->evpipe[0], &dummy, 1);
+#endif  
+}
+
 void
-initialize_thread_for_net(EThread * thread, int thread_index)
+initialize_thread_for_net(EThread *thread, int thread_index)
 {
   static bool poll_delay_read = false;
   int max_poll_delay;           // max poll delay in milliseconds
@@ -123,9 +176,9 @@
   new((ink_dummy_for_new *) get_NetHandler(thread)) NetHandler();
   new((ink_dummy_for_new *) get_PollCont(thread)) PollCont(thread->mutex, get_NetHandler(thread));
   get_NetHandler(thread)->mutex = new_ProxyMutex();
-#if defined(USE_LIBEV)
   PollCont *pc = get_PollCont(thread);
   PollDescriptor *pd = pc->pollDescriptor;
+#if defined(USE_LIBEV)
   if (!thread_index)
     pd->eio = ev_default_loop(0);
   else
@@ -137,6 +190,15 @@
   InactivityCop *inactivityCop = NEW(new InactivityCop(get_NetHandler(thread)->mutex));
   thread->schedule_every(inactivityCop, HRTIME_SECONDS(1));
 #endif
+
+  thread->signal_hook = net_signal_hook_function;
+  thread->ep = (EventIO*)malloc(sizeof(EventIO));
+  thread->ep->type = EVENTIO_ASYNC_SIGNAL;
+#if HAVE_EVENTFD
+  thread->ep->start(pd, thread->evfd, 0, EVENTIO_READ);
+#else
+  thread->ep->start(pd, thread->evpipe[0], 0, EVENTIO_READ);
+#endif
 }
 
 // NetHandler method definitions
@@ -151,7 +213,7 @@
 // from now on.
 //
 int
-NetHandler::startNetEvent(int event, Event * e)
+NetHandler::startNetEvent(int event, Event *e)
 {
   (void) event;
   SET_HANDLER((NetContHandler) & NetHandler::mainNetEvent);
@@ -164,7 +226,7 @@
 // Move VC's enabled on a different thread to the ready list
 //
 void
-NetHandler::process_enabled_list(NetHandler * nh, EThread * t)
+NetHandler::process_enabled_list(NetHandler *nh, EThread *t)
 {
   UnixNetVConnection *vc = NULL;
 
@@ -192,13 +254,13 @@
 // for this period.
 //
 int
-NetHandler::mainNetEvent(int event, Event * e)
+NetHandler::mainNetEvent(int event, Event *e)
 {
   ink_assert(trigger_event == e && (event == EVENT_INTERVAL || event == EVENT_POLL));
   (void) event;
   (void) e;
   EventIO *epd = NULL;
-  int poll_timeout = REAL_DEFAULT_EPOLL_TIMEOUT;
+  int poll_timeout = DEFAULT_POLL_TIMEOUT;
 
   NET_INCREMENT_DYN_STAT(net_handler_run_stat);
 
@@ -207,7 +269,7 @@
              !read_enable_list.empty() || !write_enable_list.empty()))
     poll_timeout = 0; // poll immediately returns -- we have triggered stuff to process right now
   else
-    poll_timeout = REAL_DEFAULT_EPOLL_TIMEOUT;
+    poll_timeout = DEFAULT_POLL_TIMEOUT;
 
   PollDescriptor *pd = get_PollDescriptor(trigger_event->ethread);
   UnixNetVConnection *vc = NULL;
@@ -264,7 +326,8 @@
     } else if (epd->type == EVENTIO_DNS_CONNECTION) {
       if (epd->data.dnscon != NULL)
         dnsqueue.enqueue(epd->data.dnscon);
-    }
+    } else if (epd->type == EVENTIO_ASYNC_SIGNAL)
+      net_signal_hook_callback(trigger_event->ethread);
     ev_next_event(pd);
   }