Procházet zdrojové kódy

Merge branch 'iocp_option'

Nick Mathewson před 15 roky
rodič
revize
3efaa30727

+ 3 - 0
changes/bufferevent-support

@@ -6,4 +6,7 @@
      flag.  Using this feature will make our networking code more flexible,
      lets us stack layers on each other, and let us use more efficient
      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 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
 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
     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
 --------------
 
@@ -855,7 +860,9 @@ is non-zero):
     characters inclusive, and must contain only the characters [a-zA-Z0-9].
 
 **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__::
     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
 }
 
+/** 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.
  * (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
 #endif
 
+int compute_num_cpus(void);
+
 /* Because we use threads instead of processes on most platforms (Windows,
  * Linux, etc), we need locking for them.  On platforms with poor thread
  * 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. */
 void
-tor_libevent_initialize(void)
+tor_libevent_initialize(tor_libevent_cfg *torcfg)
 {
   tor_assert(the_event_base == NULL);
 
@@ -171,7 +171,21 @@ tor_libevent_initialize(void)
 #endif
 
 #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
   the_event_base = event_init();
 #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);
 #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);
 const char *tor_libevent_get_method(void);
 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"),
   VAR("DirServer",               LINELIST, DirServers, NULL),
   V(DisableAllSwap,              BOOL,     "0"),
+  V(DisableIOCP,                 BOOL,     "1"),
   V(DNSPort,                     UINT,     "0"),
   V(DNSListenAddress,            LINELIST, NULL),
   V(DownloadExtraInfo,           BOOL,     "0"),
@@ -306,7 +307,7 @@ static config_var_t _option_vars[] = {
   V(WarnUnsafeSocks,              BOOL,     "1"),
   V(NoPublish,                   BOOL,     "0"),
   VAR("NodeFamily",              LINELIST, NodeFamilies,         NULL),
-  V(NumCpus,                     UINT,     "1"),
+  V(NumCpus,                     UINT,     "0"),
   V(NumEntryGuards,              UINT,     "3"),
   V(ORListenAddress,             LINELIST, NULL),
   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 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);
 
 /** 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
      * listeners as listeners.) */
     if (running_tor && !libevent_initialized) {
-      init_libevent();
+      init_libevent(options);
       libevent_initialized = 1;
     }
 
@@ -4891,13 +4892,29 @@ config_parse_interval(const char *s, int *ok)
   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.
  */
 static void
-init_libevent(void)
+init_libevent(const or_options_t *options)
 {
   const char *badness=NULL;
+  tor_libevent_cfg cfg;
+
+  tor_assert(options);
 
   configure_libevent_logging();
   /* If the kernel complains that some method (say, epoll) doesn't
@@ -4907,7 +4924,11 @@ init_libevent(void)
 
   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);
 

+ 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) \
   get_datadir_fname2_suffix((sub1), NULL, (suffix))
 
+int get_num_cpus(const or_options_t *options);
+
 or_state_t *get_or_state(void);
 int or_state_save(time_t now);
 

+ 1 - 1
src/or/cpuworker.c

@@ -366,7 +366,7 @@ spawn_cpuworker(void)
 static 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)
     num_cpuworkers_needed = MIN_CPUWORKERS;

+ 4 - 0
src/or/or.h

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