Browse Source

Merge branch 'iocp_option'

Nick Mathewson 15 years ago
parent
commit
3efaa30727

+ 3 - 0
changes/bufferevent-support

@@ -6,4 +6,7 @@
      flag.  Using this feature will make our networking code more flexible,
      flag.  Using this feature will make our networking code more flexible,
      lets us stack layers on each other, and let us use more efficient
      lets us stack layers on each other, and let us use more efficient
      zero-copy transports where available.
      zero-copy transports where available.
+   - As an experimental feature, when using the "bufferevents" buffered
+     IO backend, Tor can try to use Windows's IOCP networking API.  This
+     is off by default.  To turn it on, add "DisableIOCP 0" to your torrc.
 
 

+ 3 - 0
changes/cpudetect

@@ -0,0 +1,3 @@
+  o Minor features
+    - If you set the NumCPUs option to 0, Tor will try to detect how many
+      CPUs you have.  This is the new default behavior.

+ 1 - 1
configure.in

@@ -226,7 +226,7 @@ dnl -------------------------------------------------------------------
 dnl Check for functions before libevent, since libevent-1.2 apparently
 dnl Check for functions before libevent, since libevent-1.2 apparently
 dnl exports strlcpy without defining it in a header.
 dnl exports strlcpy without defining it in a header.
 
 
-AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit strlcat strlcpy strtoull getaddrinfo localtime_r gmtime_r memmem strtok_r flock prctl vasprintf)
+AC_CHECK_FUNCS(gettimeofday ftime socketpair uname inet_aton strptime getrlimit strlcat strlcpy strtoull getaddrinfo localtime_r gmtime_r memmem strtok_r flock prctl vasprintf sysconf)
 
 
 using_custom_malloc=no
 using_custom_malloc=no
 if test x$enable_openbsd_malloc = xyes ; then
 if test x$enable_openbsd_malloc = xyes ; then

+ 8 - 1
doc/tor.1.txt

@@ -397,6 +397,11 @@ Other options can be specified either on the command-line (--option
     networkstatus. This is an advanced option; you generally shouldn't have
     networkstatus. This is an advanced option; you generally shouldn't have
     to mess with it. (Default: not set.)
     to mess with it. (Default: not set.)
 
 
+**DisableIOCP** **0**|**1**::
+    If Tor was built to use the Libevent's "bufferevents" networking code
+    and you're running on Windows, setting this option to 1 will tell Libevent
+    not to use the Windows IOCP networking API.  (Default: 1)
+
 CLIENT OPTIONS
 CLIENT OPTIONS
 --------------
 --------------
 
 
@@ -855,7 +860,9 @@ is non-zero):
     characters inclusive, and must contain only the characters [a-zA-Z0-9].
     characters inclusive, and must contain only the characters [a-zA-Z0-9].
 
 
 **NumCPUs** __num__::
 **NumCPUs** __num__::
-    How many processes to use at once for decrypting onionskins. (Default: 1)
+    How many processes to use at once for decrypting onionskins and other
+    parallelizable operations.  If this is set to 0, Tor will try to detect
+    how many CPUs you have, defaulting to 1 if it can't tell.  (Default: 0)
 
 
 **ORPort** __PORT__::
 **ORPort** __PORT__::
     Advertise this port to listen for connections from Tor clients and servers.
     Advertise this port to listen for connections from Tor clients and servers.

+ 46 - 0
src/common/compat.c

@@ -1898,6 +1898,52 @@ spawn_exit(void)
 #endif
 #endif
 }
 }
 
 
+/** Implementation logic for compute_num_cpus(). */
+static int
+compute_num_cpus_impl(void)
+{
+#ifdef MS_WINDOWS
+  SYSTEM_INFO info;
+  memset(&info, 0, sizeof(info));
+  GetSystemInfo(&info);
+  if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX)
+    return (int)info.dwNumberOfProcessors;
+  else
+    return -1;
+#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_CONF)
+  long cpus = sysconf(_SC_NPROCESSORS_CONF);
+  if (cpus >= 1 && cpus < INT_MAX)
+    return (int)cpus;
+  else
+    return -1;
+#else
+  return -1;
+#endif
+}
+
+#define MAX_DETECTABLE_CPUS 16
+
+/** Return how many CPUs we are running with.  We assume that nobody is
+ * using hot-swappable CPUs, so we don't recompute this after the first
+ * time.  Return -1 if we don't know how to tell the number of CPUs on this
+ * system.
+ */
+int
+compute_num_cpus(void)
+{
+  static int num_cpus = -2;
+  if (num_cpus == -2) {
+    num_cpus = compute_num_cpus_impl();
+    tor_assert(num_cpus != -2);
+    if (num_cpus > MAX_DETECTABLE_CPUS)
+      log_notice(LD_GENERAL, "Wow!  I detected that you have %d CPUs. I "
+                 "will not autodetect any more than %d, though.  If you "
+                 "want to configure more, set NumCPUs in your torrc",
+                 num_cpus, MAX_DETECTABLE_CPUS);
+  }
+  return num_cpus;
+}
+
 /** Set *timeval to the current time of day.  On error, log and terminate.
 /** Set *timeval to the current time of day.  On error, log and terminate.
  * (Same as gettimeofday(timeval,NULL), but never returns -1.)
  * (Same as gettimeofday(timeval,NULL), but never returns -1.)
  */
  */

+ 2 - 0
src/common/compat.h

@@ -522,6 +522,8 @@ void spawn_exit(void) ATTR_NORETURN;
 #undef TOR_IS_MULTITHREADED
 #undef TOR_IS_MULTITHREADED
 #endif
 #endif
 
 
+int compute_num_cpus(void);
+
 /* Because we use threads instead of processes on most platforms (Windows,
 /* Because we use threads instead of processes on most platforms (Windows,
  * Linux, etc), we need locking for them.  On platforms with poor thread
  * Linux, etc), we need locking for them.  On platforms with poor thread
  * support or broken gethostbyname_r, these functions are no-ops. */
  * support or broken gethostbyname_r, these functions are no-ops. */

+ 16 - 2
src/common/compat_libevent.c

@@ -159,7 +159,7 @@ struct event_base *the_event_base = NULL;
 
 
 /** Initialize the Libevent library and set up the event base. */
 /** Initialize the Libevent library and set up the event base. */
 void
 void
-tor_libevent_initialize(void)
+tor_libevent_initialize(tor_libevent_cfg *torcfg)
 {
 {
   tor_assert(the_event_base == NULL);
   tor_assert(the_event_base == NULL);
 
 
@@ -171,7 +171,21 @@ tor_libevent_initialize(void)
 #endif
 #endif
 
 
 #ifdef HAVE_EVENT2_EVENT_H
 #ifdef HAVE_EVENT2_EVENT_H
-  the_event_base = event_base_new();
+  {
+    struct event_config *cfg = event_config_new();
+
+#if defined(MS_WINDOWS) && defined(USE_BUFFEREVENTS)
+    if (! torcfg->disable_iocp)
+      event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
+#endif
+
+#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
+    if (torcfg->num_cpus > 0)
+      event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
+#endif
+
+    the_event_base = event_base_new_with_config(cfg);
+  }
 #else
 #else
   the_event_base = event_init();
   the_event_base = event_init();
 #endif
 #endif

+ 6 - 1
src/common/compat_libevent.h

@@ -56,7 +56,12 @@ struct timeval;
 int tor_event_base_loopexit(struct event_base *base, struct timeval *tv);
 int tor_event_base_loopexit(struct event_base *base, struct timeval *tv);
 #endif
 #endif
 
 
-void tor_libevent_initialize(void);
+typedef struct tor_libevent_cfg {
+  int disable_iocp;
+  int num_cpus;
+} tor_libevent_cfg;
+
+void tor_libevent_initialize(tor_libevent_cfg *cfg);
 struct event_base *tor_libevent_get_base(void);
 struct event_base *tor_libevent_get_base(void);
 const char *tor_libevent_get_method(void);
 const char *tor_libevent_get_method(void);
 void tor_check_libevent_version(const char *m, int server,
 void tor_check_libevent_version(const char *m, int server,

+ 26 - 5
src/or/config.c

@@ -224,6 +224,7 @@ static config_var_t _option_vars[] = {
   V(DirReqStatistics,            BOOL,     "0"),
   V(DirReqStatistics,            BOOL,     "0"),
   VAR("DirServer",               LINELIST, DirServers, NULL),
   VAR("DirServer",               LINELIST, DirServers, NULL),
   V(DisableAllSwap,              BOOL,     "0"),
   V(DisableAllSwap,              BOOL,     "0"),
+  V(DisableIOCP,                 BOOL,     "1"),
   V(DNSPort,                     UINT,     "0"),
   V(DNSPort,                     UINT,     "0"),
   V(DNSListenAddress,            LINELIST, NULL),
   V(DNSListenAddress,            LINELIST, NULL),
   V(DownloadExtraInfo,           BOOL,     "0"),
   V(DownloadExtraInfo,           BOOL,     "0"),
@@ -306,7 +307,7 @@ static config_var_t _option_vars[] = {
   V(WarnUnsafeSocks,              BOOL,     "1"),
   V(WarnUnsafeSocks,              BOOL,     "1"),
   V(NoPublish,                   BOOL,     "0"),
   V(NoPublish,                   BOOL,     "0"),
   VAR("NodeFamily",              LINELIST, NodeFamilies,         NULL),
   VAR("NodeFamily",              LINELIST, NodeFamilies,         NULL),
-  V(NumCpus,                     UINT,     "1"),
+  V(NumCpus,                     UINT,     "0"),
   V(NumEntryGuards,              UINT,     "3"),
   V(NumEntryGuards,              UINT,     "3"),
   V(ORListenAddress,             LINELIST, NULL),
   V(ORListenAddress,             LINELIST, NULL),
   V(ORPort,                      UINT,     "0"),
   V(ORPort,                      UINT,     "0"),
@@ -554,7 +555,7 @@ static int is_listening_on_low_port(uint16_t port_option,
 
 
 static uint64_t config_parse_memunit(const char *s, int *ok);
 static uint64_t config_parse_memunit(const char *s, int *ok);
 static int config_parse_interval(const char *s, int *ok);
 static int config_parse_interval(const char *s, int *ok);
-static void init_libevent(void);
+static void init_libevent(const or_options_t *options);
 static int opt_streq(const char *s1, const char *s2);
 static int opt_streq(const char *s1, const char *s2);
 
 
 /** Magic value for or_options_t. */
 /** Magic value for or_options_t. */
@@ -955,7 +956,7 @@ options_act_reversible(or_options_t *old_options, char **msg)
     /* Set up libevent.  (We need to do this before we can register the
     /* Set up libevent.  (We need to do this before we can register the
      * listeners as listeners.) */
      * listeners as listeners.) */
     if (running_tor && !libevent_initialized) {
     if (running_tor && !libevent_initialized) {
-      init_libevent();
+      init_libevent(options);
       libevent_initialized = 1;
       libevent_initialized = 1;
     }
     }
 
 
@@ -4891,13 +4892,29 @@ config_parse_interval(const char *s, int *ok)
   return (int)r;
   return (int)r;
 }
 }
 
 
+/** Return the number of cpus configured in <b>options</b>.  If we are
+ * told to auto-detect the number of cpus, return the auto-detected number. */
+int
+get_num_cpus(const or_options_t *options)
+{
+  if (options->NumCpus == 0) {
+    int n = compute_num_cpus();
+    return (n >= 1) ? n : 1;
+  } else {
+    return options->NumCpus;
+  }
+}
+
 /**
 /**
  * Initialize the libevent library.
  * Initialize the libevent library.
  */
  */
 static void
 static void
-init_libevent(void)
+init_libevent(const or_options_t *options)
 {
 {
   const char *badness=NULL;
   const char *badness=NULL;
+  tor_libevent_cfg cfg;
+
+  tor_assert(options);
 
 
   configure_libevent_logging();
   configure_libevent_logging();
   /* If the kernel complains that some method (say, epoll) doesn't
   /* If the kernel complains that some method (say, epoll) doesn't
@@ -4907,7 +4924,11 @@ init_libevent(void)
 
 
   tor_check_libevent_header_compatibility();
   tor_check_libevent_header_compatibility();
 
 
-  tor_libevent_initialize();
+  memset(&cfg, 0, sizeof(cfg));
+  cfg.disable_iocp = options->DisableIOCP;
+  cfg.num_cpus = get_num_cpus(options);
+
+  tor_libevent_initialize(&cfg);
 
 
   suppress_libevent_log_msg(NULL);
   suppress_libevent_log_msg(NULL);
 
 

+ 2 - 0
src/or/config.h

@@ -57,6 +57,8 @@ char *options_get_datadir_fname2_suffix(or_options_t *options,
 #define get_datadir_fname_suffix(sub1, suffix) \
 #define get_datadir_fname_suffix(sub1, suffix) \
   get_datadir_fname2_suffix((sub1), NULL, (suffix))
   get_datadir_fname2_suffix((sub1), NULL, (suffix))
 
 
+int get_num_cpus(const or_options_t *options);
+
 or_state_t *get_or_state(void);
 or_state_t *get_or_state(void);
 int or_state_save(time_t now);
 int or_state_save(time_t now);
 
 

+ 1 - 1
src/or/cpuworker.c

@@ -366,7 +366,7 @@ spawn_cpuworker(void)
 static void
 static void
 spawn_enough_cpuworkers(void)
 spawn_enough_cpuworkers(void)
 {
 {
-  int num_cpuworkers_needed = get_options()->NumCpus;
+  int num_cpuworkers_needed = get_num_cpus(get_options());
 
 
   if (num_cpuworkers_needed < MIN_CPUWORKERS)
   if (num_cpuworkers_needed < MIN_CPUWORKERS)
     num_cpuworkers_needed = MIN_CPUWORKERS;
     num_cpuworkers_needed = MIN_CPUWORKERS;

+ 4 - 0
src/or/or.h

@@ -2892,6 +2892,10 @@ typedef struct {
    */
    */
   double CircuitPriorityHalflife;
   double CircuitPriorityHalflife;
 
 
+  /** If true, do not enable IOCP on windows with bufferevents, even if
+   * we think we could. */
+  int DisableIOCP;
+
 } or_options_t;
 } or_options_t;
 
 
 /** Persistent state for an onion router, as saved to disk. */
 /** Persistent state for an onion router, as saved to disk. */