Migrate cpu module from avocado to autils#105
Migrate cpu module from avocado to autils#105harvey0100 wants to merge 1 commit intoavocado-framework:mainfrom
Conversation
harvey0100
commented
Apr 2, 2026
- Add autils/system/cpu.py (line-for-line from avocado)
- Add unit tests with architecture-specific cpuinfo fixtures
- Add metadata/system/cpu.yml
- Add cpu to docs under System section
There was a problem hiding this comment.
Code Review
This pull request introduces a new autils.system.cpu module for querying and managing CPU information across various architectures, including x86_64, powerpc, s390, and aarch64. It provides functions for architecture detection, vendor identification, online/offline status management, and NUMA topology. Feedback focuses on improving the robustness of parsing /proc/cpuinfo and /proc/<pid>/task/<tid>/stat files, as well as optimizing the collection of NUMA node CPU assignments.
| proc_cpuinfo = genio.read_file("/proc/cpuinfo") | ||
| for line in proc_cpuinfo.splitlines(): | ||
| if "revision" in line: | ||
| rev = line.split(" ")[3].strip() |
There was a problem hiding this comment.
The current implementation of get_revision uses a fixed index after splitting by a single space, which is highly fragile. In many /proc/cpuinfo implementations (especially on non-x86 architectures like POWER), the number of spaces between the key and the value can vary, leading to an empty string or an IndexError. It is safer to split by the colon character and then extract the first word of the value.
| rev = line.split(" ")[3].strip() | |
| rev = line.split(":", 1)[1].strip().split()[0] |
| with open(proc_stat_file) as proc_stat: # pylint: disable=W1514 | ||
| cpus.add(proc_stat.read().split(" ")[processor_id_index]) | ||
| except IOError: |
There was a problem hiding this comment.
Parsing /proc/<pid>/task/<tid>/stat by splitting with spaces and using a fixed negative index is unreliable. The process name (the second field in stat) is enclosed in parentheses and can contain spaces, which shifts the index of all subsequent fields. A more robust approach is to find the last closing parenthesis to correctly identify the end of the process name field before splitting the remaining fields.
with open(proc_stat_file) as proc_stat: # pylint: disable=W1514
data = proc_stat.read()
# The comm field (2nd) is in parens and can have spaces.
# Find the last ')' to safely split the fields following it.
fields = data[data.rfind(")") + 2 :].split()
# The 'processor' field is the 39th field in the file.
# Since we split after the 2nd field, the index is 39 - 3 = 36.
cpus.add(fields[36])
except (IOError, IndexError):| def _deprecated(newfunc, oldfuncname): | ||
| """Print a deprecation warning and return the new function. | ||
|
|
There was a problem hiding this comment.
The check if pinned_cpus is not None: is redundant because pinned_cpus is initialized as an empty list just before the loop. Furthermore, updating the numa_nodes_with_cpus dictionary inside the inner loop is inefficient; it should be updated once per NUMA node after all its CPUs have been collected.
pinned_cpus.append(cpu)
numa_nodes_with_cpus[node] = sorted(pinned_cpus)- Add autils/system/cpu.py (line-for-line from avocado) - Add unit tests with architecture-specific cpuinfo fixtures - Add metadata/system/cpu.yml - Add cpu to docs under System section Assisted-By: Cursor-Claude-4-Sonnet Signed-off-by: Harvey Lynden <hlynden@redhat.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #105 +/- ##
===========================
===========================
☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|