10info =
'Alters CPU masks of running processes with different arguments, based on a configuration file.'
11parser = argparse.ArgumentParser(description=info)
12parser.add_argument(
'--pinfile',
'-p', type=str, required=
True, help=
'file with process to CPU mask list')
14 args = parser.parse_args()
20print(
'### Basic information...')
21lcpu_count = len(os.sched_getaffinity(0))
22pcpu_count = psutil.cpu_count(logical=
False)
23vmem = psutil.virtual_memory()
24print(
' -> Logical CPU count: ', lcpu_count)
25print(
' -> Physical CPU count: ', pcpu_count)
26print(
' -> Memory status: ', vmem)
32 if type(mask) == list:
35 elif type(mask) == str:
36 for region_str
in mask.split(
','):
38 region = region_str.replace(
" ",
"").split(
'-')
40 cpu_mask.add(int(region[0]))
41 elif len(region) == 2:
42 cpu_from = int(region[0])
43 cpu_to = int(region[1])
44 for cpu
in range(cpu_from, cpu_to+1):
47 raise Exception(
'This is neither a single CPU or a range of CPUs:', mask)
48 except Exception
as e:
49 raise Exception(
'Corrcupt CPU mask region! Mask string:', mask,
'Exception:', e)
51 raise Exception(
'CPU mask needs to be string or list. Current:', mask)
55print(
'### Parsing CPU mask file...')
58 with open(pinfile,
'r')
as f:
59 affinity_json = json.load(f)
60 for proc
in affinity_json:
61 if proc ==
'_comment':
64 affinity_dict[proc] = {}
65 for proc_opts
in affinity_json[proc]:
66 affinity_dict[proc][proc_opts] = {}
67 for aff_field
in affinity_json[proc][proc_opts]:
68 if aff_field ==
'parent':
69 aff_value = affinity_json[proc][proc_opts][aff_field]
70 affinity_dict[proc][proc_opts][
'parent'] =
parse_cpumask(aff_value)
71 elif aff_field ==
'threads':
72 affinity_dict[proc][proc_opts][
'threads'] = {}
73 for thr_aff_field
in affinity_json[proc][proc_opts][aff_field]:
74 aff_value = affinity_json[proc][proc_opts][aff_field][thr_aff_field]
75 affinity_dict[proc][proc_opts][
'threads'][thr_aff_field] = {
76 'regex': re.compile(thr_aff_field),
80 print(
'Expected affinity fields are \'parent\' or \'threads\'! Ignoring field: ' + aff_field)
88proc_names = affinity_dict.keys()
90print(
'### Attempt to find and apply cpu mask for the following processes:', proc_names)
91for proc
in psutil.process_iter():
92 if proc.name()
in proc_names:
96 cmdline_dict = affinity_dict[proc.name()].keys()
97 proc_cmdline =
' '.join(proc.cmdline())
98 for cmdl
in cmdline_dict:
99 if cmdl
in proc_cmdline:
100 print(
' -> Found process to mask!')
101 print(
' + Command line:', proc_cmdline)
102 print(
' + Process ID (PID):', proc.pid)
103 print(
' + Detailed memory info:', proc.memory_info())
104 rss =
'Resident Set Size (RSS): ' +
str(
'{:.2f}'.format(proc.memory_info().rss/1024/1024)) +
' [MB]'
105 vms =
'Virtual Memory Size (VMS): ' +
str(
'{:.2f}'.format(proc.memory_info().vms/1024/1024)) +
' [MB]'
106 print(
' + Memory info:', rss,
'|', vms)
107 connections = proc.connections()
108 print(
' + Network connection count:', len(connections))
109 children = proc.children(recursive=
True)
110 print(
' + Children count:', len(children))
111 threads = proc.threads()
112 print(
' + Thread count:', len(threads))
114 if 'parent' in affinity_dict[proc.name()][cmdl].keys():
115 mask = affinity_dict[proc.name()][cmdl][
'parent']
116 print(
' + Parent mask specified! Applying mask for every children and thread!')
117 print(
' - mask:', mask)
118 if max(mask) > lcpu_count:
119 print(
'WARNING! CPU Mask contains higher CPU IDs than logical CPU count visible by the kernel!')
122 for child
in children:
123 cid = psutil.Process(child.id)
124 cid.cpu_affinity(mask)
125 for thread
in threads:
126 tid = psutil.Process(thread.id)
127 tid.cpu_affinity(mask)
129 if 'threads' in affinity_dict[proc.name()][cmdl]:
130 print(
' + Thread masks specified! Applying thread specific masks!')
131 for thread
in threads:
132 tid = psutil.Process(thread.id)
133 thread_masks = affinity_dict[proc.name()][cmdl][
'threads']
137 mask_matches = [ m
for m
in [(th_mask[
'regex'].fullmatch(tid.name()),th_mask[
'cpu_list'])
for th_mask
in thread_masks.values()]
if m[0]
is not None]
138 if len(mask_matches) > 1:
139 raise ValueError(f
"Thread {tid.name()} mask_matches multiple masks {mask_matches}")
140 elif len(mask_matches) == 0:
144 ((_,cpu_list),) = mask_matches
148 print(f
' - For thread {tid.name()} applying mask {cpu_list}')
149 if max(cpu_list) > lcpu_count:
150 print(
'WARNING! CPU Mask contains higher CPU IDs than logical CPU count visible by the kernel!')
153 tid.cpu_affinity(cpu_list)
161print(
'### CPU affinity applied!')
parse_cpumask(mask)
Parses CPU mask strings and lists.