14
14
import typing
15
15
from collections import defaultdict , namedtuple
16
16
from contextlib import contextmanager
17
- from pathlib import Path
18
17
from typing import Dict
19
18
20
19
import psutil
@@ -56,50 +55,45 @@ def set_cpu_affinity(pid: int, cpulist: list) -> list:
56
55
return psutil .Process (pid ).cpu_affinity (real_cpulist )
57
56
58
57
59
- def get_thread_name (pid : int , tid : int ) -> str :
60
- """Return thread name from pid and tid pair."""
61
- try :
62
- return (
63
- Path ("/proc" , str (pid ), "task" , str (tid ), "comm" ).read_text ("utf-8" ).strip ()
64
- )
65
- except FileNotFoundError as exc :
66
- raise psutil .NoSuchProcess (tid ) from exc
67
-
68
-
69
58
CpuTimes = namedtuple ("CpuTimes" , ["user" , "system" ])
70
59
71
60
72
- def get_cpu_times (pid : int ) -> Dict [str , CpuTimes ]:
61
+ def get_cpu_times (process : psutil . Process ) -> Dict [str , CpuTimes ]:
73
62
"""Return a dict mapping thread name to CPU usage (in seconds) since start."""
63
+ # We're consciously ignoring whatever erorr is returned by psutil and returning
64
+ # empty {} as result in case of any error retrieving the process threads
65
+ # information
66
+ # pylint: disable=locally-disabled, broad-exception-caught
67
+
74
68
threads = []
75
69
try :
76
- threads = psutil . Process ( pid ) .threads ()
77
- except psutil . NoSuchProcess as exc :
78
- logging .warning ("Process %d does not exist" , pid , exc_info = exc )
70
+ threads = process .threads ()
71
+ except Exception as exc :
72
+ logging .warning ("Process %d does not exist" , process . pid , exc_info = exc )
79
73
return {}
80
74
81
75
cpu_times = {}
82
76
for thread in threads :
83
77
try :
84
- thread_name = get_thread_name ( pid , thread .id )
78
+ thread_name = psutil . Process ( thread .id ). name ( )
85
79
cpu_times [thread_name ] = CpuTimes (thread .user_time , thread .system_time )
86
- except psutil . NoSuchProcess as exc :
80
+ except Exception as exc :
87
81
logging .warning ("Thread %d no longer exists" , thread .id , exc_info = exc )
88
82
continue
89
83
90
84
return cpu_times
91
85
92
86
93
87
def get_cpu_utilization (
94
- pid : int ,
88
+ process : psutil . Process ,
95
89
interval : int = 1 ,
96
90
split_user_system : bool = False ,
97
91
) -> Dict [str , float | CpuTimes ]:
98
92
"""Return current process per thread CPU utilization over the interval (seconds)."""
99
93
cpu_utilization = {}
100
- cpu_times_before = get_cpu_times (pid )
94
+ cpu_times_before = get_cpu_times (process )
101
95
time .sleep (interval )
102
- cpu_times_after = get_cpu_times (pid )
96
+ cpu_times_after = get_cpu_times (process )
103
97
threads = set (cpu_times_before .keys ()) & set (cpu_times_after .keys ())
104
98
for thread_name in threads :
105
99
before = cpu_times_before [thread_name ]
@@ -125,8 +119,9 @@ def track_cpu_utilization(
125
119
time .sleep (omit )
126
120
127
121
cpu_utilization = defaultdict (list )
122
+ process = psutil .Process (pid )
128
123
for _ in range (iterations ):
129
- current_cpu_utilization = get_cpu_utilization (pid )
124
+ current_cpu_utilization = get_cpu_utilization (process )
130
125
assert len (current_cpu_utilization ) > 0
131
126
132
127
for thread_name , value in current_cpu_utilization .items ():
0 commit comments