Преглед на файлове

Autodetect the number of CPUs when possible if NumCPUs==0

This is needed for IOCP, since telling the IOCP backend about all
your CPUs is a good idea.  It'll also come in handy with asn's
multithreaded crypto stuff, and for people who run servers without
reading the manual.
Nick Mathewson преди 15 години
родител
ревизия
73d93c033d
променени са 8 файла, в които са добавени 73 реда и са изтрити 5 реда
  1. 3 0
      changes/cpudetect
  2. 1 1
      configure.in
  3. 3 1
      doc/tor.1.txt
  4. 46 0
      src/common/compat.c
  5. 2 0
      src/common/compat.h
  6. 15 2
      src/or/config.c
  7. 2 0
      src/or/config.h
  8. 1 1
      src/or/cpuworker.c

+ 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

+ 3 - 1
doc/tor.1.txt

@@ -860,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. */

+ 15 - 2
src/or/config.c

@@ -307,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"),
@@ -4892,6 +4892,19 @@ 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.
  */
@@ -4913,7 +4926,7 @@ init_libevent(const or_options_t *options)
 
   memset(&cfg, 0, sizeof(cfg));
   cfg.disable_iocp = options->DisableIOCP;
-  cfg.num_cpus = options->NumCpus;
+  cfg.num_cpus = get_num_cpus(options);
 
   tor_libevent_initialize(&cfg);
 

+ 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;