Skip to content

Commit b5b01cd

Browse files
committed
Merge _get_irq_numbers and _get_interrupt_counts functions into one
1 parent 6999e58 commit b5b01cd

File tree

1 file changed

+40
-97
lines changed

1 file changed

+40
-97
lines changed

contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/interrupts_button_test.py

Lines changed: 40 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def __init__(self, irq_name: str):
3434
self.irq_numbers = {}
3535
self.num_cpus = os.cpu_count()
3636

37-
def _get_irq_numbers(self) -> bool:
37+
def _get_irq_numbers_counts(self) -> bool:
3838
"""
3939
Finds all IRQ numbers for the given device name.
4040
@@ -47,21 +47,30 @@ def _get_irq_numbers(self) -> bool:
4747
PROC_INTERRUPTS,
4848
)
4949
"""
50-
The self.irq_numbers will be store the mapping of IRQs for target
51-
interrupt name as a dict and assigned IRQ number as key only.
52-
self.irq_numbers = { IRQ_number1: None,
53-
IRQ_number2: None }
50+
Following logic will mapping self.irq_numbers with initial_counts_map
51+
initial_counts_map is a mapping of IRQ and the interrupt count of
52+
all CPUs
53+
initial_counts_map = { 132: [0, 0, 0, 0],
54+
144: [2, 0, 4, 0] }
5455
"""
5556
try:
5657
with open(PROC_INTERRUPTS, "r") as f:
5758
for line in f:
5859
if self.irq_name in line:
5960
parts = line.split()
61+
# looking for irq_number for matching irq_name
6062
irq_str = parts[0].strip().replace(":", "")
63+
# Get max CPU index. The index start from 0.
64+
max_idx = self.num_cpus + 1
65+
# Get interrupts count for each CPU.
66+
counts = [
67+
int(p) for p in parts[1:max_idx] if p.isdigit()
68+
]
6169
if irq_str.isdigit():
6270
# Append every found IRQ number
63-
self.irq_numbers[(int(irq_str))] = None
64-
71+
self.irq_numbers[(int(irq_str))] = counts
72+
if not self._get_smp_affinities():
73+
raise RuntimeError("Could not get CPU affinities for IRQs.")
6574
except FileNotFoundError:
6675
logging.error("Proc file not found at %s.", PROC_INTERRUPTS)
6776
return False
@@ -101,84 +110,39 @@ def _get_smp_affinities(self) -> bool:
101110
102111
Refer to https://docs.kernel.org/core-api/irq/irq-affinity.html
103112
for more detail.
104-
113+
affected_cpus will be a list include the affected cpu core for
114+
the irq.
105115
"""
106116
affinity_mask = int(affinity_hex, 16)
107-
affected_cpus = [
117+
affected_cpus = {
108118
cpu
109119
for cpu in range(self.num_cpus)
110120
if (affinity_mask >> cpu) & 1
111-
]
112-
"""
113-
self.irq_numbers will be updated by assigning a list of
114-
affinity CPUs as the value for each IRQ accordingly.
115-
self.irq_numbers = { IRQ_number1: [0, 1],
116-
IRQ_number2: [3, 4] }
117-
"""
121+
}
118122
if not affected_cpus:
119123
logging.warning(
120124
"IRQ %d affinity mask '%s' targets no CPUs. "
121125
"Defaulting to all CPUs for this IRQ.",
122126
irq,
123127
affinity_hex,
124128
)
125-
self.irq_numbers[irq] = list(range(self.num_cpus))
126129
else:
127-
self.irq_numbers[irq] = affected_cpus
130+
"""
131+
We remove the CPU that are not affected by IRQ to
132+
make the list of CPU counts simpler.
133+
"""
134+
self.irq_numbers[irq] = [
135+
value for i, value in enumerate(
136+
self.irq_numbers[irq]) if i in affected_cpus]
128137

129138
logging.info(
130139
"IRQ %d is tuned to run on CPU(s): %s",
131140
irq,
132141
self.irq_numbers[irq],
133142
)
134143
except Exception as e:
135-
logging.error(
136-
"Error reading smp_affinity for IRQ %d: %s", irq, e
137-
)
138-
return False
139-
return True
140-
141-
def _get_interrupt_counts(self, irq_number: int) -> Optional[List[int]]:
142-
"""
143-
Gets current interrupt counts for a specific IRQ across all CPUs.
144-
145-
Args:
146-
irq_number: The IRQ number to look for.
147-
148-
Returns:
149-
A list of integer counts, or None on error.
150-
"""
151-
try:
152-
"""
153-
counts will be a list of the numbers that from the output
154-
of /proc/interrupts. It will parse the line start with
155-
specific IRQ number and get the mulitple columes value
156-
which is depend on how many CPU cores for system.
157-
e.g. The output for /proc/interrupts as follows.
158-
count for IRQ number 1 will be count = [0, 0]
159-
160-
CPU0 CPU1
161-
1: 0 0 GICv3 25 Level vgic
162-
3: 4341111 1892740 GICv3 30 Level arch_timer
163-
"""
164-
with open(PROC_INTERRUPTS, "r") as f:
165-
for line in f:
166-
# Match the line starting with the exact IRQ number
167-
if line.strip().startswith("{}:".format(irq_number)):
168-
parts = line.split()
169-
# Get counts only for the number of available CPUs
170-
max_idx = self.num_cpus + 1
171-
counts = [
172-
int(p) for p in parts[1:max_idx] if p.isdigit()
173-
]
174-
return counts
175-
except Exception as e:
176-
logging.error(
177-
"Error reading interrupt counts for IRQ %d: %s",
178-
irq_number,
179-
e,
180-
)
181-
return None
144+
raise SystemError(
145+
"Error reading smp_affinity for IRQ %d: %s", irq, e)
182146

183147
def run_test(self) -> bool:
184148
"""
@@ -188,45 +152,26 @@ def run_test(self) -> bool:
188152
Returns:
189153
True if an interrupt was detected, False otherwise.
190154
"""
191-
if not self._get_irq_numbers():
192-
raise RuntimeError(
193-
"Could not find IRQs for '{}'.".format(self.irq_name)
194-
)
195-
196-
if not self._get_smp_affinities():
197-
raise RuntimeError("Could not get CPU affinities for all IRQs.")
198155

199156
"""
200157
Store initial counts for all monitored IRQs
201-
initial_counts_map = { IRQ_number1: [cpu0_count, cpu1_count, ...],
202-
IRQ_number1: [cpu0_count, cpu1_count, ...] }
158+
initial_counts = { IRQ_number1: [cpu0_count, cpu1_count, ...],
159+
IRQ_number2: [cpu0_count, cpu1_count, ...] }
203160
"""
204-
initial_counts_map = {}
205-
for irq in self.irq_numbers:
206-
counts = self._get_interrupt_counts(irq)
207-
if counts is None:
208-
logging.error("Failed to get initial counts for IRQ %d.", irq)
209-
return False # Or raise an error
210-
initial_counts_map[irq] = counts
211-
161+
initial_counts = self._get_irq_numbers_counts()
162+
if not initial_counts:
163+
raise RuntimeError(
164+
"Could not find IRQs for '{}'.".format(self.irq_name)
165+
)
212166
logging.info("Initial interrupt counts on target CPUs:")
213-
"""
214-
Following logic will mapping self.irq_numbers with initial_counts_map
215-
self.irq_numbers is a mapping of IRQ and affinity of CPUs.
216-
self.irq_numbers = { 132: [2,3],
217-
144: [0,1] }
218-
initial_counts_map is a mapping of IRQ and the interrupt count of
219-
all CPUs
220-
initial_counts_map = { 132: [0, 0, 0, 0],
221-
144: [2, 0, 4, 0] }
222-
"""
223-
for irq, cpus in self.irq_numbers.items():
167+
168+
for irq, cpus in initial_counts.items():
224169
for cpu in cpus:
225170
logging.info(
226171
"IRQ %d, CPU %d: %d",
227172
irq,
228173
cpu,
229-
initial_counts_map[irq][cpu],
174+
initial_counts[irq][cpu],
230175
)
231176

232177
logging.info(
@@ -236,11 +181,9 @@ def run_test(self) -> bool:
236181
for _ in range(TEST_TIMEOUT):
237182
# Check each IRQ for an increase in counts
238183
for irq_num, target_cpus in self.irq_numbers.items():
239-
current_counts = self._get_interrupt_counts(irq_num)
184+
current_counts = self._get_irq_numbers_counts()
240185
if not current_counts:
241186
continue # Skip if we failed to read counts
242-
243-
initial_counts = initial_counts_map[irq_num]
244187
for cpu in target_cpus:
245188
if current_counts[cpu] > initial_counts[cpu]:
246189
logging.info(

0 commit comments

Comments
 (0)