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)
30 proc_name = proc_cmdline.split(
" ")
31 target =
"--name" if "--name" in proc_name
else "-n"
33 proc_name = proc_name[proc_name.index(target) + 1]
35 raise ValueError(
"Cannot find application name in the command line using -n or --name")
41 if type(mask) == list:
44 elif type(mask) == str:
45 for region_str
in mask.split(
','):
47 region = region_str.replace(
" ",
"").split(
'-')
49 cpu_mask.add(int(region[0]))
50 elif len(region) == 2:
51 cpu_from = int(region[0])
52 cpu_to = int(region[1])
53 for cpu
in range(cpu_from, cpu_to+1):
56 raise Exception(
'This is neither a single CPU or a range of CPUs:', mask)
57 except Exception
as e:
58 raise Exception(
'Corrcupt CPU mask region! Mask string:', mask,
'Exception:', e)
60 raise Exception(
'CPU mask needs to be string or list. Current:', mask)
64print(
'### Parsing CPU mask file...')
67 with open(pinfile,
'r')
as f:
68 affinity_json = json.load(f)
69 for proc
in affinity_json:
70 if proc ==
'_comment':
73 affinity_dict[proc] = {}
74 for proc_opts
in affinity_json[proc]:
75 affinity_dict[proc][proc_opts] = {}
76 for aff_field
in affinity_json[proc][proc_opts]:
77 if aff_field ==
'parent':
78 aff_value = affinity_json[proc][proc_opts][aff_field]
79 affinity_dict[proc][proc_opts][
'parent'] =
parse_cpumask(aff_value)
80 elif aff_field ==
'threads':
81 affinity_dict[proc][proc_opts][
'threads'] = {}
82 for thr_aff_field
in affinity_json[proc][proc_opts][aff_field]:
83 aff_value = affinity_json[proc][proc_opts][aff_field][thr_aff_field]
84 affinity_dict[proc][proc_opts][
'threads'][thr_aff_field] = {
85 'regex': re.compile(thr_aff_field),
89 print(
'Expected affinity fields are \'parent\' or \'threads\'! Ignoring field: ' + aff_field)
97proc_names = affinity_dict.keys()
99print(
'### Attempt to find and apply cpu mask for the following processes:', proc_names)
100for proc
in psutil.process_iter():
101 if proc.name()
in proc_names:
105 names_dict = affinity_dict[proc.name()].keys()
106 proc_cmdline =
' '.join(proc.cmdline())
108 for mask_name
in names_dict:
109 if mask_name == proc_name:
110 print(
' -> Found process to mask!')
111 print(
' + Command line:', proc_cmdline)
112 print(
' + Process ID (PID):', proc.pid)
113 print(
' + Detailed memory info:', proc.memory_info())
114 rss =
'Resident Set Size (RSS): ' +
str(
'{:.2f}'.format(proc.memory_info().rss/1024/1024)) +
' [MB]'
115 vms =
'Virtual Memory Size (VMS): ' +
str(
'{:.2f}'.format(proc.memory_info().vms/1024/1024)) +
' [MB]'
116 print(
' + Memory info:', rss,
'|', vms)
117 connections = proc.connections()
118 print(
' + Network connection count:', len(connections))
119 children = proc.children(recursive=
True)
120 print(
' + Children count:', len(children))
121 threads = proc.threads()
122 print(
' + Thread count:', len(threads))
124 if 'parent' in affinity_dict[proc.name()][mask_name].keys():
125 mask = affinity_dict[proc.name()][mask_name][
'parent']
126 print(
' + Parent mask specified! Applying mask for every children and thread!')
127 print(
' - mask:', mask)
128 if max(mask) > lcpu_count:
129 print(
'WARNING! CPU Mask contains higher CPU IDs than logical CPU count visible by the kernel!')
132 for child
in children:
133 cid = psutil.Process(child.pid)
134 cid.cpu_affinity(mask)
135 for thread
in threads:
136 tid = psutil.Process(thread.id)
137 tid.cpu_affinity(mask)
139 if 'threads' in affinity_dict[proc.name()][mask_name]:
140 print(
' + Thread masks specified! Applying thread specific masks!')
141 for thread
in threads:
142 tid = psutil.Process(thread.id)
143 thread_masks = affinity_dict[proc.name()][mask_name][
'threads']
147 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]
148 if len(mask_matches) > 1:
149 raise ValueError(f
"Thread {tid.name()} mask_matches multiple masks {mask_matches}")
150 elif len(mask_matches) == 0:
154 ((_,cpu_list),) = mask_matches
158 print(f
' - For thread {tid.name()} applying mask {cpu_list}')
159 if max(cpu_list) > lcpu_count:
160 print(
'WARNING! CPU Mask contains higher CPU IDs than logical CPU count visible by the kernel!')
163 tid.cpu_affinity(cpu_list)
171print(
'### CPU affinity applied!')
parse_cpumask(mask)
Parses CPU mask strings and lists.
get_app_name(proc_cmdline)