Skip to content

Commit a685f74

Browse files
committed
Implement faster priority process priority setup
1 parent 9d7b425 commit a685f74

File tree

1 file changed

+84
-36
lines changed

1 file changed

+84
-36
lines changed

command_runner/__init__.py

Lines changed: 84 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
__author__ = "Orsiris de Jong"
2222
__copyright__ = "Copyright (C) 2015-2025 Orsiris de Jong for NetInvent"
2323
__licence__ = "BSD 3 Clause"
24-
__version__ = "1.7.2"
25-
__build__ = "2025031001"
24+
__version__ = "1.8.0-dev"
25+
__build__ = "2025031301"
2626
__compat__ = "python2.7+"
2727

2828
import io
@@ -38,32 +38,83 @@
3838
# Avoid checking os type numerous times
3939
os_name = os.name
4040

41+
42+
# Don't bother with an ImportError since we need command_runner to work without dependencies
4143
try:
4244
import psutil
43-
except ImportError:
44-
# Don't bother with an error since we need command_runner to work without dependencies
45-
pass
46-
try:
4745
# Also make sure we directly import priority classes so we can reuse them
4846
if os_name == "nt":
4947
from psutil import (
50-
ABOVE_NORMAL_PRIORITY_CLASS,
51-
BELOW_NORMAL_PRIORITY_CLASS,
48+
# ABOVE_NORMAL_PRIORITY_CLASS,
49+
# BELOW_NORMAL_PRIORITY_CLASS,
5250
HIGH_PRIORITY_CLASS,
5351
IDLE_PRIORITY_CLASS,
5452
NORMAL_PRIORITY_CLASS,
5553
REALTIME_PRIORITY_CLASS,
5654
)
57-
from psutil import IOPRIO_HIGH, IOPRIO_NORMAL, IOPRIO_LOW, IOPRIO_VERYLOW
55+
from psutil import (
56+
IOPRIO_HIGH,
57+
IOPRIO_NORMAL,
58+
IOPRIO_LOW,
59+
)
5860
else:
5961
from psutil import (
6062
IOPRIO_CLASS_BE,
6163
IOPRIO_CLASS_IDLE,
62-
IOPRIO_CLASS_NONE,
64+
# IOPRIO_CLASS_NONE,
6365
IOPRIO_CLASS_RT,
6466
)
6567
except (ImportError, AttributeError):
66-
pass
68+
if os_name == "nt":
69+
BELOW_NORMAL_PRIORITY_CLASS = 16384
70+
HIGH_PRIORITY_CLASS = 128
71+
NORMAL_PRIORITY_CLASS = 32
72+
REALTIME_PRIORITY_CLASS = 256
73+
IDLE_PRIORITY_CLASS = 64
74+
IOPRIO_HIGH = 3
75+
IOPRIO_NORMAL = 2
76+
IOPRIO_LOW = 1
77+
else:
78+
IOPRIO_CLASS_IDLE = 3
79+
IOPRIO_CLASS_BE = 2
80+
IOPRIO_CLASS_RT = 1
81+
82+
83+
# Python 2.7 does not have priorities defined in subprocess module, but psutil has
84+
# Since Windows and Linux use different possible values, let's simplify things by
85+
# allowing 4 process priorities: low, normal, high, rt
86+
# and 3 process io priorities: low, normal, high
87+
# For IO, rt == high
88+
if os_name == "nt":
89+
PRIORITIES = {
90+
"process": {
91+
"low": IDLE_PRIORITY_CLASS,
92+
"normal": NORMAL_PRIORITY_CLASS,
93+
"high": HIGH_PRIORITY_CLASS,
94+
"rt": REALTIME_PRIORITY_CLASS,
95+
},
96+
"io": {
97+
"low": IOPRIO_LOW,
98+
"normal": IOPRIO_NORMAL,
99+
"high": IOPRIO_HIGH,
100+
},
101+
}
102+
else:
103+
PRIORITIES = {
104+
"process": {
105+
"low": 15,
106+
"normal": 0,
107+
"high": -15,
108+
"rt": -20,
109+
},
110+
"io": {
111+
"low": IOPRIO_CLASS_IDLE,
112+
"normal": IOPRIO_CLASS_BE,
113+
"high": IOPRIO_CLASS_RT,
114+
},
115+
}
116+
117+
67118
try:
68119
import signal
69120
except ImportError:
@@ -263,8 +314,8 @@ def _set_priority(
263314
priority_type, # type: str
264315
):
265316
"""
266-
Set process and / or io priorities
267-
Since Windows and Linux use different possible values, let's simplify things by allowing 3 prioriy types
317+
Set process and / or io prioritie
318+
let's simplify things by allowing 3 priority types
268319
"""
269320
priority = priority.lower()
270321

@@ -279,34 +330,15 @@ def _set_priority(
279330
if priority_type == "io" and priority not in ["low", "normal", "high"]:
280331
raise ValueError("Bogus {} priority given: {}".format(priority_type, priority))
281332

282-
if os_name == "nt":
283-
priorities = {
284-
"process": {
285-
"low": BELOW_NORMAL_PRIORITY_CLASS,
286-
"normal": NORMAL_PRIORITY_CLASS,
287-
"high": HIGH_PRIORITY_CLASS,
288-
},
289-
"io": {"low": IOPRIO_LOW, "normal": IOPRIO_NORMAL, "high": IOPRIO_HIGH},
290-
}
291-
else:
292-
priorities = {
293-
"process": {"low": 15, "normal": 0, "high": -15},
294-
"io": {
295-
"low": IOPRIO_CLASS_IDLE,
296-
"normal": IOPRIO_CLASS_BE,
297-
"high": IOPRIO_CLASS_RT,
298-
},
299-
}
300-
301333
if priority_type == "process":
302334
# Allow direct priority nice settings under linux
303335
if isinstance(priority, int):
304336
_priority = priority
305337
else:
306-
_priority = priorities[priority_type][priority]
338+
_priority = PRIORITIES[priority_type][priority]
307339
psutil.Process(pid).nice(_priority)
308340
elif priority_type == "io":
309-
psutil.Process(pid).ionice(priorities[priority_type][priority])
341+
psutil.Process(pid).ionice(PRIORITIES[priority_type][priority])
310342
else:
311343
raise ValueError("Bogus priority type given.")
312344

@@ -961,9 +993,22 @@ def _monitor_process(
961993

962994
# Python >= 3.3 has SubProcessError(TimeoutExpired) class
963995
# Python >= 3.6 has encoding & error arguments
996+
# Python >= 3.7 has creationflags argument
964997
# universal_newlines=True makes netstat command fail under windows
965998
# timeout does not work under Python 2.7 with subprocess32 < 3.5
966999
# decoder may be cp437 or unicode_escape for dos commands or utf-8 for powershell
1000+
1001+
process_prio = 0
1002+
if priority:
1003+
if isinstance(priority, int) and os_name != "nt" and -20 <= priority <= 20:
1004+
raise ValueError("Bogus process priority int given: {}".format(priority))
1005+
else:
1006+
process_prio = PRIORITIES["process"][priority.lower()]
1007+
if os_name == "nt" and sys.version_info >= (3, 7):
1008+
kwargs["creationflags"] = kwargs.pop("creationflags", 0) | process_prio
1009+
else:
1010+
kwargs["preexec_fn"] = lambda: os.nice(process_prio)
1011+
9671012
# Disabling pylint error for the same reason as above
9681013
# pylint: disable=E1123
9691014
if sys.version_info >= (3, 6):
@@ -995,8 +1040,8 @@ def _monitor_process(
9951040
**kwargs
9961041
)
9971042

998-
# Set process priority if given
999-
if priority:
1043+
# Set process priority if not set earlier by creationflags or preexec_fn
1044+
if priority and sys.version_info < (3, 7) and os_name == "nt":
10001045
try:
10011046
try:
10021047
set_priority(process.pid, priority)
@@ -1236,3 +1281,6 @@ def deferred_command(command, defer_time=300):
12361281
stderr=None,
12371282
close_fds=True,
12381283
)
1284+
1285+
1286+
command_runner("ping 127.0.0.1 -n 100", live_output=True, priority="low")

0 commit comments

Comments
 (0)