Skip to content

Commit 35a0d6a

Browse files
committed
Refactor operations to fully work on AArch64.
Create IntelPstateOperation class for Intel P-State operations. Enable CPUGovernor on AArch64 platforms.
1 parent 5ac2a2d commit 35a0d6a

File tree

1 file changed

+174
-137
lines changed

1 file changed

+174
-137
lines changed

pyperf/_system.py

+174-137
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT = 38
2020

2121
OS_LINUX = sys.platform.startswith('linux')
22+
PLATFORM_X86 = platform.machine() in ('x86', 'x86_64', 'amd64')
2223

2324

2425
def is_root():
@@ -119,18 +120,113 @@ def write(self, tune):
119120
pass
120121

121122

123+
class IntelPstateOperation(Operation):
124+
@staticmethod
125+
def available():
126+
return use_intel_pstate()
127+
128+
129+
class TurboBoostIntelPstate(IntelPstateOperation):
130+
"""
131+
Get/Set Turbo Boost mode of Intel CPUs by reading from/writing into
132+
/sys/devices/system/cpu/intel_pstate/no_turbo of the intel_pstate driver.
133+
"""
134+
135+
def __init__(self, system):
136+
IntelPstateOperation.__init__(self, 'Turbo Boost (intel_pstate)', system)
137+
self.path = sysfs_path("devices/system/cpu/intel_pstate/no_turbo")
138+
self.enabled = None
139+
140+
def read_turbo_boost(self):
141+
no_turbo = self.read_first_line(self.path)
142+
if no_turbo == '1':
143+
self.enabled = False
144+
elif no_turbo == '0':
145+
self.enabled = True
146+
else:
147+
self.error("Invalid no_turbo value: %r" % no_turbo)
148+
self.enabled = None
149+
150+
def show(self):
151+
self.read_turbo_boost()
152+
if self.enabled is not None:
153+
state = 'enabled' if self.enabled else 'disabled'
154+
self.log_state("Turbo Boost %s" % state)
155+
156+
self.tuned_for_benchmarks = (not self.enabled)
157+
if self.enabled:
158+
self.advice('Disable Turbo Boost to get more reliable '
159+
'CPU frequency')
160+
161+
def write(self, tune):
162+
enable = (not tune)
163+
164+
self.read_turbo_boost()
165+
if self.enabled == enable:
166+
# no_turbo already set to the expected value
167+
return
168+
169+
content = '0' if enable else '1'
170+
try:
171+
write_text(self.path, content)
172+
except OSError as exc:
173+
# don't log a permission error if the user is root: permission
174+
# error as root means that Turbo Boost is disabled in the BIOS
175+
if not is_root():
176+
self.check_permission_error(exc)
177+
178+
action = 'enable' if enable else 'disable'
179+
msg = "Failed to %s Turbo Boost" % action
180+
disabled_in_bios = is_permission_error(exc) and is_root()
181+
if disabled_in_bios:
182+
msg += " (Turbo Boost disabled in the BIOS?)"
183+
msg = "%s: failed to write into %s: %s" % (msg, self.path, exc)
184+
185+
if disabled_in_bios:
186+
self.log_action("WARNING: %s" % msg)
187+
else:
188+
self.error(msg)
189+
return
190+
191+
msg = "%r written into %s" % (content, self.path)
192+
action = 'enabled' if enable else 'disabled'
193+
self.log_action("Turbo Boost %s: %s" % (action, msg))
194+
195+
196+
class CheckNOHZFullIntelPstate(IntelPstateOperation):
197+
198+
def __init__(self, system):
199+
IntelPstateOperation.__init__(self, 'Check nohz_full', system)
200+
201+
def show(self):
202+
nohz_full = self.read_first_line(sysfs_path('devices/system/cpu/nohz_full'))
203+
if not nohz_full:
204+
return
205+
206+
nohz_full = parse_cpu_list(nohz_full)
207+
if not nohz_full:
208+
return
209+
210+
used = set(self.system.cpus) | set(nohz_full)
211+
if not used:
212+
return
213+
214+
self.advice("WARNING: nohz_full is enabled on CPUs %s which use the "
215+
"intel_pstate driver, whereas intel_pstate is incompatible "
216+
"with nohz_full"
217+
% format_cpu_list(used))
218+
self.advice("See https://bugzilla.redhat.com/show_bug.cgi?id=1378529")
219+
self.tuned_for_benchmarks = False
220+
221+
122222
class TurboBoostMSR(Operation):
123223
"""
124-
Get/Set Turbo Boost mode of Intel CPUs using /dev/cpu/N/msr.
224+
Get/Set Turbo Boost mode of X86 CPUs using /dev/cpu/N/msr
125225
"""
126226

127227
@staticmethod
128228
def available():
129-
return (
130-
OS_LINUX and
131-
not use_intel_pstate() and
132-
platform.machine() in ('x86', 'x86_64', 'amd64')
133-
)
229+
return OS_LINUX and PLATFORM_X86 and not use_intel_pstate()
134230

135231
def __init__(self, system):
136232
Operation.__init__(self, 'Turbo Boost (MSR)', system)
@@ -266,125 +362,92 @@ def write(self, tune):
266362
break
267363

268364

269-
class TurboBoostIntelPstate(Operation):
365+
class CPUGovernor(Operation):
270366
"""
271-
Get/Set Turbo Boost mode of Intel CPUs by reading from/writing into
272-
/sys/devices/system/cpu/intel_pstate/no_turbo of the intel_pstate driver.
367+
Get/Set CPU scaling governor
273368
"""
369+
BENCHMARK_GOVERNOR = 'performance'
274370

275-
@staticmethod
276-
def available():
277-
return use_intel_pstate()
371+
@classmethod
372+
def available(cls):
373+
return os.path.exists(
374+
sysfs_path("devices/system/cpu/cpu0/cpufreq/scaling_governor")
375+
)
278376

279377
def __init__(self, system):
280-
Operation.__init__(self, 'Turbo Boost (intel_pstate)', system)
281-
self.path = sysfs_path("devices/system/cpu/intel_pstate/no_turbo")
282-
self.enabled = None
283-
284-
def read_turbo_boost(self):
285-
no_turbo = self.read_first_line(self.path)
286-
if no_turbo == '1':
287-
self.enabled = False
288-
elif no_turbo == '0':
289-
self.enabled = True
290-
else:
291-
self.error("Invalid no_turbo value: %r" % no_turbo)
292-
self.enabled = None
293-
294-
def show(self):
295-
self.read_turbo_boost()
296-
if self.enabled is not None:
297-
state = 'enabled' if self.enabled else 'disabled'
298-
self.log_state("Turbo Boost %s" % state)
299-
300-
self.tuned_for_benchmarks = (not self.enabled)
301-
if self.enabled:
302-
self.advice('Disable Turbo Boost to get more reliable '
303-
'CPU frequency')
304-
305-
def write(self, tune):
306-
enable = (not tune)
307-
308-
self.read_turbo_boost()
309-
if self.enabled == enable:
310-
# no_turbo already set to the expected value
311-
return
378+
Operation.__init__(self, 'CPU scaling governor', system)
379+
self.device_syspath = sysfs_path("devices/system/cpu")
312380

313-
content = '0' if enable else '1'
381+
def read_governor(self, cpu):
382+
filename = os.path.join(self.device_syspath, 'cpu%s/cpufreq/scaling_governor' % cpu)
314383
try:
315-
write_text(self.path, content)
384+
with open(filename, "r") as fp:
385+
return fp.readline().rstrip()
316386
except OSError as exc:
317-
# don't log a permission error if the user is root: permission
318-
# error as root means that Turbo Boost is disabled in the BIOS
319-
if not is_root():
320-
self.check_permission_error(exc)
387+
self.check_permission_error(exc)
388+
self.error("Unable to read CPU scaling governor from %s" % filename)
389+
return None
321390

322-
action = 'enable' if enable else 'disable'
323-
msg = "Failed to %s Turbo Boost" % action
324-
disabled_in_bios = is_permission_error(exc) and is_root()
325-
if disabled_in_bios:
326-
msg += " (Turbo Boost disabled in the BIOS?)"
327-
msg = "%s: failed to write into %s: %s" % (msg, self.path, exc)
391+
def show(self):
392+
cpus = {}
393+
for cpu in range(self.system.logical_cpu_count):
394+
governor = self.read_governor(cpu)
395+
if governor is not None:
396+
cpus[cpu] = governor
328397

329-
if disabled_in_bios:
330-
self.log_action("WARNING: %s" % msg)
331-
else:
332-
self.error(msg)
398+
infos = format_cpu_infos(cpus)
399+
if not infos:
333400
return
401+
self.log_state('; '.join(infos))
334402

335-
msg = "%r written into %s" % (content, self.path)
336-
action = 'enabled' if enable else 'disabled'
337-
self.log_action("Turbo Boost %s: %s" % (action, msg))
338-
403+
self.tuned_for_benchmarks = all(
404+
governor == self.BENCHMARK_GOVERNOR for governor in cpus.values()
405+
)
406+
if not self.tuned_for_benchmarks:
407+
self.advice('Use CPU scaling governor %r'
408+
% self.BENCHMARK_GOVERNOR)
339409

340-
class CPUGovernorIntelPstate(Operation):
341-
"""
342-
Get/Set CPU scaling governor of the intel_pstate driver.
343-
"""
344-
BENCHMARK_GOVERNOR = 'performance'
410+
def write_governor(self, filename, new_governor):
411+
with open(filename, "r") as fp:
412+
governor = fp.readline().rstrip()
345413

346-
@staticmethod
347-
def available():
348-
return use_intel_pstate()
414+
if new_governor == governor:
415+
return False
349416

350-
def __init__(self, system):
351-
Operation.__init__(self, 'CPU scaling governor (intel_pstate)',
352-
system)
353-
self.path = sysfs_path("devices/system/cpu/cpu0/cpufreq/scaling_governor")
354-
self.governor = None
355-
356-
def read_governor(self):
357-
governor = self.read_first_line(self.path)
358-
if governor:
359-
self.governor = governor
360-
else:
361-
self.error("Unable to read CPU scaling governor from %s" % self.path)
417+
with open(filename, "w") as fp:
418+
fp.write(new_governor)
419+
return True
362420

363-
def show(self):
364-
self.read_governor()
365-
if not self.governor:
366-
return
421+
def write_cpu(self, cpu, tune):
422+
governor = self.read_governor(cpu)
423+
if not governor:
424+
self.warning("Unable to read governor of CPU %s" % (cpu))
425+
return False
367426

368-
self.log_state(self.governor)
369-
self.tuned_for_benchmarks = (self.governor == self.BENCHMARK_GOVERNOR)
370-
if not self.tuned_for_benchmarks:
371-
self.advice('Use CPU scaling governor %r'
372-
% self.BENCHMARK_GOVERNOR)
427+
new_governor = self.BENCHMARK_GOVERNOR if tune else "powersave"
428+
filename = os.path.join(self.device_syspath, 'cpu%s/cpufreq/scaling_governor' % cpu)
429+
try:
430+
return self.write_governor(filename, new_governor)
431+
except OSError as exc:
432+
self.check_permission_error(exc)
433+
self.error("Unable to write governor of CPU %s: %s"
434+
% (cpu, exc))
373435

374436
def write(self, tune):
375-
self.read_governor()
376-
if not self.governor:
377-
return
437+
modified = []
438+
for cpu in self.system.cpus:
439+
if self.write_cpu(cpu, tune):
440+
modified.append(cpu)
441+
if self.permission_error:
442+
break
378443

379-
new_governor = 'performance' if tune else 'powersave'
380-
if new_governor == self.governor:
381-
return
382-
try:
383-
write_text(self.path, new_governor)
384-
except OSError as exc:
385-
self.error("Failed to set the CPU scaling governor: %s" % exc)
386-
else:
387-
self.log_action("CPU scaling governor set to %s" % new_governor)
444+
if modified:
445+
cpus = format_cpu_list(modified)
446+
if tune:
447+
action = "set to performance"
448+
else:
449+
action = "reset to powersave"
450+
self.log_action("CPU scaling governor of CPUs %s %s" % (cpus, action))
388451

389452

390453
class LinuxScheduler(Operation):
@@ -828,35 +891,6 @@ def write(self, tune):
828891
self.write_irqs(cpus)
829892

830893

831-
class CheckNOHZFullIntelPstate(Operation):
832-
@staticmethod
833-
def available():
834-
return use_intel_pstate()
835-
836-
def __init__(self, system):
837-
Operation.__init__(self, 'Check nohz_full', system)
838-
839-
def show(self):
840-
nohz_full = self.read_first_line(sysfs_path('devices/system/cpu/nohz_full'))
841-
if not nohz_full:
842-
return
843-
844-
nohz_full = parse_cpu_list(nohz_full)
845-
if not nohz_full:
846-
return
847-
848-
used = set(self.system.cpus) | set(nohz_full)
849-
if not used:
850-
return
851-
852-
self.advice("WARNING: nohz_full is enabled on CPUs %s which use the "
853-
"intel_pstate driver, whereas intel_pstate is incompatible "
854-
"with nohz_full"
855-
% format_cpu_list(used))
856-
self.advice("See https://bugzilla.redhat.com/show_bug.cgi?id=1378529")
857-
self.tuned_for_benchmarks = False
858-
859-
860894
class PowerSupply(Operation):
861895
path = sysfs_path('class/power_supply')
862896

@@ -950,18 +984,21 @@ def write(self, tune):
950984

951985

952986
OPERATIONS = [
987+
# Generic operations
953988
PerfEvent,
954989
ASLR,
955990
LinuxScheduler,
956991
CPUFrequency,
992+
IRQAffinity,
993+
PowerSupply,
957994
# Setting the CPU scaling governor resets no_turbo
958995
# and so must be set before Turbo Boost
959-
CPUGovernorIntelPstate,
996+
CPUGovernor,
997+
# Intel Pstate Operations
960998
TurboBoostIntelPstate,
961999
CheckNOHZFullIntelPstate,
1000+
# X86 Operations
9621001
TurboBoostMSR,
963-
IRQAffinity,
964-
PowerSupply,
9651002
]
9661003

9671004

0 commit comments

Comments
 (0)