Interrupts which are not marked per CPU increment not only the per CPU statistics, but also the accumulation counter irq_desc::tot_count. Change the counter to type unsigned long so it does not produce sporadic zeros due to wrap arounds on 64-bit machines and do a quick check for non per CPU interrupts. If the counter is zero, then simply emit a full set of zero strings. That spares the evaluation of the per CPU counters completely for interrupts with zero events.
Unified · Split
| @@ -52,8 +52,8 @@ struct irq_redirect { · 51 unmodified lines | ||
| 52 | 52 | * @depth: disable-depth, for nested irq_disable() calls |
| 53 | 53 | * @wake_depth: enable depth, for multiple irq_set_irq_wake() callers |
| 54 | 54 | * @tot_count: stats field for non-percpu irqs |
| 55 | − * @irq_count: stats field to detect stalled irqs | |
| 56 | 55 | * @last_unhandled: aging timer for unhandled count |
| 56 | + * @irq_count: stats field to detect stalled irqs | |
| 57 | 57 | * @irqs_unhandled: stats field for spurious unhandled interrupts |
| 58 | 58 | * @threads_handled: stats field for deferred spurious detection of threaded handlers |
| 59 | 59 | * @threads_handled_last: comparator field for deferred spurious detection of threaded handlers |
| @@ -87,9 +87,9 @@ struct irq_desc { · 27 unmodified lines | ||
| 87 | 87 | unsigned int core_internal_state__do_not_mess_with_it; |
| 88 | 88 | unsigned int depth; /* nested irq disables */ |
| 89 | 89 | unsigned int wake_depth; /* nested wake enables */ |
| 90 | − unsigned int tot_count; | |
| 91 | − unsigned int irq_count; /* For detecting broken IRQs */ | |
| 90 | + unsigned long tot_count; | |
| 92 | 91 | unsigned long last_unhandled; /* Aging timer for unhandled count */ |
| 92 | + unsigned int irq_count; /* For detecting broken IRQs */ | |
| 93 | 93 | unsigned int irqs_unhandled; |
| 94 | 94 | atomic_t threads_handled; |
| 95 | 95 | int threads_handled_last; |
| @@ -523,7 +523,16 @@ int show_interrupts(struct seq_file *p, void *v) · 522 unmodified lines | ||
| 523 | 523 | return 0; |
| 524 | 524 | |
| 525 | 525 | seq_printf(p, "%*d:", prec, i); |
| 526 | − irq_proc_emit_counts(p, &desc->kstat_irqs->cnt); | |
| 526 | + | |
| 527 | + /* | |
| 528 | + * Always output per CPU interrupts. Output device interrupts only when | |
| 529 | + * desc::tot_count is not zero. | |
| 530 | + */ | |
| 531 | + if (irq_settings_is_per_cpu(desc) || irq_settings_is_per_cpu_devid(desc) || | |
| 532 | + data_race(desc->tot_count)) | |
| 533 | + irq_proc_emit_counts(p, &desc->kstat_irqs->cnt); | |
| 534 | + else | |
| 535 | + irq_proc_emit_zero_counts(p, num_online_cpus()); | |
| 527 | 536 | seq_putc(p, ' '); |
| 528 | 537 | |
| 529 | 538 | guard(raw_spinlock_irq)(&desc->lock); |