Skip to content
Snippets Groups Projects
Commit 3b0003b8 authored by Christoph Alt's avatar Christoph Alt
Browse files

Merge branch 'devel/frequency' into 'main'

Devel/frequency

See merge request !4
parents e1ba73b3 b9ae82e0
No related branches found
No related tags found
1 merge request!4Devel/frequency
Pipeline #51055 passed
#!/usr/bin/env python
import subprocess
import re
import logging
import argparse
logger = logging.getLogger(__file__)
# tuples with filepath and conversion_factor to Hz
FREQUENCY_FILES = [
("/sys/devices/system/cpu/cpu0/cpufreq/bios_limit", 1e3), # KHZ
("/sys/devices/system/cpu/cpu0/cpufreq/base_frequency", 1e3) # KHZ
]
# tuples with command, regex pattern and conversion_factor to Hz
FREQUENCY_COMMANDS = [
("likwid-powermeter -i", r"Base clock:\s*([+-]?\d+(?:\.\d+)?)", 1e6) # MHZ
]
def read_frequency_from_file(file_path: str) -> float:
"""
Read the frequency value from a file.
Args:
file_path: The path to the file.
Returns:
The frequency value as a float.
Raises:
FileNotFoundError: If the file does not exist.
ValueError: If the file contains an invalid number.
"""
try:
with open(file_path, "r") as file_handle:
return float(file_handle.read().strip())
except FileNotFoundError as e:
raise FileNotFoundError(f"File {file_path} not found") from e
except ValueError as e:
raise ValueError(f"Invalid number in file {file_path}") from e
def run_command(command: str) -> str:
"""
Runs a shell command and returns its output.
Args:
command: The shell command to run.
Returns:
The output of the command as a string.
Raises:
ValueError: If there is an error running the shell command.
"""
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True
)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
raise ValueError(f"Error running command '{command}':\n{e.stderr}") from e
def filter_output(pattern: str, output: str) -> str:
"""
Filters the output of a command using a regex pattern.
Args:
pattern: The regex pattern to search for.
output: The output of the command as a string.
Returns:
The first match for the regex pattern in the output.
Raises:
LookupError: If no match is found for the regex pattern.
"""
pattern = re.compile(pattern)
match = pattern.search(output)
if match:
return match.groups()[0]
else:
raise LookupError(f"No match found for pattern '{pattern}' in command output:\n{output}")
def run_command_and_grep_output(command: str, grep_pattern: str) -> str:
"""
Runs a shell command and greps the output for a regex pattern.
Args:
command: The shell command to run.
grep_pattern: The regex pattern to search for in the command output.
Returns:
The first match for the regex pattern in the command output.
Raises:
LookupError: If no match is found for the regex pattern.
ValueError: If there is an error running the shell command.
"""
try:
output = run_command(command)
return filter_output(grep_pattern, output)
except subprocess.CalledProcessError as e:
raise ValueError(f"Error running command '{command}':\n{e.stderr}") from e
def get_cpu_base_frequency(frequency_files=FREQUENCY_FILES, frequency_commands=FREQUENCY_COMMANDS) -> float:
"""
Searches for the base CPU frequency in a list of files and returns it in GHz.
Args:
frequency_files (list of tuples): A list with tuples of frequency file paths and conversion factors.
frequency_commands (list of tuples): A list with tuples of commands, regex patterns, and conversion factors.
Returns:
The base CPU frequency in Hz as a float.
Raises:
ValueError: If the base CPU frequency cannot be determined.
"""
for frequency_file, conversion_factor in frequency_files:
try:
frequency = read_frequency_from_file(frequency_file) * float(conversion_factor)
logger.info(f"Found CPU frequency in {frequency_file}: {frequency:.2f} Hz")
return frequency
except (FileNotFoundError, ValueError) as e:
logger.debug(f"Error reading CPU frequency from {frequency_file}: {e}")
for command, grep_pattern, conversion_factor in frequency_commands:
try:
frequency = float(run_command_and_grep_output(command, grep_pattern)) * float(conversion_factor)
logger.info(f"Found CPU frequency in {command} {grep_pattern}: {frequency:.2f} Hz")
return frequency
except (LookupError, ValueError) as e:
logger.debug(f"Error reading CPU frequency from {command} with {grep_pattern}: {e}")
raise ValueError("Unable to determine base CPU frequency")
def main():
parser = argparse.ArgumentParser(description="Get the base CPU clock frequency in GHz")
parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity")
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.DEBUG)
frequency = get_cpu_base_frequency() / 1e9
print(f"{frequency:.2f}")
if __name__ == "__main__":
main()
......@@ -10,6 +10,10 @@ setup(name="cb-util",
"cbutil.postprocessing",
"dashboards",
"plotting"]),
entry_points={
'console_scripts':
'get_frequency = cbutil.cpu_frequency:main'
},
install_requires=[
"python-dotenv",
"influxdb",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment