When sending an IPI to a single CPU there is no need to deal with cpumasks. With 2 CPU guest on WS2019 I'm seeing a minor (like 3%, 8043 -> 7761 CPU cycles) improvement with smp_call_function_single() loop benchmark. The optimization, however, is tiny and straitforward. Also, send_ipi_one() is important for PV spinlock kick. I was also wondering if it would make sense to switch to using regular APIC IPI send for CPU > 64 case but no, it is twice as expesive (12650 CPU cycles for __send_ipi_mask_ex() call, 26000 for orig_apic.send_IPI(cpu, vector)). Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> --- arch/x86/hyperv/hv_apic.c | 22 +++++++++++++++++++--- arch/x86/include/asm/trace/hyperv.h | 15 +++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index e01078e93dd3..847f9d0328fe 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -194,10 +194,26 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector) static bool __send_ipi_one(int cpu, int vector) { - struct cpumask mask = CPU_MASK_NONE; + int ret; - cpumask_set_cpu(cpu, &mask); - return __send_ipi_mask(&mask, vector); + trace_hyperv_send_ipi_one(cpu, vector); + + if (unlikely(!hv_hypercall_pg)) + return false; + + if (unlikely((vector < HV_IPI_LOW_VECTOR) || + (vector > HV_IPI_HIGH_VECTOR))) + return false; + + if (cpu >= 64) + goto do_ex_hypercall; + + ret = hv_do_fast_hypercall16(HVCALL_SEND_IPI, vector, + BIT_ULL(hv_cpu_number_to_vp_number(cpu))); + return ((ret == 0) ? true : false); + +do_ex_hypercall: + return __send_ipi_mask_ex(cpumask_of(cpu), vector); } static void hv_send_ipi(int cpu, int vector) diff --git a/arch/x86/include/asm/trace/hyperv.h b/arch/x86/include/asm/trace/hyperv.h index ace464f09681..4d705cb4d63b 100644 --- a/arch/x86/include/asm/trace/hyperv.h +++ b/arch/x86/include/asm/trace/hyperv.h @@ -71,6 +71,21 @@ TRACE_EVENT(hyperv_send_ipi_mask, __entry->ncpus, __entry->vector) ); +TRACE_EVENT(hyperv_send_ipi_one, + TP_PROTO(int cpu, + int vector), + TP_ARGS(cpu, vector), + TP_STRUCT__entry( + __field(int, cpu) + __field(int, vector) + ), + TP_fast_assign(__entry->cpu = cpu; + __entry->vector = vector; + ), + TP_printk("cpu %d vector %x", + __entry->cpu, __entry->vector) + ); + #endif /* CONFIG_HYPERV */ #undef TRACE_INCLUDE_PATH -- 2.20.1