Skip to content

Commit

Permalink
cpu/em_cpufreq: fix and refactor cpufreq test
Browse files Browse the repository at this point in the history
- Ensure validation of cpufreq setting in `cpuinfo_cur_freq`.
- Validate cpufreq with absolute difference to ensure and detect both
  positive and negative discrepancies.
- Add a configuration file to make a few attributes configurable.

Signed-off-by: Aboorva Devarajan <[email protected]>
  • Loading branch information
AboorvaDevarajan committed Jan 10, 2024
1 parent d9692a7 commit 0ad7a9f
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 61 deletions.
159 changes: 98 additions & 61 deletions cpu/em_cpufreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,103 +13,140 @@
#
# Copyright: 2017 IBM
# Author: Shriya Kulkarni <[email protected]>

import random
import platform
from avocado import Test
from avocado import skipIf
from avocado.utils import process, distro, cpu
from avocado.utils.software_manager.manager import SoftwareManager

# Check if the platform is PowerNV
IS_POWER_NV = 'PowerNV' in open('/proc/cpuinfo', 'r').read()


class Cpufreq(Test):
"""
Test to validate the frequency transition.
Test to validate the frequency transition on PowerNV.
:avocado: tags=cpu,power
"""

# Skip this test if the platform is not PowerNV
@skipIf(not IS_POWER_NV, "This test is not supported on PowerVM platform")
def setUp(self):
smm = SoftwareManager()
self.detected_distro = distro.detect()
self.distro_name = self.detected_distro.name
self.distro_ver = self.detected_distro.version
self.distro_rel = self.detected_distro.release
# Get the configured attributes
self.num_loop = int(self.params.get('test_loop', default=10))
self.cpufreq_diff_threshold = int(
self.params.get('cpufreq_diff_threshold', default=10000))
self.cpu = 0
if 'Ubuntu' in self.distro_name:
deps = ['linux-tools-common', 'linux-tools-%s'
% platform.uname()[2]]
deps = [
'linux-tools-common',
'linux-tools-%s' % platform.uname()[2]
]
else:
deps = ['kernel-tools']
for package in deps:
if not smm.check_installed(package) and not smm.install(package):
self.cancel('%s is needed for the test to be run' % package)
self.log.info('Checking if %s is installed' % package)

# Pick a random CPU from the list of online CPUs
def get_random_cpu(self):
self.log.info('Getting a random CPU')
return random.choice(cpu.cpu_online_list())

# Get the CPU frequency attribute
def get_cpufreq_attribute(self, file):
self.log.info('Getting CPU frequency path for file %s' % file)
f_name = "/sys/devices/system/cpu/cpu%s/cpufreq/%s" % (self.cpu, file)
return open(f_name, 'r').readline().strip('\n').strip(' ')

# Get the ppc64 CPU frequency
def get_ppc64_cpu_frequency(self, new_format):
self.log.info('Getting ppc64 CPU frequency')
if new_format:
freq_read = process.system_output(
"ppc64_cpu --frequency -t 5 | grep 'avg' | awk '{print $3}'",
shell=True)
else:
freq_read = process.system_output(
"ppc64_cpu --frequency -t 5 | grep 'avg:' | awk '{print $2}'",
shell=True)

return float(freq_read) * (10**6)

# Get a random frequency
def get_random_freq(self):
self.log.info('Getting a random frequency')
cmd = "scaling_available_frequencies"
return random.choice(self.get_cpufreq_attribute(cmd).split(' '))

# Check if the distro uses the new format
def check_new_format(self):
new_format = False
if self.distro_name == "rhel":
if (self.distro_ver == "9" and self.distro_rel > "1") or \
(self.distro_ver == "8" and self.distro_rel > "7"):
new_format = True
elif self.distro_name == "SuSE":
if self.distro_ver == "15" and self.distro_rel > "4":
new_format = True
return new_format

# Compare two frequencies and check if they are within the threshold
def compare_frequencies(self, loop, freq1, freq2):
diff = float(freq1) - float(freq2)
if abs(diff) > self.cpufreq_diff_threshold:
self.fail("Frequency set and frequency read differs : %s %s" %
(freq2, freq1))
else:
self.log.info(
"Frequency set and frequency read are within the threshold : %s %s"
% (freq1, freq2))
self.log.info("Difference between the two frequencies is %s" %
diff)
self.log.info("Test %s passed" % loop)

# Set the CPU frequency
def set_cpu_frequency(self, rand_freq):
self.log.info("cpupower frequency-set -f %s" % rand_freq)
process.run("cpupower frequency-set -f %s" % rand_freq)

# Perform the test
def test(self):
"""
Set the governor to userspace
choose random frequency and cpu
validate the frequency is set using ppc64_cpu tool.
This method performs a series of tests on the CPU frequency settings.
It sets the CPU governor to 'userspace' and verifies if the governor is set
successfully. Then, it performs a number of iterations, each time setting a
random CPU frequency and comparing it with the actual frequency.
"""
self.cpu = 0
threshold = 10000
self.log.info('Starting the test')
output = process.run("cpupower frequency-set -g userspace", shell=True)
cur_governor = self.cpu_freq_path('scaling_governor')
cur_governor = self.get_cpufreq_attribute('scaling_governor')

if 'userspace' == cur_governor and output.exit_status == 0:
self.log.info("%s governor set successfully" % cur_governor)
else:
self.cancel("Unable to set the userspace governor")
for var in range(1, 10):
self.cpu = self.__get_random_cpu()
self.log.info(" cpu is %s" % self.cpu)
self.log.info("---------------Iteration %s-----------------" % var)
process.run("cpupower frequency-set -f %s"
% self.get_random_freq())
freq_set = self.cpu_freq_path("cpuinfo_cur_freq")
new_format = False
if self.distro_name == "rhel":
if (self.distro_ver == "9" and self.distro_rel > "1") or \
(self.distro_ver == "8" and self.distro_rel > "7"):
new_format = True
if self.distro_name == "SuSE":
if self.distro_ver == "15" and self.distro_rel > "4":
new_format = True
if new_format:
freq_read = process.system_output("ppc64_cpu --frequency -t 5"
"| grep 'avg' | awk "
"'{print $3}'", shell=True)
else:
freq_read = process.system_output("ppc64_cpu --frequency -t 5"
"| grep 'avg:' | awk "
"'{print $2}'", shell=True)
freq_read = float(freq_read) * (10 ** 6)
diff = float(freq_read) - float(freq_set)
self.log.info(" Difference is %s" % diff)
if diff > threshold:
self.log.info("Frequency set and frequency read differs :"
"%s %s " % (freq_set, freq_read))
else:
self.log.info("Works as expected for iteration %s " % var)

def get_random_freq(self):
"""
Get random frequency from list
"""
cmd = "scaling_available_frequencies"
return random.choice(self.cpu_freq_path(cmd).split(' '))

@staticmethod
def __get_random_cpu():
"""
Get random online cpu
"""
return random.choice(cpu.cpu_online_list())
for loop in range(self.num_loop):
self.cpu = self.get_random_cpu()
self.log.info("---------------CPU %s-----------------" % self.cpu)
self.log.info("---------------Iteration %s-----------------" %
loop)
rand_freq = self.get_random_freq()
self.set_cpu_frequency(rand_freq)
freq_set = self.get_cpufreq_attribute("cpuinfo_cur_freq")
self.compare_frequencies(loop, rand_freq, freq_set)

def cpu_freq_path(self, file):
"""
get cpu_freq values
:param: file: is filename which data needs to be fetched
:param: cpu_num is value for cpu
"""
f_name = "/sys/devices/system/cpu/cpu%s/cpufreq/%s" % (self.cpu, file)
return open(f_name, 'r').readline().strip('\n').strip(' ')
new_format = self.check_new_format()
freq_read = self.get_ppc64_cpu_frequency(new_format)
self.compare_frequencies(loop, freq_set, freq_read)
2 changes: 2 additions & 0 deletions cpu/em_cpufreq.py.data/em_cpufreq.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test_loop : 10
cpufreq_diff_threshold : 10000

0 comments on commit 0ad7a9f

Please sign in to comment.