History

genirq/proc: Utilize irq_desc::tot_count to avoid evaluation

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.

Thomas Gleixner committed 6 months ago

Commit 01794641 parent 95c33a62 files · +13 −4Browse files

Unified · Split

2 files
  1. include/linux/irqdesc.h +3 −3
  2. kernel/irq/proc.c +10 −1
include/linux/irqdesc.h+3−3
@@ -52,8 +52,8 @@ struct irq_redirect { · 51 unmodified lines
5252 * @depth: disable-depth, for nested irq_disable() calls
5353 * @wake_depth: enable depth, for multiple irq_set_irq_wake() callers
5454 * @tot_count: stats field for non-percpu irqs
55− * @irq_count: stats field to detect stalled irqs
5655 * @last_unhandled: aging timer for unhandled count
56+ * @irq_count: stats field to detect stalled irqs
5757 * @irqs_unhandled: stats field for spurious unhandled interrupts
5858 * @threads_handled: stats field for deferred spurious detection of threaded handlers
5959 * @threads_handled_last: comparator field for deferred spurious detection of threaded handlers
@@ -87,9 +87,9 @@ struct irq_desc { · 27 unmodified lines
8787 unsigned int core_internal_state__do_not_mess_with_it;
8888 unsigned int depth; /* nested irq disables */
8989 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;
9291 unsigned long last_unhandled; /* Aging timer for unhandled count */
92+ unsigned int irq_count; /* For detecting broken IRQs */
9393 unsigned int irqs_unhandled;
9494 atomic_t threads_handled;
9595 int threads_handled_last;
kernel/irq/proc.c+10−1
@@ -523,7 +523,16 @@ int show_interrupts(struct seq_file *p, void *v) · 522 unmodified lines
523523 return 0;
524524
525525 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());
527536 seq_putc(p, ' ');
528537
529538 guard(raw_spinlock_irq)(&desc->lock);