@@ -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