Re: [PATCH] genirq: reduce irqdebug bouncing cachelines
On 4/13/21 10:24 PM, Thomas Gleixner wrote: > On Tue, Apr 13 2021 at 14:16, Cédric Le Goater wrote: We could test irq_settings_no_debug() directly under handle_nested_irq() and handle_irq_event_percpu() to avoid calling note_interrupt(), just like we do for noirqdebug. >>> >>> We can do that, but then we should not just make it: >>> >>>if (!irqnodebug && !irq_settings_no_debug(desc)) >>> note_interrupt(...); >>> >>> Instead have only one condition: >>> >>>if (!irq_settings_no_debug(desc)) >>> note_interrupt(...); >>> >>> See the uncompiled delta patch below. >> >> I merged this second part with the first and gave IRQF_NO_DEBUG a try >> on P8 and P9 systems and all looked fine. I should send both patches >> after IRQF_NO_AUTOEN is merged in mainline. > > Does having that NODEBUG flag set on the IPI irqs make a measurable > difference or is it just too small to matter? It does not add much benefits on the 2s and 4s systems but I will give it a try on bigger ones when I can grab them. Then we can decide if it is worth merging. Thanks, C.
Re: [PATCH] genirq: reduce irqdebug bouncing cachelines
On Tue, Apr 13 2021 at 14:16, Cédric Le Goater wrote: >>> We could test irq_settings_no_debug() directly under handle_nested_irq() >>> and handle_irq_event_percpu() to avoid calling note_interrupt(), just >>> like we do for noirqdebug. >> >> We can do that, but then we should not just make it: >> >>if (!irqnodebug && !irq_settings_no_debug(desc)) >> note_interrupt(...); >> >> Instead have only one condition: >> >>if (!irq_settings_no_debug(desc)) >> note_interrupt(...); >> >> See the uncompiled delta patch below. > > I merged this second part with the first and gave IRQF_NO_DEBUG a try > on P8 and P9 systems and all looked fine. I should send both patches > after IRQF_NO_AUTOEN is merged in mainline. Does having that NODEBUG flag set on the IPI irqs make a measurable difference or is it just too small to matter? Thanks, tglx
Re: [PATCH] genirq: reduce irqdebug bouncing cachelines
Thomas, >> We could test irq_settings_no_debug() directly under handle_nested_irq() >> and handle_irq_event_percpu() to avoid calling note_interrupt(), just >> like we do for noirqdebug. > > We can do that, but then we should not just make it: > >if (!irqnodebug && !irq_settings_no_debug(desc)) > note_interrupt(...); > > Instead have only one condition: > >if (!irq_settings_no_debug(desc)) > note_interrupt(...); > > See the uncompiled delta patch below. I merged this second part with the first and gave IRQF_NO_DEBUG a try on P8 and P9 systems and all looked fine. I should send both patches after IRQF_NO_AUTOEN is merged in mainline. Thanks, C.
Re: [PATCH] genirq: reduce irqdebug bouncing cachelines
Cédric, On Mon, Apr 12 2021 at 11:06, Cédric Le Goater wrote: > On 4/10/21 1:58 PM, Thomas Gleixner wrote: >> --- a/kernel/irq/spurious.c >> +++ b/kernel/irq/spurious.c >> @@ -274,7 +274,7 @@ void note_interrupt(struct irq_desc *des >> unsigned int irq; >> >> if (desc->istate & IRQS_POLL_INPROGRESS || >> -irq_settings_is_polled(desc)) >> +irq_settings_is_polled(desc) | irq_settings_no_debug(desc)) > > Shouldn't it be '||' instead ? It could. But that's intentionally '|'. Why? Because that lets the compiler merge the bit checks into one and therefore spares one conditional branch. >> return; >> >> if (bad_action_ret(action_ret)) { >> > > We could test irq_settings_no_debug() directly under handle_nested_irq() > and handle_irq_event_percpu() to avoid calling note_interrupt(), just > like we do for noirqdebug. We can do that, but then we should not just make it: if (!irqnodebug && !irq_settings_no_debug(desc)) note_interrupt(...); Instead have only one condition: if (!irq_settings_no_debug(desc)) note_interrupt(...); See the uncompiled delta patch below. Thanks, tglx --- --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1690,6 +1690,9 @@ static int irq_settings_set_no_debug(desc); } + if (noirqdebug) + irq_settings_set_no_debug(desc); + if (new->flags & IRQF_ONESHOT) desc->istate |= IRQS_ONESHOT; --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -274,7 +274,7 @@ void note_interrupt(struct irq_desc *des unsigned int irq; if (desc->istate & IRQS_POLL_INPROGRESS || - irq_settings_is_polled(desc) | irq_settings_no_debug(desc)) + irq_settings_is_polled(desc)) return; if (bad_action_ret(action_ret)) { --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -481,7 +481,7 @@ void handle_nested_irq(unsigned int irq) for_each_action_of_desc(desc, action) action_ret |= action->thread_fn(action->irq, action->dev_id); - if (!noirqdebug) + if (!irq_settings_no_debug(desc)) note_interrupt(desc, action_ret); raw_spin_lock_irq(>lock); --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -197,7 +197,7 @@ irqreturn_t handle_irq_event_percpu(stru add_interrupt_randomness(desc->irq_data.irq, flags); - if (!noirqdebug) + if (!irq_settings_no_debug(desc)) note_interrupt(desc, retval); return retval; }
Re: [PATCH] genirq: reduce irqdebug bouncing cachelines
Hello, On 4/10/21 1:58 PM, Thomas Gleixner wrote: > Nicholas, > > On Fri, Apr 02 2021 at 23:20, Nicholas Piggin wrote: >> note_interrupt increments desc->irq_count for each interrupt even for >> percpu interrupt handlers, even when they are handled successfully. This >> causes cacheline bouncing and limits scalability. >> >> Instead of incrementing irq_count every time, only start incrementing it >> after seeing an unhandled irq, which should avoid the cache line >> bouncing in the common path. >> >> This actually should give better consistency in handling misbehaving >> irqs too, because instead of the first unhandled irq arriving at an >> arbitrary point in the irq_count cycle, its arrival will begin the >> irq_count cycle. > > I've applied that because it makes sense in general, but I think the whole > call to note_interrupt() can be avoided or return early when interrupts > would be marked accordingly. For IPI handlers which always return > HANDLED the whole procedure is pretty pointless to begin with. > > Something like the completely untested below. > > Thanks, > > tglx > --- > include/linux/interrupt.h |3 +++ > include/linux/irq.h |2 ++ > kernel/irq/manage.c |2 ++ > kernel/irq/settings.h | 12 > kernel/irq/spurious.c |2 +- > 5 files changed, 20 insertions(+), 1 deletion(-) > > --- a/include/linux/interrupt.h > +++ b/include/linux/interrupt.h > @@ -64,6 +64,8 @@ > * IRQF_NO_AUTOEN - Don't enable IRQ or NMI automatically when users request > it. > *Users will enable it explicitly by enable_irq() or > enable_nmi() > *later. > + * IRQF_NO_DEBUG - Exclude from runnaway detection for IPI and similar > handlers, > + * depends on IRQF_PERCPU. > */ > #define IRQF_SHARED 0x0080 > #define IRQF_PROBE_SHARED0x0100 > @@ -78,6 +80,7 @@ > #define IRQF_EARLY_RESUME0x0002 > #define IRQF_COND_SUSPEND0x0004 > #define IRQF_NO_AUTOEN 0x0008 > +#define IRQF_NO_DEBUG0x0010 > > #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | > IRQF_NO_THREAD) > > --- a/include/linux/irq.h > +++ b/include/linux/irq.h > @@ -72,6 +72,7 @@ enum irqchip_irq_state; > * mechanism and from core side polling. > * IRQ_DISABLE_UNLAZY- Disable lazy irq disable > * IRQ_HIDDEN- Don't show up in /proc/interrupts > + * IRQ_NO_DEBUG - Exclude from note_interrupt() > debugging > */ > enum { > IRQ_TYPE_NONE = 0x, > @@ -99,6 +100,7 @@ enum { > IRQ_IS_POLLED = (1 << 18), > IRQ_DISABLE_UNLAZY = (1 << 19), > IRQ_HIDDEN = (1 << 20), > + IRQ_NO_DEBUG= (1 << 21), > }; > > #define IRQF_MODIFY_MASK \ > --- a/kernel/irq/manage.c > +++ b/kernel/irq/manage.c > @@ -1682,6 +1682,8 @@ static int > if (new->flags & IRQF_PERCPU) { > irqd_set(>irq_data, IRQD_PER_CPU); > irq_settings_set_per_cpu(desc); > + if (new->flags & IRQF_NO_DEBUG) > + irq_settings_set_no_debug(desc); > } > > if (new->flags & IRQF_ONESHOT) > --- a/kernel/irq/settings.h > +++ b/kernel/irq/settings.h > @@ -18,6 +18,7 @@ enum { > _IRQ_IS_POLLED = IRQ_IS_POLLED, > _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, > _IRQ_HIDDEN = IRQ_HIDDEN, > + _IRQ_NO_DEBUG = IRQ_NO_DEBUG, > _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, > }; > > @@ -33,6 +34,7 @@ enum { > #define IRQ_IS_POLLEDGOT_YOU_MORON > #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON > #define IRQ_HIDDEN GOT_YOU_MORON > +#define IRQ_NO_DEBUG GOT_YOU_MORON > #undef IRQF_MODIFY_MASK > #define IRQF_MODIFY_MASK GOT_YOU_MORON > > @@ -174,3 +176,13 @@ static inline bool irq_settings_is_hidde > { > return desc->status_use_accessors & _IRQ_HIDDEN; > } > + > +static inline void irq_settings_set_no_debug(struct irq_desc *desc) > +{ > + desc->status_use_accessors |= _IRQ_NO_DEBUG; > +} > + > +static inline bool irq_settings_no_debug(struct irq_desc *desc) > +{ > + return desc->status_use_accessors & _IRQ_NO_DEBUG; > +} > --- a/kernel/irq/spurious.c > +++ b/kernel/irq/spurious.c > @@ -274,7 +274,7 @@ void note_interrupt(struct irq_desc *des > unsigned int irq; > > if (desc->istate & IRQS_POLL_INPROGRESS || > - irq_settings_is_polled(desc)) > + irq_settings_is_polled(desc) | irq_settings_no_debug(desc)) Shouldn't it be '||' instead ? > return; > > if (bad_action_ret(action_ret)) { > We could test irq_settings_no_debug() directly under handle_nested_irq() and handle_irq_event_percpu() to avoid calling note_interrupt(), just like we do for noirqdebug.
Re: [PATCH] genirq: reduce irqdebug bouncing cachelines
Nicholas, On Fri, Apr 02 2021 at 23:20, Nicholas Piggin wrote: > note_interrupt increments desc->irq_count for each interrupt even for > percpu interrupt handlers, even when they are handled successfully. This > causes cacheline bouncing and limits scalability. > > Instead of incrementing irq_count every time, only start incrementing it > after seeing an unhandled irq, which should avoid the cache line > bouncing in the common path. > > This actually should give better consistency in handling misbehaving > irqs too, because instead of the first unhandled irq arriving at an > arbitrary point in the irq_count cycle, its arrival will begin the > irq_count cycle. I've applied that because it makes sense in general, but I think the whole call to note_interrupt() can be avoided or return early when interrupts would be marked accordingly. For IPI handlers which always return HANDLED the whole procedure is pretty pointless to begin with. Something like the completely untested below. Thanks, tglx --- include/linux/interrupt.h |3 +++ include/linux/irq.h |2 ++ kernel/irq/manage.c |2 ++ kernel/irq/settings.h | 12 kernel/irq/spurious.c |2 +- 5 files changed, 20 insertions(+), 1 deletion(-) --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -64,6 +64,8 @@ * IRQF_NO_AUTOEN - Don't enable IRQ or NMI automatically when users request it. *Users will enable it explicitly by enable_irq() or enable_nmi() *later. + * IRQF_NO_DEBUG - Exclude from runnaway detection for IPI and similar handlers, + *depends on IRQF_PERCPU. */ #define IRQF_SHARED0x0080 #define IRQF_PROBE_SHARED 0x0100 @@ -78,6 +80,7 @@ #define IRQF_EARLY_RESUME 0x0002 #define IRQF_COND_SUSPEND 0x0004 #define IRQF_NO_AUTOEN 0x0008 +#define IRQF_NO_DEBUG 0x0010 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -72,6 +72,7 @@ enum irqchip_irq_state; * mechanism and from core side polling. * IRQ_DISABLE_UNLAZY - Disable lazy irq disable * IRQ_HIDDEN - Don't show up in /proc/interrupts + * IRQ_NO_DEBUG- Exclude from note_interrupt() debugging */ enum { IRQ_TYPE_NONE = 0x, @@ -99,6 +100,7 @@ enum { IRQ_IS_POLLED = (1 << 18), IRQ_DISABLE_UNLAZY = (1 << 19), IRQ_HIDDEN = (1 << 20), + IRQ_NO_DEBUG= (1 << 21), }; #define IRQF_MODIFY_MASK \ --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1682,6 +1682,8 @@ static int if (new->flags & IRQF_PERCPU) { irqd_set(>irq_data, IRQD_PER_CPU); irq_settings_set_per_cpu(desc); + if (new->flags & IRQF_NO_DEBUG) + irq_settings_set_no_debug(desc); } if (new->flags & IRQF_ONESHOT) --- a/kernel/irq/settings.h +++ b/kernel/irq/settings.h @@ -18,6 +18,7 @@ enum { _IRQ_IS_POLLED = IRQ_IS_POLLED, _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, _IRQ_HIDDEN = IRQ_HIDDEN, + _IRQ_NO_DEBUG = IRQ_NO_DEBUG, _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, }; @@ -33,6 +34,7 @@ enum { #define IRQ_IS_POLLED GOT_YOU_MORON #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON #define IRQ_HIDDEN GOT_YOU_MORON +#define IRQ_NO_DEBUG GOT_YOU_MORON #undef IRQF_MODIFY_MASK #define IRQF_MODIFY_MASK GOT_YOU_MORON @@ -174,3 +176,13 @@ static inline bool irq_settings_is_hidde { return desc->status_use_accessors & _IRQ_HIDDEN; } + +static inline void irq_settings_set_no_debug(struct irq_desc *desc) +{ + desc->status_use_accessors |= _IRQ_NO_DEBUG; +} + +static inline bool irq_settings_no_debug(struct irq_desc *desc) +{ + return desc->status_use_accessors & _IRQ_NO_DEBUG; +} --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -274,7 +274,7 @@ void note_interrupt(struct irq_desc *des unsigned int irq; if (desc->istate & IRQS_POLL_INPROGRESS || - irq_settings_is_polled(desc)) + irq_settings_is_polled(desc) | irq_settings_no_debug(desc)) return; if (bad_action_ret(action_ret)) {