From e1d39fc082a8b96d779c8029ee5680904094a856 Mon Sep 17 00:00:00 2001 From: ticoneva Date: Sun, 28 May 2023 17:20:50 +0800 Subject: [PATCH 1/5] Added the cpu_weight option --- README.md | 18 ++++++++++++++++++ systemdspawner/systemdspawner.py | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d8e03d2..840fe7d 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ in your `jupyterhub_config.py` file: - **[`mem_limit`](#mem_limit)** - **[`cpu_limit`](#cpu_limit)** +- **[`cpu_weight`](#cpu_weight)** - **[`user_workingdir`](#user_workingdir)** - **[`username_template`](#username_template)** - **[`default_shell`](#default_shell)** @@ -214,6 +215,23 @@ This works out perfect for most cases, since this allows users to burst up and use all CPU when nobody else is using CPU & forces them to automatically yield when other users want to use the CPU. +The share of access can be adjusted with the `cpu_weight` option. + +### `cpu_weight` ### + +An integer representing the share of CPU time each user can use. A user with +a `cpu_weight` of 200 will get 2x access to the CPU than a user with a `cpu_weight` +of 100, which is the system default. + +```python +c.SystemdSpawner.cpu_weight = 100 +``` + +Defaults to `None`, which implicitly means 100. + +This info is exposed to the single-user server as the environment variable +`CPU_WEIGHT` as an integer. + ### `user_workingdir` The directory to spawn each user's notebook server in. This directory is what users diff --git a/systemdspawner/systemdspawner.py b/systemdspawner/systemdspawner.py index cc2850d..ad8a118 100644 --- a/systemdspawner/systemdspawner.py +++ b/systemdspawner/systemdspawner.py @@ -5,7 +5,7 @@ from jupyterhub.spawner import Spawner from jupyterhub.utils import random_port -from traitlets import Bool, Dict, List, Unicode +from traitlets import Bool, Dict, List, Unicode, Integer from systemdspawner import systemd @@ -146,6 +146,18 @@ class SystemdSpawner(Spawner): """, ).tag(config=True) + cpu_weight = Integer( + None, + allow_none=True, + help=""" + Assign a CPU weight to the single-user notebook server. + Available CPU time is allocated in proportion to each user's weight. + + Acceptable value: an integer between 1 to 10000. + System default is 100. + """ + ).tag(config=True) + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # All traitlets configurables are configured by now @@ -304,6 +316,11 @@ async def start(self): properties["CPUAccounting"] = "yes" properties["CPUQuota"] = f"{int(self.cpu_limit * 100)}%" + if self.cpu_weight is not None: + # FIXME: Detect & use proper properties for v1 vs v2 cgroups + properties['CPUAccounting'] = 'yes' + properties['CPUWeight'] = str(self.cpu_weight) + if self.disable_user_sudo: properties["NoNewPrivileges"] = "yes" From 63e152abdadeb783c5f247be785a9d73373bde3d Mon Sep 17 00:00:00 2001 From: ticoneva Date: Sun, 28 May 2023 17:23:26 +0800 Subject: [PATCH 2/5] Edited readme for clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 840fe7d..2533856 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ This works out perfect for most cases, since this allows users to burst up and use all CPU when nobody else is using CPU & forces them to automatically yield when other users want to use the CPU. -The share of access can be adjusted with the `cpu_weight` option. +The share of access each user gets can be adjusted with the `cpu_weight` option. ### `cpu_weight` ### From 9038af9a692cbc7307ed165649665ce6fd6ef6ec Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 09:27:26 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- README.md | 6 +++--- systemdspawner/systemdspawner.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2533856..4ac8d11 100644 --- a/README.md +++ b/README.md @@ -217,11 +217,11 @@ when other users want to use the CPU. The share of access each user gets can be adjusted with the `cpu_weight` option. -### `cpu_weight` ### +### `cpu_weight` -An integer representing the share of CPU time each user can use. A user with +An integer representing the share of CPU time each user can use. A user with a `cpu_weight` of 200 will get 2x access to the CPU than a user with a `cpu_weight` -of 100, which is the system default. +of 100, which is the system default. ```python c.SystemdSpawner.cpu_weight = 100 diff --git a/systemdspawner/systemdspawner.py b/systemdspawner/systemdspawner.py index ad8a118..81fcb06 100644 --- a/systemdspawner/systemdspawner.py +++ b/systemdspawner/systemdspawner.py @@ -5,7 +5,7 @@ from jupyterhub.spawner import Spawner from jupyterhub.utils import random_port -from traitlets import Bool, Dict, List, Unicode, Integer +from traitlets import Bool, Dict, Integer, List, Unicode from systemdspawner import systemd @@ -155,7 +155,7 @@ class SystemdSpawner(Spawner): Acceptable value: an integer between 1 to 10000. System default is 100. - """ + """, ).tag(config=True) def __init__(self, *args, **kwargs): @@ -318,8 +318,8 @@ async def start(self): if self.cpu_weight is not None: # FIXME: Detect & use proper properties for v1 vs v2 cgroups - properties['CPUAccounting'] = 'yes' - properties['CPUWeight'] = str(self.cpu_weight) + properties["CPUAccounting"] = "yes" + properties["CPUWeight"] = str(self.cpu_weight) if self.disable_user_sudo: properties["NoNewPrivileges"] = "yes" From cba63a8028ee8fc38d97dfb16451e3c3bd10d20f Mon Sep 17 00:00:00 2001 From: ticoneva Date: Wed, 31 May 2023 19:14:16 +0800 Subject: [PATCH 4/5] Export CPU_WEIGHT environment variable --- systemdspawner/systemdspawner.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/systemdspawner/systemdspawner.py b/systemdspawner/systemdspawner.py index ad8a118..83fe51b 100644 --- a/systemdspawner/systemdspawner.py +++ b/systemdspawner/systemdspawner.py @@ -288,6 +288,9 @@ async def start(self): else: working_dir = self._expand_user_vars(self.user_workingdir) + if self.cpu_weight: + env['CPU_WEIGHT'] = str(self.cpu_weight) + if self.isolate_tmp: properties["PrivateTmp"] = "yes" From a4fcd23f5d6fe787586893800acb3ce68c581f3c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 11:14:35 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- systemdspawner/systemdspawner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemdspawner/systemdspawner.py b/systemdspawner/systemdspawner.py index 984bde3..1a27482 100644 --- a/systemdspawner/systemdspawner.py +++ b/systemdspawner/systemdspawner.py @@ -289,7 +289,7 @@ async def start(self): working_dir = self._expand_user_vars(self.user_workingdir) if self.cpu_weight: - env['CPU_WEIGHT'] = str(self.cpu_weight) + env["CPU_WEIGHT"] = str(self.cpu_weight) if self.isolate_tmp: properties["PrivateTmp"] = "yes"