summary refs log tree commit diff
diff options
context:
space:
mode:
authorRichard van der Hoff <richard@matrix.org>2017-08-15 17:08:28 +0100
committerRichard van der Hoff <richard@matrix.org>2017-08-15 17:08:28 +0100
commit10d8b701a1fa585c5fc2d5edcea8d4d02ae360a4 (patch)
tree5c6a455a53db8c5eb91c8b648d0eb92daf05098e
parentFactor out common application start (diff)
downloadsynapse-10d8b701a1fa585c5fc2d5edcea8d4d02ae360a4.tar.xz
Allow configuration of CPU affinity
Make it possible to set the CPU affinity in the config file, so that we don't
need to remember to do it manually every time.
-rw-r--r--synapse/app/_base.py9
-rwxr-xr-xsynapse/app/homeserver.py1
-rw-r--r--synapse/config/server.py12
-rw-r--r--synapse/config/workers.py1
-rw-r--r--synapse/python_dependencies.py1
5 files changed, 23 insertions, 1 deletions
diff --git a/synapse/app/_base.py b/synapse/app/_base.py
index 3889c35946..cd0e815919 100644
--- a/synapse/app/_base.py
+++ b/synapse/app/_base.py
@@ -15,6 +15,7 @@
 import gc
 import logging
 
+import affinity
 from daemonize import Daemonize
 from synapse.util import PreserveLoggingContext
 from synapse.util.rlimit import change_resource_limit
@@ -40,7 +41,8 @@ def start_worker_reactor(appname, config):
         config.gc_thresholds,
         config.worker_pid_file,
         config.worker_daemonize,
-        logger
+        config.worker_cpu_affinity,
+        logger,
     )
 
 
@@ -50,6 +52,7 @@ def start_reactor(
         gc_thresholds,
         pid_file,
         daemonize,
+        cpu_affinity,
         logger,
 ):
     """ Run the reactor in the main process
@@ -63,6 +66,7 @@ def start_reactor(
         gc_thresholds:
         pid_file (str): name of pid file to write to if daemonize is True
         daemonize (bool): true to run the reactor in a background process
+        cpu_affinity (int|None): cpu affinity mask
         logger (logging.Logger): logger instance to pass to Daemonize
     """
 
@@ -73,6 +77,9 @@ def start_reactor(
         # between the sentinel and `run` logcontexts.
         with PreserveLoggingContext():
             logger.info("Running")
+            if cpu_affinity is not None:
+                logger.info("Setting CPU affinity to %s" % cpu_affinity)
+                affinity.set_process_affinity_mask(0, cpu_affinity)
             change_resource_limit(soft_file_limit)
             if gc_thresholds:
                 gc.set_threshold(*gc_thresholds)
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index 83b6c3212b..84ad8f04a0 100755
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -442,6 +442,7 @@ def run(hs):
         hs.config.gc_thresholds,
         hs.config.pid_file,
         hs.config.daemonize,
+        hs.config.cpu_affinity,
         logger,
     )
 
diff --git a/synapse/config/server.py b/synapse/config/server.py
index 28b4e5f50c..4e4bf6b432 100644
--- a/synapse/config/server.py
+++ b/synapse/config/server.py
@@ -29,6 +29,7 @@ class ServerConfig(Config):
         self.user_agent_suffix = config.get("user_agent_suffix")
         self.use_frozen_dicts = config.get("use_frozen_dicts", False)
         self.public_baseurl = config.get("public_baseurl")
+        self.cpu_affinity = config.get("cpu_affinity")
 
         # Whether to send federation traffic out in this process. This only
         # applies to some federation traffic, and so shouldn't be used to
@@ -147,6 +148,17 @@ class ServerConfig(Config):
         # When running as a daemon, the file to store the pid in
         pid_file: %(pid_file)s
 
+        # CPU affinity mask. Setting this restricts the CPUs on which the process
+        # will be scheduled. It is represented as a bitmask, with the lowest order
+        # bit corresponding to the first logical CPU and the highest order bit
+        # corresponding to the last logical CPU. Not all CPUs may exist on a
+        # given system but a mask may specify more CPUs than are present.
+        # For example:
+        #    0x00000001  is processor #0,
+        #    0x00000003  is processors #0 and #1,
+        #    0xFFFFFFFF  is all processors (#0 through #31).
+        # cpu_affinity: 0xFFFFFFFF
+
         # Whether to serve a web client from the HTTP/HTTPS root resource.
         web_client: True
 
diff --git a/synapse/config/workers.py b/synapse/config/workers.py
index 99d5d8aaeb..c5a5a8919c 100644
--- a/synapse/config/workers.py
+++ b/synapse/config/workers.py
@@ -33,6 +33,7 @@ class WorkerConfig(Config):
         self.worker_name = config.get("worker_name", self.worker_app)
 
         self.worker_main_http_uri = config.get("worker_main_http_uri", None)
+        self.worker_cpu_affinity = config.get("worker_cpu_affinity")
 
         if self.worker_listeners:
             for listener in self.worker_listeners:
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index ed7f1c89ad..1d902dc38d 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -40,6 +40,7 @@ REQUIREMENTS = {
     "pymacaroons-pynacl": ["pymacaroons"],
     "msgpack-python>=0.3.0": ["msgpack"],
     "phonenumbers>=8.2.0": ["phonenumbers"],
+    "affinity": ["affinity"],
 }
 CONDITIONAL_REQUIREMENTS = {
     "web_client": {