Skip to content

Commit

Permalink
Refactor operations to fully work on AArch64. (#191)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
diegorusso and vstinner authored May 26, 2024
1 parent 5ac2a2d commit 2b9591d
Showing 1 changed file with 96 additions and 56 deletions.
152 changes: 96 additions & 56 deletions pyperf/_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT = 38

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


def is_root():
Expand Down Expand Up @@ -119,21 +120,23 @@ def write(self, tune):
pass


class IntelPstateOperation(Operation):
@staticmethod
def available():
return use_intel_pstate()


class TurboBoostMSR(Operation):
"""
Get/Set Turbo Boost mode of Intel CPUs using /dev/cpu/N/msr.
Get/Set Turbo Boost mode of x86 CPUs using /dev/cpu/N/msr
"""

@staticmethod
def available():
return (
OS_LINUX and
not use_intel_pstate() and
platform.machine() in ('x86', 'x86_64', 'amd64')
)
return OS_LINUX and PLATFORM_X86 and not use_intel_pstate()

def __init__(self, system):
Operation.__init__(self, 'Turbo Boost (MSR)', system)
super().__init__('Turbo Boost (MSR)', system)
self.cpu_states = {}
self.have_device = True

Expand Down Expand Up @@ -266,18 +269,14 @@ def write(self, tune):
break


class TurboBoostIntelPstate(Operation):
class TurboBoostIntelPstate(IntelPstateOperation):
"""
Get/Set Turbo Boost mode of Intel CPUs by reading from/writing into
/sys/devices/system/cpu/intel_pstate/no_turbo of the intel_pstate driver.
"""

@staticmethod
def available():
return use_intel_pstate()

def __init__(self, system):
Operation.__init__(self, 'Turbo Boost (intel_pstate)', system)
super().__init__('Turbo Boost (intel_pstate)', system)
self.path = sysfs_path("devices/system/cpu/intel_pstate/no_turbo")
self.enabled = None

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


class CPUGovernorIntelPstate(Operation):
class CPUGovernor(Operation):
"""
Get/Set CPU scaling governor of the intel_pstate driver.
Get/Set CPU scaling governor
"""
BENCHMARK_GOVERNOR = 'performance'

@staticmethod
def available():
return use_intel_pstate()
return os.path.exists(
sysfs_path("devices/system/cpu/cpu0/cpufreq/scaling_governor")
)

def __init__(self, system):
Operation.__init__(self, 'CPU scaling governor (intel_pstate)',
system)
self.path = sysfs_path("devices/system/cpu/cpu0/cpufreq/scaling_governor")
self.governor = None

def read_governor(self):
governor = self.read_first_line(self.path)
if governor:
self.governor = governor
else:
self.error("Unable to read CPU scaling governor from %s" % self.path)
super().__init__('CPU scaling governor', system)
self.device_syspath = sysfs_path("devices/system/cpu")

def read_governor(self, cpu):
filename = os.path.join(self.device_syspath, 'cpu%s/cpufreq/scaling_governor' % cpu)
try:
with open(filename, "r") as fp:
return fp.readline().rstrip()
except OSError as exc:
self.check_permission_error(exc)
self.error("Unable to read CPU scaling governor from %s" % filename)
return None

def show(self):
self.read_governor()
if not self.governor:
cpus = {}
for cpu in range(self.system.logical_cpu_count):
governor = self.read_governor(cpu)
if governor is not None:
cpus[cpu] = governor

infos = format_cpu_infos(cpus)
if not infos:
return
self.log_state('; '.join(infos))

self.log_state(self.governor)
self.tuned_for_benchmarks = (self.governor == self.BENCHMARK_GOVERNOR)
self.tuned_for_benchmarks = all(
governor == self.BENCHMARK_GOVERNOR for governor in cpus.values()
)
if not self.tuned_for_benchmarks:
self.advice('Use CPU scaling governor %r'
% self.BENCHMARK_GOVERNOR)

def write(self, tune):
self.read_governor()
if not self.governor:
return
def write_governor(self, filename, new_governor):
with open(filename, "r") as fp:
governor = fp.readline().rstrip()

new_governor = 'performance' if tune else 'powersave'
if new_governor == self.governor:
return
if new_governor == governor:
return False

with open(filename, "w") as fp:
fp.write(new_governor)
return True

def write_cpu(self, cpu, tune):
governor = self.read_governor(cpu)
if not governor:
self.warning("Unable to read governor of CPU %s" % (cpu))
return False

new_governor = self.BENCHMARK_GOVERNOR if tune else "powersave"
filename = os.path.join(self.device_syspath, 'cpu%s/cpufreq/scaling_governor' % cpu)
try:
write_text(self.path, new_governor)
return self.write_governor(filename, new_governor)
except OSError as exc:
self.error("Failed to set the CPU scaling governor: %s" % exc)
else:
self.log_action("CPU scaling governor set to %s" % new_governor)
self.check_permission_error(exc)
self.error("Unable to write governor of CPU %s: %s"
% (cpu, exc))

def write(self, tune):
modified = []
for cpu in self.system.cpus:
if self.write_cpu(cpu, tune):
modified.append(cpu)
if self.permission_error:
break

if modified:
cpus = format_cpu_list(modified)
if tune:
action = "set to performance"
else:
action = "reset to powersave"
self.log_action("CPU scaling governor of CPUs %s %s" % (cpus, action))


class LinuxScheduler(Operation):
Expand All @@ -398,7 +435,7 @@ def available():
return OS_LINUX

def __init__(self, system):
Operation.__init__(self, 'Linux scheduler', system)
super().__init__('Linux scheduler', system)
self.ncpu = None
self.linux_version = None

Expand Down Expand Up @@ -473,7 +510,7 @@ def available(cls):
return os.path.exists(cls.path)

def __init__(self, system):
Operation.__init__(self, 'ASLR', system)
super().__init__('ASLR', system)

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

def __init__(self, system):
Operation.__init__(self, 'CPU Frequency', system)
super().__init__('CPU Frequency', system)
self.device_syspath = sysfs_path("devices/system/cpu")

def read_cpu(self, cpu):
Expand Down Expand Up @@ -617,7 +654,7 @@ def available(cls):
return os.path.exists(cls.irq_path)

def __init__(self, system):
Operation.__init__(self, 'IRQ affinity', system)
super().__init__('IRQ affinity', system)
self.irq_affinity_path = os.path.join(self.irq_path, "%s/smp_affinity")
self.default_affinity_path = os.path.join(self.irq_path, 'default_smp_affinity')

Expand Down Expand Up @@ -828,13 +865,10 @@ def write(self, tune):
self.write_irqs(cpus)


class CheckNOHZFullIntelPstate(Operation):
@staticmethod
def available():
return use_intel_pstate()
class CheckNOHZFullIntelPstate(IntelPstateOperation):

def __init__(self, system):
Operation.__init__(self, 'Check nohz_full', system)
super().__init__('Check nohz_full', system)

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

def __init__(self, system):
Operation.__init__(self, 'Power supply', system)
super().__init__('Power supply', system)

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

def __init__(self, system):
Operation.__init__(self, 'Perf event', system)
super().__init__('Perf event', system)

def read_max_sample_rate(self):
line = self.read_first_line(self.path)
Expand Down Expand Up @@ -950,18 +984,24 @@ def write(self, tune):


OPERATIONS = [
# Generic operations
PerfEvent,
ASLR,
LinuxScheduler,
CPUFrequency,
IRQAffinity,
PowerSupply,

# Setting the CPU scaling governor resets no_turbo
# and so must be set before Turbo Boost
CPUGovernorIntelPstate,
CPUGovernor,

# Intel Pstate Operations
TurboBoostIntelPstate,
CheckNOHZFullIntelPstate,

# X86 Operations
TurboBoostMSR,
IRQAffinity,
PowerSupply,
]


Expand Down

0 comments on commit 2b9591d

Please sign in to comment.