diff mbox series

[2/2] genirq/proc: Refine percpu kstat_irqs access logic

Message ID 20240513120548.14046-3-ahuang12@lenovo.com (mailing list archive)
State New
Headers show
Series genirq/proc: Speed up show_interrupts() | expand

Commit Message

Adrian Huang May 13, 2024, 12:05 p.m. UTC
From: Adrian Huang <ahuang12@lenovo.com>

There is no need to accumulate all CPUs' kstat_irqs to determine whether
the corresponding irq should be printed. Instead, stop the iteration
once one of kstat_irqs is nonzero.

In addition, no need to check if kstat_irqs address is available
for each iteration when printing each CPU irq statistic.

Tested-by: Jiwei Sun <sunjw10@lenovo.com>
Signed-off-by: Adrian Huang <ahuang12@lenovo.com>
---
 kernel/irq/proc.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

Comments

Thomas Gleixner May 14, 2024, 11:04 p.m. UTC | #1
On Mon, May 13 2024 at 20:05, Adrian Huang wrote:
> @@ -461,7 +461,7 @@ int show_interrupts(struct seq_file *p, void *v)
>  {
>  	static int prec;
>  
> -	unsigned long flags, any_count = 0;
> +	unsigned long flags, print_irq = 1;

What's wrong with making print_irq boolean?

>  	int i = *(loff_t *) v, j;
>  	struct irqaction *action;
>  	struct irq_desc *desc;
> @@ -488,18 +488,28 @@ int show_interrupts(struct seq_file *p, void *v)
>  	if (!desc || irq_settings_is_hidden(desc))
>  		goto outsparse;
>  
> -	if (desc->kstat_irqs) {
> -		for_each_online_cpu(j)
> -			any_count |= data_race(*per_cpu_ptr(desc->kstat_irqs, j));
> +	if ((!desc->action || irq_desc_is_chained(desc)) && desc->kstat_irqs) {

The condition is wrong. Look how the old code evaluated any_count.

> +		print_irq = 0;
> +		for_each_online_cpu(j) {
> +			if (data_race(*per_cpu_ptr(desc->kstat_irqs, j))) {
> +				print_irq = 1;
> +				break;
> +			}
> +		}

Aside of that this code is just fundamentally wrong in several aspects:

  1) Interrupts which have no action are completely uninteresting as
     there is no real information attached, i.e. it shows that there
     were interrupts on some CPUs, but there is zero information from
     which device they originated.

     Especially with sparse interrupts enabled they are usually gone
     shortly after the last action was removed.

  2) Chained interrupts do not have a count at all as they completely
     evade the core kernel entry points.

So all of this can be avoided and the whole nonsense can be reduced to:

	if (!desc->action || irq_desc_is_chained(desc) || !desc->kstat_irqs)
        	goto outsparse;

which in turn allows to convert this:

> -	for_each_online_cpu(j)
> -		seq_printf(p, "%10u ", desc->kstat_irqs ?
> -					*per_cpu_ptr(desc->kstat_irqs, j) : 0);

into an unconditional:

	for_each_online_cpu(j)
		seq_printf(p, "%10u ", *per_cpu_ptr(desc->kstat_irqs, j));

Thanks,

        tglx
diff mbox series

Patch

diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 623b8136e9af..bfa341fac687 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -461,7 +461,7 @@  int show_interrupts(struct seq_file *p, void *v)
 {
 	static int prec;
 
-	unsigned long flags, any_count = 0;
+	unsigned long flags, print_irq = 1;
 	int i = *(loff_t *) v, j;
 	struct irqaction *action;
 	struct irq_desc *desc;
@@ -488,18 +488,28 @@  int show_interrupts(struct seq_file *p, void *v)
 	if (!desc || irq_settings_is_hidden(desc))
 		goto outsparse;
 
-	if (desc->kstat_irqs) {
-		for_each_online_cpu(j)
-			any_count |= data_race(*per_cpu_ptr(desc->kstat_irqs, j));
+	if ((!desc->action || irq_desc_is_chained(desc)) && desc->kstat_irqs) {
+		print_irq = 0;
+		for_each_online_cpu(j) {
+			if (data_race(*per_cpu_ptr(desc->kstat_irqs, j))) {
+				print_irq = 1;
+				break;
+			}
+		}
 	}
 
-	if ((!desc->action || irq_desc_is_chained(desc)) && !any_count)
+	if (!print_irq)
 		goto outsparse;
 
 	seq_printf(p, "%*d: ", prec, i);
-	for_each_online_cpu(j)
-		seq_printf(p, "%10u ", desc->kstat_irqs ?
-					*per_cpu_ptr(desc->kstat_irqs, j) : 0);
+
+	if (desc->kstat_irqs) {
+		for_each_online_cpu(j)
+			seq_printf(p, "%10u ", *per_cpu_ptr(desc->kstat_irqs, j));
+	} else {
+		for_each_online_cpu(j)
+			seq_printf(p, "%10u ", 0);
+	}
 
 	raw_spin_lock_irqsave(&desc->lock, flags);
 	if (desc->irq_data.chip) {