-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-109595: Add -Xcpu_count=<n> cmdline for container users #109667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
41be170
f7a7428
7009bbe
d1f91d8
8c92ed6
c27bdfc
b13e5ee
45fce16
49a48e4
829a8e8
cfb33a4
95a2173
0394d1d
f4a3f01
60a28fe
7e5595c
8678012
cbc5484
4622b60
50f0178
5c3ac68
a276bfd
9c582be
35b952f
f04ea58
7ecf705
18dcd44
b344f4f
8069d21
c70bc82
c8abc29
2ac6901
f0a3ebf
89d8bb2
66c617f
4a72ed4
0426e3e
ac5329b
e50e678
24fe0e4
32843ed
a954f1c
3ab2bc4
7231697
b18da0d
3579fc4
134ed9e
2bec7f4
9f7cb5e
1217ab5
64da2f9
64c7329
cc54afb
ba421c7
5f20bf6
c11789b
936c182
2f0dc1c
a7b2c88
551c76d
75021be
57dd53b
3f9da50
57e82c5
c37c8d0
c7726e5
de8bf53
633914b
37fbdfe
a0cfb21
8daa3b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -901,6 +901,11 @@ def res2int(res): | |
| ) | ||
| self.assertEqual(res2int(res), (6000, 6000)) | ||
|
|
||
| def test_cpu_count(self): | ||
| code = "import os; print(os.cpu_count())" | ||
| res = assert_python_ok('-X', 'cpu_count=4321', '-c', code) | ||
| self.assertEqual(res.out.strip().decode("utf-8"), '4321') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a lot of CPUs, it's exciting! Until recently, Linux was limited to 4096 CPUs! https://unix.stackexchange.com/questions/4507/how-many-cores-can-linux-kernel-handle |
||
|
|
||
|
|
||
| @unittest.skipIf(interpreter_requires_environment(), | ||
| 'Cannot run -I tests when PYTHON env vars are required.') | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Add :samp:`-Xcpu_count={n}` command line option for overriding system CPU resources from | ||
| Python program. Patch by Donghee Na. | ||
|
corona10 marked this conversation as resolved.
Outdated
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -715,6 +715,7 @@ static int test_init_from_config(void) | |
|
|
||
| putenv("PYTHONINTMAXSTRDIGITS=6666"); | ||
| config.int_max_str_digits = 31337; | ||
| config.cpu_count = -1; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please set a more interesting value like 1234? |
||
|
|
||
| init_from_config_clear(&config); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -130,7 +130,10 @@ The following implementation-specific options are available:\n\ | |
| \n\ | ||
| -X int_max_str_digits=number: limit the size of int<->str conversions.\n\ | ||
| This helps avoid denial of service attacks when parsing untrusted data.\n\ | ||
| The default is sys.int_info.default_max_str_digits. 0 disables." | ||
| The default is sys.int_info.default_max_str_digits. 0 disables.\n\ | ||
| \n\ | ||
| -X cpu_count=n: override CPU count of os.cpu_count().\n\ | ||
|
corona10 marked this conversation as resolved.
Outdated
|
||
| This helps for users who need to limit CPU resources of a container system." | ||
|
|
||
| #ifdef Py_STATS | ||
| "\n\ | ||
|
|
@@ -633,6 +636,8 @@ config_check_consistency(const PyConfig *config) | |
| assert(config->_is_python_build >= 0); | ||
| assert(config->safe_path >= 0); | ||
| assert(config->int_max_str_digits >= 0); | ||
| // cpu_count can be -1 if the user doesn't override it. | ||
| assert(config->cpu_count != 0); | ||
|
corona10 marked this conversation as resolved.
|
||
| // config->use_frozen_modules is initialized later | ||
| // by _PyConfig_InitImportConfig(). | ||
| #ifdef Py_STATS | ||
|
|
@@ -732,6 +737,7 @@ _PyConfig_InitCompatConfig(PyConfig *config) | |
| config->int_max_str_digits = -1; | ||
| config->_is_python_build = 0; | ||
| config->code_debug_ranges = 1; | ||
| config->cpu_count = -1; | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -959,6 +965,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2) | |
| COPY_WSTRLIST(orig_argv); | ||
| COPY_ATTR(_is_python_build); | ||
| COPY_ATTR(int_max_str_digits); | ||
| COPY_ATTR(cpu_count); | ||
|
corona10 marked this conversation as resolved.
Outdated
|
||
| #ifdef Py_STATS | ||
| COPY_ATTR(_pystats); | ||
| #endif | ||
|
|
@@ -1069,6 +1076,7 @@ _PyConfig_AsDict(const PyConfig *config) | |
| SET_ITEM_INT(safe_path); | ||
| SET_ITEM_INT(_is_python_build); | ||
| SET_ITEM_INT(int_max_str_digits); | ||
| SET_ITEM_INT(cpu_count); | ||
| #ifdef Py_STATS | ||
| SET_ITEM_INT(_pystats); | ||
| #endif | ||
|
|
@@ -1379,6 +1387,7 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict) | |
| GET_UINT(safe_path); | ||
| GET_UINT(_is_python_build); | ||
| GET_INT(int_max_str_digits); | ||
| GET_INT(cpu_count); | ||
| #ifdef Py_STATS | ||
| GET_UINT(_pystats); | ||
| #endif | ||
|
|
@@ -1678,6 +1687,29 @@ config_read_env_vars(PyConfig *config) | |
| return _PyStatus_OK(); | ||
| } | ||
|
|
||
| static PyStatus | ||
| config_init_cpu_count(PyConfig *config) | ||
| { | ||
| int cpu_count = -1; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can move the variable declaration inside the "if (sep)" block. Does it have to be initialized? If you are afraid of undefined behavior, maybe config_wstr_to_int() should set
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now I added
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want, you can move the variable declaration inside each "if (env)" block and duplicate the variable, to better show its scope. But well, that's just a personal preference. Feel free to ignore my coding style remark ;-) |
||
| const wchar_t *xoption = config_get_xoption(config, L"cpu_count"); | ||
|
corona10 marked this conversation as resolved.
|
||
| if (xoption) { | ||
| const wchar_t *sep = wcschr(xoption, L'='); | ||
| if (sep) { | ||
| if (config_wstr_to_int(sep + 1, &cpu_count) < 0 || cpu_count < 1) { | ||
| goto error; | ||
| } | ||
| } | ||
| else { | ||
| goto error; | ||
| } | ||
| config->cpu_count = cpu_count; | ||
| } | ||
| return _PyStatus_OK(); | ||
|
|
||
| error: | ||
|
corona10 marked this conversation as resolved.
|
||
| return _PyStatus_ERR("-X cpu_count=n option: n is missing or an invalid number"); | ||
|
corona10 marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| static PyStatus | ||
| config_init_perf_profiling(PyConfig *config) | ||
| { | ||
|
|
@@ -1860,6 +1892,13 @@ config_read_complex_options(PyConfig *config) | |
| } | ||
| } | ||
|
|
||
| if (config->cpu_count < 0) { | ||
| status = config_init_cpu_count(config); | ||
| if (_PyStatus_EXCEPTION(status)) { | ||
| return status; | ||
| } | ||
| } | ||
|
|
||
| if (config->pycache_prefix == NULL) { | ||
| status = config_init_pycache_prefix(config); | ||
| if (_PyStatus_EXCEPTION(status)) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.