thds.core 1.32.20250321183714__py3-none-any.whl → 1.32.20250321195352__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of thds.core might be problematic. Click here for more details.
- thds/core/cpus.py +81 -0
- {thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/METADATA +1 -1
- {thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/RECORD +6 -5
- {thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/WHEEL +0 -0
- {thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/entry_points.txt +0 -0
- {thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/top_level.txt +0 -0
thds/core/cpus.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import multiprocessing
|
|
2
|
+
import os
|
|
3
|
+
import typing as ty
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from . import log
|
|
7
|
+
|
|
8
|
+
_CPU_QUOTA_PATH = Path("/sys/fs/cgroup/cpu/cpu.cfs_quota_us")
|
|
9
|
+
_CPU_PERIOD_PATH = Path("/sys/fs/cgroup/cpu/cpu.cfs_period_us")
|
|
10
|
+
# standard linux kernel cgroup config files
|
|
11
|
+
# https://www.kernel.org/doc/html/latest/scheduler/sched-bwc.html#management
|
|
12
|
+
_CPU_MAX_PATH_V2 = Path("/sys/fs/cgroup/cpu.max")
|
|
13
|
+
# cgroups v2: https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#cgroup-v2-cpu
|
|
14
|
+
_CPU_SHARES_PATH = Path("/sys/fs/cgroup/cpu/cpu.shares")
|
|
15
|
+
# some kind of redhat thing: https://www.redhat.com/en/blog/cgroups-part-two
|
|
16
|
+
|
|
17
|
+
logger = log.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
T = ty.TypeVar("T")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _try_read_value(config_path: Path, parse: ty.Callable[[str], T]) -> ty.Optional[T]:
|
|
23
|
+
if config_path.is_file():
|
|
24
|
+
logger.info(f"Found {config_path}; attempting to read value")
|
|
25
|
+
with config_path.open() as f:
|
|
26
|
+
contents = f.read().strip()
|
|
27
|
+
try:
|
|
28
|
+
value = parse(contents)
|
|
29
|
+
except Exception as e:
|
|
30
|
+
logger.error(f"Could not parse value from {contents} with {parse}: {e}")
|
|
31
|
+
# if the file exists but we can't parse the contents, something is very wrong with our assumptions;
|
|
32
|
+
# better to fail loudly than risk silent CPU oversubscription
|
|
33
|
+
raise e
|
|
34
|
+
else:
|
|
35
|
+
logger.info(f"Read value {value} from {config_path}")
|
|
36
|
+
return value
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _parse_cpu_quota_and_period_v2(s: str) -> ty.Tuple[int, int]:
|
|
41
|
+
"""Parse both CPU quota and period from kernel cgroup v2 config file."""
|
|
42
|
+
quota, period = map(int, s.split())
|
|
43
|
+
return quota, period
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def available_cpu_count() -> int:
|
|
47
|
+
"""Attempt to determine number of available CPUs, accounting for the possibility of running inside a docker
|
|
48
|
+
container. Ideally, this serves as a drop-in replacement for os.cpu_count() in that context.
|
|
49
|
+
|
|
50
|
+
Partially cribbed from a suggestion in https://bugs.python.org/issue36054, and partially from joblib (specifically
|
|
51
|
+
handling v2 of the kernel cgroup spec).
|
|
52
|
+
"""
|
|
53
|
+
if hasattr(os, "sched_getaffinity"):
|
|
54
|
+
cpu_count = len(os.sched_getaffinity(0))
|
|
55
|
+
else:
|
|
56
|
+
cpu_count = multiprocessing.cpu_count()
|
|
57
|
+
|
|
58
|
+
cpu_quota_us: ty.Optional[int]
|
|
59
|
+
cpu_period_us: ty.Optional[int]
|
|
60
|
+
if (
|
|
61
|
+
quota_and_period_v2 := _try_read_value(_CPU_MAX_PATH_V2, _parse_cpu_quota_and_period_v2)
|
|
62
|
+
) is not None:
|
|
63
|
+
# this file contains both values
|
|
64
|
+
cpu_quota_us, cpu_period_us = quota_and_period_v2
|
|
65
|
+
else:
|
|
66
|
+
cpu_quota_us = _try_read_value(_CPU_QUOTA_PATH, int)
|
|
67
|
+
cpu_period_us = _try_read_value(_CPU_PERIOD_PATH, int)
|
|
68
|
+
|
|
69
|
+
if cpu_quota_us is not None and cpu_period_us is not None and cpu_quota_us != -1:
|
|
70
|
+
cpu_shares = int(cpu_quota_us / cpu_period_us)
|
|
71
|
+
elif cpu_shares_ := _try_read_value(_CPU_SHARES_PATH, int):
|
|
72
|
+
cpu_shares = int(cpu_shares_ / 1024)
|
|
73
|
+
else:
|
|
74
|
+
logger.info(f"Using naive CPU count: {cpu_count}")
|
|
75
|
+
return cpu_count
|
|
76
|
+
|
|
77
|
+
logger.info(
|
|
78
|
+
f"Determined CPU shares from quota and period: {cpu_shares}; returning lesser of this and naive "
|
|
79
|
+
f"CPU count: {cpu_count}"
|
|
80
|
+
)
|
|
81
|
+
return min(cpu_shares, cpu_count)
|
|
@@ -5,6 +5,7 @@ thds/core/calgitver.py,sha256=HklIz-SczK92Vm2rXtTSDiVxAcxUW_GPVCRRGt4BmBA,2324
|
|
|
5
5
|
thds/core/cm.py,sha256=WZB8eQU0DaBYj9s97nc3PuCtai9guovfyiQH68zhLzY,1086
|
|
6
6
|
thds/core/concurrency.py,sha256=NQunF_tJ_z8cfVyhzkTPlb-nZrgu-vIk9_3XffgscKQ,3520
|
|
7
7
|
thds/core/config.py,sha256=VWymw6pqPRvX7wwsJ0Y-D2gLoCclAHhARmTnuUw7kb0,10014
|
|
8
|
+
thds/core/cpus.py,sha256=DOm6E1uWKZLCEXWKwfS1ZHuSTWD0XWwp1vgXHC-5oNk,3230
|
|
8
9
|
thds/core/decos.py,sha256=VpFTKTArXepICxN4U8C8J6Z5KDq-yVjFZQzqs2jeVAk,1341
|
|
9
10
|
thds/core/dict_utils.py,sha256=MatsjZC9lchfdaDqNAzL2mkTZytDnCAqg56sMm71wbE,6364
|
|
10
11
|
thds/core/env.py,sha256=HkuyFmGpCgdQUB1r2GbpCqB3cs1lCsvp47Ghk1DHBo8,1083
|
|
@@ -66,8 +67,8 @@ thds/core/sqlite/structured.py,sha256=swCbDoyVT6cE7Kl79Wh_rg5Z1-yrUDJbiVJF4bjset
|
|
|
66
67
|
thds/core/sqlite/types.py,sha256=oUkfoKRYNGDPZRk29s09rc9ha3SCk2SKr_K6WKebBFs,1308
|
|
67
68
|
thds/core/sqlite/upsert.py,sha256=BmKK6fsGVedt43iY-Lp7dnAu8aJ1e9CYlPVEQR2pMj4,5827
|
|
68
69
|
thds/core/sqlite/write.py,sha256=z0219vDkQDCnsV0WLvsj94keItr7H4j7Y_evbcoBrWU,3458
|
|
69
|
-
thds_core-1.32.
|
|
70
|
-
thds_core-1.32.
|
|
71
|
-
thds_core-1.32.
|
|
72
|
-
thds_core-1.32.
|
|
73
|
-
thds_core-1.32.
|
|
70
|
+
thds_core-1.32.20250321195352.dist-info/METADATA,sha256=cVcwdcBqE_YE27yyk064W0XVYJaI3sna0JcHuPpKy94,2277
|
|
71
|
+
thds_core-1.32.20250321195352.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
72
|
+
thds_core-1.32.20250321195352.dist-info/entry_points.txt,sha256=bOCOVhKZv7azF3FvaWX6uxE6yrjK6FcjqhtxXvLiFY8,161
|
|
73
|
+
thds_core-1.32.20250321195352.dist-info/top_level.txt,sha256=LTZaE5SkWJwv9bwOlMbIhiS-JWQEEIcjVYnJrt-CriY,5
|
|
74
|
+
thds_core-1.32.20250321195352.dist-info/RECORD,,
|
|
File without changes
|
{thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{thds_core-1.32.20250321183714.dist-info → thds_core-1.32.20250321195352.dist-info}/top_level.txt
RENAMED
|
File without changes
|