Commit a6f3f1cd authored by Alejandro Homs Puron's avatar Alejandro Homs Puron
Browse files

[SET_CPU_AFFINITY] CPUFreq: support cpufreq-utils support & 'cpufreq_governor' in config

parent 30720585
......@@ -98,9 +98,6 @@ class SMPSystem:
NbCPUs = 0
MaxNbCPUs = 0
PerformanceCPUFreqGovernor = 'performance'
OnDemandCPUFreqGovernor = 'ondemand'
@classmethod
def getNbCPUs(klass):
if klass.NbCPUs == 0:
......@@ -121,43 +118,153 @@ class SMPSystem:
def getCPUSysfsDir(klass, cpu):
return f'/sys/devices/system/cpu/cpu{cpu}'
class CPUFreqRawFileSetter:
@classmethod
def getBaseDir(klass, cpu):
return os.path.join(SMPSystem.getCPUSysfsDir(cpu), 'cpufreq')
@classmethod
def getScalingGovernorFile(klass, cpu):
return os.path.join(klass.getBaseDir(cpu), 'scaling_governor')
@classmethod
def getAvailableGovernorsFile(klass, cpu):
return os.path.join(klass.getBaseDir(cpu), 'scaling_available_governor')
@classmethod
def getCPUFreqDir(klass, cpu):
return os.path.join(klass.getCPUSysfsDir(cpu), 'cpufreq')
def getAvailableGovernors(klass, cpu):
fname = klass.getAvailableGovernorsFile()
cmd = SystemCmd(['cat', fname], try_sudo=False)
cat = cmd.doPopen(stdout=PIPE, text=True)
return cat.stdout.readline().strip().split()
@classmethod
def getCPUFreqCurrGovernor(klass, cpu):
fname = os.path.join(klass.getCPUFreqDir(cpu), 'scaling_governor')
cmd = SystemCmd(['cat', fname])
cat = cmd.doPopen(stdout=PIPE)
return cat.stdout.readline().strip()
def getCurrGovernor(klass, cpu_list):
governor_list = []
for cpu in cpu_list:
fname = klass.getScalingGovernorFile()
cmd = SystemCmd(['cat', fname], try_sudo=False)
cat = cmd.doPopen(stdout=PIPE, text=True)
governor_list.append(cat.stdout.readline().strip())
return governor_list
@classmethod
def setCPUFreqCurrGovernor(klass, cpu_list, governor):
def setCurrGovernor(klass, cpu_list, governor):
cpu_cmds = []
for cpu in cpu_list:
fname = os.path.join(klass.getCPUFreqDir(cpu), 'scaling_governor')
fname = klass.getScalingGovernorFile()
cpu_cmds.append(f'echo {governor} > {fname}')
bash_cmd = ' && '.join(cpu_cmds)
cmd = SystemCmd(['bash', '-c', bash_cmd])
if cmd.execute() != 0:
raise RuntimeError(f'Cannot set CPU {cpu} freq. governor '
raise RuntimeError(f'Cannot set CPUs {cpu_list} freq. governor '
f'to {governor}')
class CPUFreqUtilsSetter:
Info = 'cpufreq-info'
Set = 'cpufreq-set'
@classmethod
def getAvailableGovernors(klass, cpu):
cmd = SystemCmd([klass.Info, '-c', str(cpu), '-g'], try_sudo=False)
info = cmd.doPopen(stdout=PIPE, text=True)
avail = info.stdout.readline().strip().split()
return avail
@classmethod
def setAllCPUFreqGovernor(klass, governor):
def getGovernorInfo(klass, cpu):
cmd = SystemCmd([klass.Info, '-c', str(cpu), '-p'], try_sudo=False)
info = cmd.doPopen(stdout=PIPE, text=True)
min_freq, max_freq, policy = info.stdout.readline().strip().split()
return min_freq, max_freq, policy
@classmethod
def getCurrGovernor(klass, cpu_list):
governors = []
for cpu in cpu_list:
min_freq, max_freq, policy = klass.getGovernorInfo(cpu)
governors.append(policy)
return governors
@classmethod
def setCurrGovernor(klass, cpu_list, governor):
for cpu in cpu_list:
min_freq, max_freq, policy = klass.getGovernorInfo(cpu)
cmd = SystemCmd([klass.Set, '-c', str(cpu), '-g', governor,
'-d', min_freq, '-u', max_freq])
if cmd.execute() != 0:
raise RuntimeError(f'Cannot set CPU {cpu} freq. governor '
f'to {governor}')
class CPUFreqMgr:
PerformanceGovernors = ['performance']
PowerSaveGovernors = ['ondemand', 'powersave']
def __init__(self, target_governors=None,
default_governors=PowerSaveGovernors, setter=None):
self.m_setter = setter or self.getSetter()
if target_governors:
if not self.m_setter:
raise RuntimeError('No available CPUFreq setter: '
'install cpufreq-utils or provide '
'sudo privileges')
available_targets = self.getAvailableGovernorsFrom(target_governors)
if not available_targets:
raise ValueError(f'None of the target governors '
f'{target_governors} is available')
self.m_target_governor = available_targets[0]
else:
self.m_target_governor = None
available_defaults = self.getAvailableGovernorsFrom(default_governors)
if not available_defaults:
raise ValueError(f'None of the default governors '
f'{default_governors} is available')
self.m_default_governor = available_defaults[0]
print(f'default_governor={self.m_default_governor}')
def getSetter(self):
for klass in [CPUFreqUtilsSetter, CPUFreqRawFileSetter]:
try:
setter = klass()
cpu_list=[0]
governors = setter.getCurrGovernor(cpu_list)
setter.setCurrGovernor(cpu_list, governors[0])
return setter
except:
pass
return None
def getAvailableGovernorsFrom(self, governors):
available_governors = None
for cpu in range(SMPSystem.getNbCPUs()):
available_for_this = self.m_setter.getAvailableGovernors(cpu)
if available_governors is None:
available_governors = available_for_this
else:
available_governors = [g for g in available_for_this
if g in available_governors]
return [g for g in governors if g in available_governors]
def setAllGovernors(self, governor):
print(f'Setting all CPUs freq. governor to {governor} ...')
klass.setCPUFreqCurrGovernor(range(klass.getNbCPUs()), governor)
self.m_setter.setCurrGovernor(range(SMPSystem.getNbCPUs()), governor)
def __enter__(self):
if self.m_target_governor:
self.setAllGovernors(self.m_target_governor)
@contextmanager
def all_cpu_freq_governor(governor,
default_governor=SMPSystem.OnDemandCPUFreqGovernor):
SMPSystem.setAllCPUFreqGovernor(governor)
try:
yield
finally:
SMPSystem.setAllCPUFreqGovernor(default_governor)
def __exit__(self, *args):
if self.m_target_governor:
self.setAllGovernors(self.m_default_governor)
def CPU(*args):
......@@ -568,6 +675,7 @@ class CPUAffinityDataJSONParser:
config = json.loads(json_str)
self.m_json = None
listener = []
cpufreq_governor = None
lima = ProcessMgr.DefaultAffinity
other = ProcessMgr.DefaultAffinity
net_dev = []
......@@ -578,6 +686,7 @@ class CPUAffinityDataJSONParser:
self.m_json = config['cpu_affinity']
if 'recv' in self.m_json:
listener = self.listenerAffinityFromJSON(self.m_json['recv'])
cpufreq_governor = self.m_json.get('cpufreq_governor', None)
if 'lima' in self.m_json:
lima = self.limaAffinityFromJSON(self.m_json['lima'])
if 'other' in self.m_json:
......@@ -585,8 +694,9 @@ class CPUAffinityDataJSONParser:
if 'net_dev' in self.m_json:
net_dev = [self.netDevGroupAffinityFromJSON(json)
for json in self.m_json['net_dev']]
self.m_global_data = dict(listener=listener, lima=lima, other=other,
net_dev=net_dev)
self.m_global_data = dict(listener=listener,
cpufreq_governor=cpufreq_governor, lima=lima,
other=other, net_dev=net_dev)
@classmethod
def listenerAffinityFromRecvsJSON(klass, recvs):
......@@ -682,7 +792,7 @@ def main(argv):
for l in CPUGlobalDataToStringLines(cpu_affinity_data):
print(l)
with all_cpu_freq_governor(SMPSystem.PerformanceCPUFreqGovernor):
with CPUFreqMgr([cpu_affinity_data['cpufreq_governor']]):
with net_dev_groups_cpu_affinity(cpu_affinity_data['net_dev']):
with ProcessMgr(cpu_affinity_data['other']):
def child_func(affinity, *argv):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment