Skip to content

Commit 2b9591d

Browse files
diegorussovstinner
andauthored
Refactor operations to fully work on AArch64. (#191)
* Refactor operations to fully work on AArch64. Create IntelPstateOperation class for Intel P-State operations. Enable CPUGovernor on AArch64 platforms. * Address PR comments * Update pyperf/_system.py Co-authored-by: Victor Stinner <[email protected]> --------- Co-authored-by: Victor Stinner <[email protected]>
1 parent 5ac2a2d commit 2b9591d

File tree

1 file changed

+96
-56
lines changed

1 file changed

+96
-56
lines changed

pyperf/_system.py

Lines changed: 96 additions & 56 deletions
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,21 +120,23 @@ def write(self, tune):
119120
pass
120121

121122

123+
class IntelPstateOperation(Operation):
124+
@staticmethod
125+
def available():
126+
return use_intel_pstate()
127+
128+
122129
class TurboBoostMSR(Operation):
123130
"""
124-
Get/Set Turbo Boost mode of Intel CPUs using /dev/cpu/N/msr.
131+
Get/Set Turbo Boost mode of x86 CPUs using /dev/cpu/N/msr
125132
"""
126133

127134
@staticmethod
128135
def available():
129-
return (
130-
OS_LINUX and
131-
not use_intel_pstate() and
132-
platform.machine() in ('x86', 'x86_64', 'amd64')
133-
)
136+
return OS_LINUX and PLATFORM_X86 and not use_intel_pstate()
134137

135138
def __init__(self, system):
136-
Operation.__init__(self, 'Turbo Boost (MSR)', system)
139+
super().__init__('Turbo Boost (MSR)', system)
137140
self.cpu_states = {}
138141
self.have_device = True
139142

@@ -266,18 +269,14 @@ def write(self, tune):
266269
break
267270

268271

269-
class TurboBoostIntelPstate(Operation):
272+
class TurboBoostIntelPstate(IntelPstateOperation):
270273
"""
271274
Get/Set Turbo Boost mode of Intel CPUs by reading from/writing into
272275
/sys/devices/system/cpu/intel_pstate/no_turbo of the intel_pstate driver.
273276
"""
274277

275-
@staticmethod
276-
def available():
277-
return use_intel_pstate()
278-
279278
def __init__(self, system):
280-
Operation.__init__(self, 'Turbo Boost (intel_pstate)', system)
279+
super().__init__('Turbo Boost (intel_pstate)', system)
281280
self.path = sysfs_path("devices/system/cpu/intel_pstate/no_turbo")
282281
self.enabled = None
283282

@@ -337,54 +336,92 @@ def write(self, tune):
337336
self.log_action("Turbo Boost %s: %s" % (action, msg))
338337

339338

340-
class CPUGovernorIntelPstate(Operation):
339+
class CPUGovernor(Operation):
341340
"""
342-
Get/Set CPU scaling governor of the intel_pstate driver.
341+
Get/Set CPU scaling governor
343342
"""
344343
BENCHMARK_GOVERNOR = 'performance'
345344

346345
@staticmethod
347346
def available():
348-
return use_intel_pstate()
347+
return os.path.exists(
348+
sysfs_path("devices/system/cpu/cpu0/cpufreq/scaling_governor")
349+
)
349350

350351
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)
352+
super().__init__('CPU scaling governor', system)
353+
self.device_syspath = sysfs_path("devices/system/cpu")
354+
355+
def read_governor(self, cpu):
356+
filename = os.path.join(self.device_syspath, 'cpu%s/cpufreq/scaling_governor' % cpu)
357+
try:
358+
with open(filename, "r") as fp:
359+
return fp.readline().rstrip()
360+
except OSError as exc:
361+
self.check_permission_error(exc)
362+
self.error("Unable to read CPU scaling governor from %s" % filename)
363+
return None
362364

363365
def show(self):
364-
self.read_governor()
365-
if not self.governor:
366+
cpus = {}
367+
for cpu in range(self.system.logical_cpu_count):
368+
governor = self.read_governor(cpu)
369+
if governor is not None:
370+
cpus[cpu] = governor
371+
372+
infos = format_cpu_infos(cpus)
373+
if not infos:
366374
return
375+
self.log_state('; '.join(infos))
367376

368-
self.log_state(self.governor)
369-
self.tuned_for_benchmarks = (self.governor == self.BENCHMARK_GOVERNOR)
377+
self.tuned_for_benchmarks = all(
378+
governor == self.BENCHMARK_GOVERNOR for governor in cpus.values()
379+
)
370380
if not self.tuned_for_benchmarks:
371381
self.advice('Use CPU scaling governor %r'
372382
% self.BENCHMARK_GOVERNOR)
373383

374-
def write(self, tune):
375-
self.read_governor()
376-
if not self.governor:
377-
return
384+
def write_governor(self, filename, new_governor):
385+
with open(filename, "r") as fp:
386+
governor = fp.readline().rstrip()
378387

379-
new_governor = 'performance' if tune else 'powersave'
380-
if new_governor == self.governor:
381-
return
388+
if new_governor == governor:
389+
return False
390+
391+
with open(filename, "w") as fp:
392+
fp.write(new_governor)
393+
return True
394+
395+
def write_cpu(self, cpu, tune):
396+
governor = self.read_governor(cpu)
397+
if not governor:
398+
self.warning("Unable to read governor of CPU %s" % (cpu))
399+
return False
400+
401+
new_governor = self.BENCHMARK_GOVERNOR if tune else "powersave"
402+
filename = os.path.join(self.device_syspath, 'cpu%s/cpufreq/scaling_governor' % cpu)
382403
try:
383-
write_text(self.path, new_governor)
404+
return self.write_governor(filename, new_governor)
384405
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)
406+
self.check_permission_error(exc)
407+
self.error("Unable to write governor of CPU %s: %s"
408+
% (cpu, exc))
409+
410+
def write(self, tune):
411+
modified = []
412+
for cpu in self.system.cpus:
413+
if self.write_cpu(cpu, tune):
414+
modified.append(cpu)
415+
if self.permission_error:
416+
break
417+
418+
if modified:
419+
cpus = format_cpu_list(modified)
420+
if tune:
421+
action = "set to performance"
422+
else:
423+
action = "reset to powersave"
424+
self.log_action("CPU scaling governor of CPUs %s %s" % (cpus, action))
388425

389426

390427
class LinuxScheduler(Operation):
@@ -398,7 +435,7 @@ def available():
398435
return OS_LINUX
399436

400437
def __init__(self, system):
401-
Operation.__init__(self, 'Linux scheduler', system)
438+
super().__init__('Linux scheduler', system)
402439
self.ncpu = None
403440
self.linux_version = None
404441

@@ -473,7 +510,7 @@ def available(cls):
473510
return os.path.exists(cls.path)
474511

475512
def __init__(self, system):
476-
Operation.__init__(self, 'ASLR', system)
513+
super().__init__('ASLR', system)
477514

478515
def show(self):
479516
line = self.read_first_line(self.path)
@@ -519,7 +556,7 @@ def available():
519556
return os.path.exists(sysfs_path("devices/system/cpu/cpu0/cpufreq"))
520557

521558
def __init__(self, system):
522-
Operation.__init__(self, 'CPU Frequency', system)
559+
super().__init__('CPU Frequency', system)
523560
self.device_syspath = sysfs_path("devices/system/cpu")
524561

525562
def read_cpu(self, cpu):
@@ -617,7 +654,7 @@ def available(cls):
617654
return os.path.exists(cls.irq_path)
618655

619656
def __init__(self, system):
620-
Operation.__init__(self, 'IRQ affinity', system)
657+
super().__init__('IRQ affinity', system)
621658
self.irq_affinity_path = os.path.join(self.irq_path, "%s/smp_affinity")
622659
self.default_affinity_path = os.path.join(self.irq_path, 'default_smp_affinity')
623660

@@ -828,13 +865,10 @@ def write(self, tune):
828865
self.write_irqs(cpus)
829866

830867

831-
class CheckNOHZFullIntelPstate(Operation):
832-
@staticmethod
833-
def available():
834-
return use_intel_pstate()
868+
class CheckNOHZFullIntelPstate(IntelPstateOperation):
835869

836870
def __init__(self, system):
837-
Operation.__init__(self, 'Check nohz_full', system)
871+
super().__init__('Check nohz_full', system)
838872

839873
def show(self):
840874
nohz_full = self.read_first_line(sysfs_path('devices/system/cpu/nohz_full'))
@@ -865,7 +899,7 @@ def available(cls):
865899
return os.path.exists(cls.path)
866900

867901
def __init__(self, system):
868-
Operation.__init__(self, 'Power supply', system)
902+
super().__init__('Power supply', system)
869903

870904
def read_power_supply(self):
871905
# Python implementation of the on_ac_power shell script
@@ -912,7 +946,7 @@ def available(cls):
912946
return os.path.exists(cls.path)
913947

914948
def __init__(self, system):
915-
Operation.__init__(self, 'Perf event', system)
949+
super().__init__('Perf event', system)
916950

917951
def read_max_sample_rate(self):
918952
line = self.read_first_line(self.path)
@@ -950,18 +984,24 @@ def write(self, tune):
950984

951985

952986
OPERATIONS = [
987+
# Generic operations
953988
PerfEvent,
954989
ASLR,
955990
LinuxScheduler,
956991
CPUFrequency,
992+
IRQAffinity,
993+
PowerSupply,
994+
957995
# Setting the CPU scaling governor resets no_turbo
958996
# and so must be set before Turbo Boost
959-
CPUGovernorIntelPstate,
997+
CPUGovernor,
998+
999+
# Intel Pstate Operations
9601000
TurboBoostIntelPstate,
9611001
CheckNOHZFullIntelPstate,
1002+
1003+
# X86 Operations
9621004
TurboBoostMSR,
963-
IRQAffinity,
964-
PowerSupply,
9651005
]
9661006

9671007

0 commit comments

Comments
 (0)