* [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
@ 2008-07-29 23:32 Jeremy Fitzhardinge
2008-07-29 23:43 ` Jeremy Fitzhardinge
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Jeremy Fitzhardinge @ 2008-07-29 23:32 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
This adds 8 queues for smp_call_function(), in order to avoid a
bottleneck on a single global lock and list for function calls. When
initiating a function call, the sender chooses a queue based on its
own processor id (if there are more than 8 processors, they hash down
to 8 queues). It then sends an IPI to the corresponding vector for
that queue to each target CPU. The target CPUs use the vector number
to determine which queue they should scan for work.
This should give smp_call_function the same performance
characteristics as the original x86-64 cross-cpu tlb flush code, which
used the same scheme.
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
---
arch/x86/Kconfig | 4 ++++
arch/x86/kernel/apic_32.c | 11 ++++++++++-
arch/x86/kernel/entry_32.S | 25 ++++++++++++++-----------
arch/x86/kernel/entry_64.S | 19 ++++++++++++++++---
arch/x86/kernel/irqinit_64.c | 11 ++++++++++-
arch/x86/kernel/smp.c | 10 +++++++---
arch/x86/xen/smp.c | 27 ++++++++++++++++++++++++++-
include/asm-x86/hw_irq.h | 20 +++++++++-----------
include/asm-x86/irq_vectors.h | 6 ++++--
include/asm-x86/mach-default/entry_arch.h | 16 +++++++++++++++-
10 files changed, 115 insertions(+), 34 deletions(-)
===================================================================
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -178,6 +178,10 @@
depends on SMP && ((X86_32 && !X86_VOYAGER) || X86_64)
select USE_GENERIC_SMP_HELPERS
default y
+
+config GENERIC_SMP_QUEUES
+ int
+ default "8"
config X86_32_SMP
def_bool y
===================================================================
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -1382,7 +1382,16 @@
alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
/* IPI for generic function call */
- alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+ BUILD_BUG_ON(CONFIG_GENERIC_SMP_QUEUES !=
+ (CALL_FUNCTION_VECTOR_END - CALL_FUNCTION_VECTOR_START + 1));
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+0, call_function_interrupt0);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+1, call_function_interrupt1);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+2, call_function_interrupt2);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+3, call_function_interrupt3);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+4, call_function_interrupt4);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+5, call_function_interrupt5);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+6, call_function_interrupt6);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+7, call_function_interrupt7);
/* IPI for single call function */
set_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
===================================================================
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -688,19 +688,22 @@
ENDPROC(common_interrupt)
CFI_ENDPROC
-#define BUILD_INTERRUPT(name, nr) \
-ENTRY(name) \
- RING0_INT_FRAME; \
- pushl $~(nr); \
- CFI_ADJUST_CFA_OFFSET 4; \
- SAVE_ALL; \
- TRACE_IRQS_OFF \
- movl %esp,%eax; \
- call smp_##name; \
- jmp ret_from_intr; \
- CFI_ENDPROC; \
+#define __BUILD_INTERRUPT(name, func, nr) \
+ENTRY(name) \
+ RING0_INT_FRAME; \
+ pushl $~(nr); \
+ CFI_ADJUST_CFA_OFFSET 4; \
+ SAVE_ALL; \
+ TRACE_IRQS_OFF \
+ movl %esp,%eax; \
+ call func; \
+ jmp ret_from_intr; \
+ CFI_ENDPROC; \
ENDPROC(name)
+#define BUILD_INTERRUPT(name, nr) \
+ __BUILD_INTERRUPT(name, smp_##name, nr)
+
/* The include is where all of the SMP etc. interrupts come from */
#include "entry_arch.h"
===================================================================
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -869,9 +869,22 @@
apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
END(reschedule_interrupt)
-ENTRY(call_function_interrupt)
- apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
-END(call_function_interrupt)
+
+ .macro CALLFUNCTION_ENTRY num
+ENTRY(call_function_interrupt\num)
+ apicinterrupt CALL_FUNCTION_VECTOR_START+\num,smp_call_function_interrupt
+END(call_function_interrupt\num)
+ .endm
+
+ CALLFUNCTION_ENTRY 0
+ CALLFUNCTION_ENTRY 1
+ CALLFUNCTION_ENTRY 2
+ CALLFUNCTION_ENTRY 3
+ CALLFUNCTION_ENTRY 4
+ CALLFUNCTION_ENTRY 5
+ CALLFUNCTION_ENTRY 6
+ CALLFUNCTION_ENTRY 7
+
ENTRY(call_function_single_interrupt)
apicinterrupt CALL_FUNCTION_SINGLE_VECTOR,smp_call_function_single_interrupt
END(call_function_single_interrupt)
===================================================================
--- a/arch/x86/kernel/irqinit_64.c
+++ b/arch/x86/kernel/irqinit_64.c
@@ -188,7 +188,16 @@
alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
/* IPI for generic function call */
- alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+ BUILD_BUG_ON(CONFIG_GENERIC_SMP_QUEUES !=
+ (CALL_FUNCTION_VECTOR_END - CALL_FUNCTION_VECTOR_START + 1));
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+0, call_function_interrupt0);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+1, call_function_interrupt1);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+2, call_function_interrupt2);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+3, call_function_interrupt3);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+4, call_function_interrupt4);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+5, call_function_interrupt5);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+6, call_function_interrupt6);
+ alloc_intr_gate(CALL_FUNCTION_VECTOR_START+7, call_function_interrupt7);
/* IPI for generic single function call */
alloc_intr_gate(CALL_FUNCTION_SINGLE_VECTOR,
===================================================================
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -129,15 +129,16 @@
void native_send_call_func_ipi(cpumask_t mask)
{
cpumask_t allbutself;
+ unsigned queue = smp_processor_id() % CONFIG_GENERIC_SMP_QUEUES;
allbutself = cpu_online_map;
cpu_clear(smp_processor_id(), allbutself);
if (cpus_equal(mask, allbutself) &&
cpus_equal(cpu_online_map, cpu_callout_map))
- send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+ send_IPI_allbutself(CALL_FUNCTION_VECTOR_START + queue);
else
- send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
+ send_IPI_mask(mask, CALL_FUNCTION_VECTOR_START + queue);
}
static void stop_this_cpu(void *dummy)
@@ -187,9 +188,12 @@
void smp_call_function_interrupt(struct pt_regs *regs)
{
+ unsigned queue;
+
ack_APIC_irq();
irq_enter();
- generic_smp_call_function_interrupt(0);
+ queue = ~regs->orig_ax - CALL_FUNCTION_VECTOR_START;
+ generic_smp_call_function_interrupt(queue);
#ifdef CONFIG_X86_32
__get_cpu_var(irq_stat).irq_call_count++;
#else
===================================================================
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -41,6 +41,8 @@
static DEFINE_PER_CPU(int, callfunc_irq);
static DEFINE_PER_CPU(int, callfuncsingle_irq);
static DEFINE_PER_CPU(int, debug_irq) = -1;
+
+static DEFINE_PER_CPU(unsigned, callfunc_queue);
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
@@ -381,6 +383,21 @@
static void xen_smp_send_call_function_ipi(cpumask_t mask)
{
int cpu;
+ unsigned queue = smp_processor_id() % CONFIG_GENERIC_SMP_QUEUES;
+
+ /*
+ * We can't afford to allocate N callfunc vectors * M cpu
+ * interrupts, so we just need to fake it for now. We can fix
+ * this when we integrate event channels at the vector level.
+ * For now, we just leave a hint for the target cpus for which
+ * queue to start on, but they still need to search them all.
+ * (Which is not really much worse than having a single
+ * queue.)
+ */
+ for_each_cpu_mask_nr(cpu, mask)
+ per_cpu(callfunc_queue, cpu) = queue;
+
+ wmb(); /* set queues before sending interrupt */
xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
@@ -400,8 +417,16 @@
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
{
+ unsigned start_queue = __get_cpu_var(callfunc_queue);
+ unsigned queue;
+
irq_enter();
- generic_smp_call_function_interrupt(0);
+ queue = start_queue;
+ do {
+ generic_smp_call_function_interrupt(queue);
+ queue = (queue + 1) % CONFIG_GENERIC_SMP_QUEUES;
+ } while(queue != start_queue);
+
#ifdef CONFIG_X86_32
__get_cpu_var(irq_stat).irq_call_count++;
#else
===================================================================
--- a/include/asm-x86/hw_irq.h
+++ b/include/asm-x86/hw_irq.h
@@ -34,20 +34,18 @@
extern void thermal_interrupt(void);
extern void reschedule_interrupt(void);
-extern void invalidate_interrupt(void);
-extern void invalidate_interrupt0(void);
-extern void invalidate_interrupt1(void);
-extern void invalidate_interrupt2(void);
-extern void invalidate_interrupt3(void);
-extern void invalidate_interrupt4(void);
-extern void invalidate_interrupt5(void);
-extern void invalidate_interrupt6(void);
-extern void invalidate_interrupt7(void);
-
extern void irq_move_cleanup_interrupt(void);
extern void threshold_interrupt(void);
-extern void call_function_interrupt(void);
+extern void call_function_interrupt0(void);
+extern void call_function_interrupt1(void);
+extern void call_function_interrupt2(void);
+extern void call_function_interrupt3(void);
+extern void call_function_interrupt4(void);
+extern void call_function_interrupt5(void);
+extern void call_function_interrupt6(void);
+extern void call_function_interrupt7(void);
+
extern void call_function_single_interrupt(void);
/* PIC specific functions */
===================================================================
--- a/include/asm-x86/irq_vectors.h
+++ b/include/asm-x86/irq_vectors.h
@@ -62,8 +62,9 @@
# define SPURIOUS_APIC_VECTOR 0xff
# define ERROR_APIC_VECTOR 0xfe
# define RESCHEDULE_VECTOR 0xfc
-# define CALL_FUNCTION_VECTOR 0xfb
# define CALL_FUNCTION_SINGLE_VECTOR 0xfa
+# define CALL_FUNCTION_VECTOR_END 0xf8
+# define CALL_FUNCTION_VECTOR_START 0xf1 /* f1-f8 multiple callfunction queues */
# define THERMAL_APIC_VECTOR 0xf0
#else
@@ -71,10 +72,11 @@
#define SPURIOUS_APIC_VECTOR 0xff
#define ERROR_APIC_VECTOR 0xfe
#define RESCHEDULE_VECTOR 0xfd
-#define CALL_FUNCTION_VECTOR 0xfc
#define CALL_FUNCTION_SINGLE_VECTOR 0xfb
#define THERMAL_APIC_VECTOR 0xfa
#define THRESHOLD_APIC_VECTOR 0xf9
+#define CALL_FUNCTION_VECTOR_END 0xf7
+#define CALL_FUNCTION_VECTOR_START 0xf0 /* f0-f7 multiple callfunction queues */
#endif
===================================================================
--- a/include/asm-x86/mach-default/entry_arch.h
+++ b/include/asm-x86/mach-default/entry_arch.h
@@ -11,8 +11,22 @@
*/
#ifdef CONFIG_X86_SMP
BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
-BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
+
+#define BUILD_CALLFUNCTION(n) \
+ __BUILD_INTERRUPT(call_function_interrupt##n, \
+ smp_call_function_interrupt, \
+ CALL_FUNCTION_VECTOR_START + n)
+BUILD_CALLFUNCTION(0)
+BUILD_CALLFUNCTION(1)
+BUILD_CALLFUNCTION(2)
+BUILD_CALLFUNCTION(3)
+BUILD_CALLFUNCTION(4)
+BUILD_CALLFUNCTION(5)
+BUILD_CALLFUNCTION(6)
+BUILD_CALLFUNCTION(7)
+
+#undef BUILD_CALLFUNCTION
#endif
/*
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-29 23:32 [PATCH 2/2] x86: implement multiple queues for smp function call IPIs Jeremy Fitzhardinge
@ 2008-07-29 23:43 ` Jeremy Fitzhardinge
2008-07-30 0:13 ` Andi Kleen
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Jeremy Fitzhardinge @ 2008-07-29 23:43 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
Jeremy Fitzhardinge wrote:
> This adds 8 queues for smp_call_function(), in order to avoid a
> bottleneck on a single global lock and list for function calls. When
> initiating a function call, the sender chooses a queue based on its
> own processor id (if there are more than 8 processors, they hash down
> to 8 queues). It then sends an IPI to the corresponding vector for
> that queue to each target CPU. The target CPUs use the vector number
> to determine which queue they should scan for work.
I should point out that this patch depends on the earlier tlb.c
unification patch, since it recycles the IPI vectors that series freed up.
J
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-29 23:32 [PATCH 2/2] x86: implement multiple queues for smp function call IPIs Jeremy Fitzhardinge
2008-07-29 23:43 ` Jeremy Fitzhardinge
@ 2008-07-30 0:13 ` Andi Kleen
2008-07-30 0:44 ` Jeremy Fitzhardinge
2008-07-30 4:55 ` Nick Piggin
2008-07-31 22:08 ` Ingo Molnar
3 siblings, 1 reply; 12+ messages in thread
From: Andi Kleen @ 2008-07-30 0:13 UTC (permalink / raw)
To: Jeremy Fitzhardinge
Cc: Ingo Molnar, Nick Piggin, Andi Kleen, Linux Kernel Mailing List
On Tue, Jul 29, 2008 at 04:32:57PM -0700, Jeremy Fitzhardinge wrote:
> This adds 8 queues for smp_call_function(), in order to avoid a
Now that we have per CPU IDT and there's no global bottleneck anymore
I think it would be actually fine to use
more than 8 vectors. 32 or 64 might be a better default.
> void native_send_call_func_ipi(cpumask_t mask)
> {
> cpumask_t allbutself;
> + unsigned queue = smp_processor_id() % CONFIG_GENERIC_SMP_QUEUES;
Does this really always run with preemption disabled?
Did I miss it but where is the per vector lock?
-Andi
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-30 0:13 ` Andi Kleen
@ 2008-07-30 0:44 ` Jeremy Fitzhardinge
0 siblings, 0 replies; 12+ messages in thread
From: Jeremy Fitzhardinge @ 2008-07-30 0:44 UTC (permalink / raw)
To: Andi Kleen; +Cc: Ingo Molnar, Nick Piggin, Linux Kernel Mailing List
Andi Kleen wrote:
> On Tue, Jul 29, 2008 at 04:32:57PM -0700, Jeremy Fitzhardinge wrote:
>
>> This adds 8 queues for smp_call_function(), in order to avoid a
>>
>
> Now that we have per CPU IDT and there's no global bottleneck anymore
> I think it would be actually fine to use
> more than 8 vectors. 32 or 64 might be a better default.
>
Well, there's no point in having more vectors than CPUs, and a bit of
doubling up doesn't hurt too much. So I think 8 is a good default for
normal sized machines. But I can see that being able to add more
vectors for large machines might be helpful. I guess it really depends
on what the fan-out is for multicast messages.
I dunno, maybe it makes sense to take numa topology into account, on the
assumption that 1) most cross-cpu function calls will be tlb flushes now
(or at least, sending to mm->cpu_vm_mask), and 2) most tlb flushes will
be between cpus within one node.
>> void native_send_call_func_ipi(cpumask_t mask)
>> {
>> cpumask_t allbutself;
>> + unsigned queue = smp_processor_id() % CONFIG_GENERIC_SMP_QUEUES;
>>
>
> Does this really always run with preemption disabled?
Think so, but I'll check again. One of my TODO list items is to check
whether smp_call_function_mask should disable preemption for itself, or
at least WARN_ON if its called with preemption enabled.
J
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-29 23:32 [PATCH 2/2] x86: implement multiple queues for smp function call IPIs Jeremy Fitzhardinge
2008-07-29 23:43 ` Jeremy Fitzhardinge
2008-07-30 0:13 ` Andi Kleen
@ 2008-07-30 4:55 ` Nick Piggin
2008-07-31 22:08 ` Ingo Molnar
3 siblings, 0 replies; 12+ messages in thread
From: Nick Piggin @ 2008-07-30 4:55 UTC (permalink / raw)
To: Jeremy Fitzhardinge; +Cc: Ingo Molnar, Andi Kleen, Linux Kernel Mailing List
On Wednesday 30 July 2008 09:32, Jeremy Fitzhardinge wrote:
> This adds 8 queues for smp_call_function(), in order to avoid a
> bottleneck on a single global lock and list for function calls. When
> initiating a function call, the sender chooses a queue based on its
> own processor id (if there are more than 8 processors, they hash down
> to 8 queues). It then sends an IPI to the corresponding vector for
> that queue to each target CPU. The target CPUs use the vector number
> to determine which queue they should scan for work.
>
> This should give smp_call_function the same performance
> characteristics as the original x86-64 cross-cpu tlb flush code, which
> used the same scheme.
Yep, I'm much happier if you go this way to do it. This way hopefully
eventually we can extend the call function infrastructure to also
generalise the UV type payload-IPIs and fold all that in here too.
I don't _think_ there should any longer be any reason why it should
be slower than the special case code (at least nothing fundamental
that I can see).
Actually it should have a chance to be faster because we should be able
to queue up multiple tlb flushes into each global call queue, rather
than executing them strictly one at a time under the tlbstate lock like
we do now.
Anyway it looks like Andi is reviewing the fine details, so I'm happy
with this if he is :) Thanks!
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-29 23:32 [PATCH 2/2] x86: implement multiple queues for smp function call IPIs Jeremy Fitzhardinge
` (2 preceding siblings ...)
2008-07-30 4:55 ` Nick Piggin
@ 2008-07-31 22:08 ` Ingo Molnar
2008-07-31 22:12 ` Andi Kleen
2008-07-31 22:23 ` Jeremy Fitzhardinge
3 siblings, 2 replies; 12+ messages in thread
From: Ingo Molnar @ 2008-07-31 22:08 UTC (permalink / raw)
To: Jeremy Fitzhardinge; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
* Jeremy Fitzhardinge <jeremy@goop.org> wrote:
> This adds 8 queues for smp_call_function(), in order to avoid a
> bottleneck on a single global lock and list for function calls. When
> initiating a function call, the sender chooses a queue based on its
> own processor id (if there are more than 8 processors, they hash down
> to 8 queues). It then sends an IPI to the corresponding vector for
> that queue to each target CPU. The target CPUs use the vector number
> to determine which queue they should scan for work.
>
> This should give smp_call_function the same performance
> characteristics as the original x86-64 cross-cpu tlb flush code, which
> used the same scheme.
heh, nice :-)
Before going into all the fine details an trying our luck in tip/master
QA, i'm a bit worried about hw compatibility in general though. APICs
have been flaky since the beginnings of times. We had erratas in the
area of local timer IRQs(IPIs) overlapping with IPIs, etc. - so i'd not
bet the farm on all APICs being able to handle a _lot_ more overlapped
inter-CPU IPIs than we do currently. (which basically was just three of
them until now, and now four with the new SMP cross-call IPIs)
So this _has_ to be approached defensively. It _should_ work, and i'm
all in favor of utilizing hardware resources more fully, but it's an
entirely new mode of operation for the hardware. I think a Kconfig
option (which defaults to off), and a boot option to disable it would be
nice, so that we can introduce this gently, at least initially. Then
when we see that it's 100% trouble-free we can flip around the default.
Plus, would it be possible to shape this a bit more dynamically? I like
8 as a nice round number, but i bet some folks would like to have 16,
some would like to have 4 ... Perhaps even making it dynamic (so that we
can turn it all off in the case of trouble with certain CPU/APIC
versions).
Hm?
Ingo
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-31 22:08 ` Ingo Molnar
@ 2008-07-31 22:12 ` Andi Kleen
2008-07-31 22:23 ` Jeremy Fitzhardinge
1 sibling, 0 replies; 12+ messages in thread
From: Andi Kleen @ 2008-07-31 22:12 UTC (permalink / raw)
To: Ingo Molnar
Cc: Jeremy Fitzhardinge, Nick Piggin, Andi Kleen,
Linux Kernel Mailing List
> Before going into all the fine details an trying our luck in tip/master
> QA, i'm a bit worried about hw compatibility in general though. APICs
> have been flaky since the beginnings of times. We had erratas in the
> area of local timer IRQs(IPIs) overlapping with IPIs, etc. - so i'd not
> bet the farm on all APICs being able to handle a _lot_ more overlapped
> inter-CPU IPIs than we do currently. (which basically was just three of
> them until now, and now four with the new SMP cross-call IPIs)
At least on 64bit systems this configuration has been already tested
for years with the 8 vector TLB flush. I am not aware
of any problems caused by it. Using them on them should be fine.
So your cautious approach would only be potentially useful on older 32bit only
systems.
-Andi
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-31 22:08 ` Ingo Molnar
2008-07-31 22:12 ` Andi Kleen
@ 2008-07-31 22:23 ` Jeremy Fitzhardinge
2008-07-31 22:42 ` Ingo Molnar
1 sibling, 1 reply; 12+ messages in thread
From: Jeremy Fitzhardinge @ 2008-07-31 22:23 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
Ingo Molnar wrote:
>
> heh, nice :-)
>
> Before going into all the fine details an trying our luck in tip/master
> QA, i'm a bit worried about hw compatibility in general though. APICs
> have been flaky since the beginnings of times. We had erratas in the
> area of local timer IRQs(IPIs) overlapping with IPIs, etc. - so i'd not
> bet the farm on all APICs being able to handle a _lot_ more overlapped
> inter-CPU IPIs than we do currently. (which basically was just three of
> them until now, and now four with the new SMP cross-call IPIs)
>
> So this _has_ to be approached defensively. It _should_ work, and i'm
> all in favor of utilizing hardware resources more fully, but it's an
> entirely new mode of operation for the hardware. I think a Kconfig
> option (which defaults to off), and a boot option to disable it would be
> nice, so that we can introduce this gently, at least initially. Then
> when we see that it's 100% trouble-free we can flip around the default.
>
As Andi pointed out, this is more or less functionally identical to the
code I ripped out of tlb_64.c, so this mode of operation has had lots of
exposure on the 64-bit side. Because the number of queues is a CONFIG
variable, it would be relatively easy to make it a real config option,
and/or use different numbers for 32 and 64-bit. Choosing 1 as the
number of queues will make it behave exactly as the current code does.
I'm not really familiar with all the ins and outs of apic bugs. What's
the issue you're concerned about?
> Plus, would it be possible to shape this a bit more dynamically? I like
> 8 as a nice round number, but i bet some folks would like to have 16,
> some would like to have 4 ... Perhaps even making it dynamic (so that we
> can turn it all off in the case of trouble with certain CPU/APIC
> versions).
>
> Hm?
>
Sure, that's possible in a followup patch. There's a pile of repeated
boilerplate code which would need to be cleaned up to make it
configurable and/or runtime changable. Also, it would need some way to
allocate a contiguous block of vectors; I'm not sure if the just-posted
SGI patch allows that...
It also occurred to me that it might be more interesting to parameterise
the queues - and the mapping of cpus->queues - in a more topology-aware
way than simply NQUEUES=NCPUS/x, queue=cpuid % NQUEUES. But I haven't
given it much thought.
J
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-31 22:23 ` Jeremy Fitzhardinge
@ 2008-07-31 22:42 ` Ingo Molnar
2008-08-01 4:58 ` Jeremy Fitzhardinge
0 siblings, 1 reply; 12+ messages in thread
From: Ingo Molnar @ 2008-07-31 22:42 UTC (permalink / raw)
To: Jeremy Fitzhardinge; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
* Jeremy Fitzhardinge <jeremy@goop.org> wrote:
>> So this _has_ to be approached defensively. It _should_ work, and i'm
>> all in favor of utilizing hardware resources more fully, but it's an
>> entirely new mode of operation for the hardware. I think a Kconfig
>> option (which defaults to off), and a boot option to disable it would
>> be nice, so that we can introduce this gently, at least initially.
>> Then when we see that it's 100% trouble-free we can flip around the
>> default.
>
> As Andi pointed out, this is more or less functionally identical to
> the code I ripped out of tlb_64.c, so this mode of operation has had
> lots of exposure on the 64-bit side. Because the number of queues is
> a CONFIG variable, it would be relatively easy to make it a real
> config option, and/or use different numbers for 32 and 64-bit.
> Choosing 1 as the number of queues will make it behave exactly as the
> current code does.
>
> I'm not really familiar with all the ins and outs of apic bugs.
> What's the issue you're concerned about?
Yes on the 64-bit side we've had NUM_INVALIDATE_TLB_VECTORS (==8) for a
long time, but note that 64-bit is obviously for more modern CPUs. What
i'm mindful about (i'm not _that_ worried) are fragile APICs and unknown
erratas.
The other issue is that the concurrency pattern changes somewhat and
becomes more agressive. The existing 64-bit special-purpose TLB flush
code uses in essence synchronous waiting for that specific IPI that
belongs to that CPU, it sends the IPI then waits for the acknowledgement
by polling the flush mask:
send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR_START + sender);
while (!cpus_empty(f->flush_cpumask))
cpu_relax();
while with generic IPIs we could have asynchronous IPIs as well.
So with the TLB flush code there's never any true "multiple outstanding
IPIs" scenario for the same IPI, for 8 CPUs and fewer. (which is the
predominant majority of existing hardware)
> It also occurred to me that it might be more interesting to
> parameterise the queues - and the mapping of cpus->queues - in a more
> topology-aware way than simply NQUEUES=NCPUS/x, queue=cpuid % NQUEUES.
> But I haven't given it much thought.
i'd suggest we keep it at the current simple modulo rule.
Ingo
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-07-31 22:42 ` Ingo Molnar
@ 2008-08-01 4:58 ` Jeremy Fitzhardinge
2008-08-01 9:09 ` Ingo Molnar
0 siblings, 1 reply; 12+ messages in thread
From: Jeremy Fitzhardinge @ 2008-08-01 4:58 UTC (permalink / raw)
To: Ingo Molnar; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
Ingo Molnar wrote:
> Yes on the 64-bit side we've had NUM_INVALIDATE_TLB_VECTORS (==8) for a
> long time, but note that 64-bit is obviously for more modern CPUs. What
> i'm mindful about (i'm not _that_ worried) are fragile APICs and unknown
> erratas.
>
Well, the whole exercise is only useful if you have a relatively large
number of CPUs, which presumably means you have relatively modern
APICs. If we set the number of queues to 1 for < 4 CPUs, would that
avoid the problem APICs?
J
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-08-01 4:58 ` Jeremy Fitzhardinge
@ 2008-08-01 9:09 ` Ingo Molnar
2008-08-01 14:17 ` Andi Kleen
0 siblings, 1 reply; 12+ messages in thread
From: Ingo Molnar @ 2008-08-01 9:09 UTC (permalink / raw)
To: Jeremy Fitzhardinge; +Cc: Nick Piggin, Andi Kleen, Linux Kernel Mailing List
* Jeremy Fitzhardinge <jeremy@goop.org> wrote:
> Ingo Molnar wrote:
>> Yes on the 64-bit side we've had NUM_INVALIDATE_TLB_VECTORS (==8) for a
>> long time, but note that 64-bit is obviously for more modern CPUs. What
>> i'm mindful about (i'm not _that_ worried) are fragile APICs and
>> unknown erratas.
>>
>
> Well, the whole exercise is only useful if you have a relatively large
> number of CPUs, which presumably means you have relatively modern
> APICs. If we set the number of queues to 1 for < 4 CPUs, would that
> avoid the problem APICs?
hm, but such special casing would reduce testing exposure and would also
needlessly penalize boxes that work perfectly fine.
So ... how about my original suggestion, to add a (default-off) boot
option that reduces the queues to 1? I.e. lets have something in place
from day 1 on that could be quirk-handler-driven, should the need arise.
"apic=simpleipi" or something like that.
In a year or two, once this all has proven itself fine on a broad range
of systems, we'll laugh out loud at being so cautious and can remove the
boot option for good ;-)
Ingo
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] x86: implement multiple queues for smp function call IPIs
2008-08-01 9:09 ` Ingo Molnar
@ 2008-08-01 14:17 ` Andi Kleen
0 siblings, 0 replies; 12+ messages in thread
From: Andi Kleen @ 2008-08-01 14:17 UTC (permalink / raw)
To: Ingo Molnar
Cc: Jeremy Fitzhardinge, Nick Piggin, Andi Kleen,
Linux Kernel Mailing List
> So ... how about my original suggestion, to add a (default-off) boot
> option that reduces the queues to 1? I.e. lets have something in place
> from day 1 on that could be quirk-handler-driven, should the need arise.
> "apic=simpleipi" or something like that.
>
> In a year or two, once this all has proven itself fine on a broad range
> of systems, we'll laugh out loud at being so cautious and can remove the
> boot option for good ;-)
I agree that adding a boot option to turn it off is a good idea (assuming
it doesn't take too much code to implement) Adding such paranoid boot options early
has saved my ass a few times in the past.
Only tricky bit is use if () not "modulo variable", because the if ()
will be much faster than a division through an arbitary number.
-Andi
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2008-08-01 14:17 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-29 23:32 [PATCH 2/2] x86: implement multiple queues for smp function call IPIs Jeremy Fitzhardinge
2008-07-29 23:43 ` Jeremy Fitzhardinge
2008-07-30 0:13 ` Andi Kleen
2008-07-30 0:44 ` Jeremy Fitzhardinge
2008-07-30 4:55 ` Nick Piggin
2008-07-31 22:08 ` Ingo Molnar
2008-07-31 22:12 ` Andi Kleen
2008-07-31 22:23 ` Jeremy Fitzhardinge
2008-07-31 22:42 ` Ingo Molnar
2008-08-01 4:58 ` Jeremy Fitzhardinge
2008-08-01 9:09 ` Ingo Molnar
2008-08-01 14:17 ` Andi Kleen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox