Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1645640 > unrolled thread

[PATCH v3 00/10] Hyper-V: praravirtualized remote TLB flushing and hypercall improvements

Started byVitaly Kuznetsov <vkuznets@redhat.com>
First post2017-05-19 16:20 +0200
Last post2017-05-19 16:20 +0200
Articles 2 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 00/10] Hyper-V: praravirtualized remote TLB flushing and hypercall improvements Vitaly Kuznetsov <vkuznets@redhat.com> - 2017-05-19 16:20 +0200
    [PATCH v3 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls Vitaly Kuznetsov <vkuznets@redhat.com> - 2017-05-19 16:20 +0200

#1645640 — [PATCH v3 00/10] Hyper-V: praravirtualized remote TLB flushing and hypercall improvements

FromVitaly Kuznetsov <vkuznets@redhat.com>
Date2017-05-19 16:20 +0200
Subject[PATCH v3 00/10] Hyper-V: praravirtualized remote TLB flushing and hypercall improvements
Message-ID<tIQV3-3mw-3@gated-at.bofh.it>
Changes since v2:
- Rebased to the latest char-misc-next tree.
- Added Acked-By and Tested-By tags.

Original descriptions:

Hyper-V supports hypercalls for doing local and remote TLB flushing and
gives its guests hints when using hypercall is preferred. While doing
hypercalls for local TLB flushes is probably not practical (and is not
being suggested by modern Hyper-V versions) remote TLB flush with a
hypercall brings significant improvement.

To test the series I wrote a special 'TLB trasher': on a 16 vCPU guest I
was creating 32 threads which were doing 100000 mmap/munmaps each on some
big file. Here are the results:

Before:
# time ./pthread_mmap ./randfile 
real	3m44.994s
user	0m3.829s
sys	3m36.323s

After:
# time ./pthread_mmap ./randfile 
real	2m57.145s
user	0m3.797s
sys	2m34.812s

This series brings a number of small improvements along the way: fast
hypercall implementation and using it for event signaling, rep hypercalls
implementation, hyperv tracing subsystem (which only traces the newly added
remote TLB flush for now).

Vitaly Kuznetsov (10):
  x86/hyper-v: include hyperv/ only when CONFIG_HYPERV is set
  x86/hyper-v: stash the max number of virtual/logical processor
  x86/hyper-v: make hv_do_hypercall() inline
  x86/hyper-v: fast hypercall implementation
  hyper-v: use fast hypercall for HVCALL_SIGNAL_EVENT
  x86/hyper-v: implement rep hypercalls
  hyper-v: globalize vp_index
  x86/hyper-v: use hypercall for remote TLB flush
  x86/hyper-v: support extended CPU ranges for TLB flush hypercalls
  tracing/hyper-v: trace hyperv_mmu_flush_tlb_others()

 MAINTAINERS                         |   1 +
 arch/x86/Kbuild                     |   4 +-
 arch/x86/hyperv/Makefile            |   2 +-
 arch/x86/hyperv/hv_init.c           |  90 ++++++------
 arch/x86/hyperv/mmu.c               | 270 ++++++++++++++++++++++++++++++++++++
 arch/x86/include/asm/mshyperv.h     | 149 +++++++++++++++++++-
 arch/x86/include/asm/trace/hyperv.h |  34 +++++
 arch/x86/include/uapi/asm/hyperv.h  |  36 +++++
 arch/x86/kernel/cpu/mshyperv.c      |  14 +-
 drivers/hv/channel_mgmt.c           |  22 ++-
 drivers/hv/connection.c             |   8 +-
 drivers/hv/hv.c                     |   9 --
 drivers/hv/hyperv_vmbus.h           |  11 --
 drivers/hv/vmbus_drv.c              |  17 ---
 drivers/pci/host/pci-hyperv.c       |   4 +-
 include/linux/hyperv.h              |  21 ++-
 16 files changed, 568 insertions(+), 124 deletions(-)
 create mode 100644 arch/x86/hyperv/mmu.c
 create mode 100644 arch/x86/include/asm/trace/hyperv.h

-- 
2.9.3

[toc] | [next] | [standalone]


#1645642 — [PATCH v3 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls

FromVitaly Kuznetsov <vkuznets@redhat.com>
Date2017-05-19 16:20 +0200
Subject[PATCH v3 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls
Message-ID<tIQV5-3mw-43@gated-at.bofh.it>
In reply to#1645640
Hyper-V hosts may support more than 64 vCPUs, we need to use
HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this
case.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Acked-by: K. Y. Srinivasan <kys@microsoft.com>
Tested-by: Simon Xiao <sixiao@microsoft.com>
Tested-by: Srikanth Myakam <v-srm@microsoft.com>
---
 arch/x86/hyperv/mmu.c              | 149 ++++++++++++++++++++++++++++++++++++-
 arch/x86/include/uapi/asm/hyperv.h |  10 +++
 2 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c
index e3ab9b9..c9cecb3 100644
--- a/arch/x86/hyperv/mmu.c
+++ b/arch/x86/hyperv/mmu.c
@@ -15,8 +15,57 @@ struct hv_flush_pcpu {
 	__u64 gva_list[];
 };
 
+/* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */
+struct hv_flush_pcpu_ex {
+	__u64 address_space;
+	__u64 flags;
+	struct {
+		__u64 format;
+		__u64 valid_bank_mask;
+		__u64 bank_contents[];
+	} hv_vp_set;
+	__u64 gva_list[];
+};
+
 static struct hv_flush_pcpu __percpu *pcpu_flush;
 
+static struct hv_flush_pcpu_ex __percpu *pcpu_flush_ex;
+
+static inline int cpumask_to_vp_set(struct hv_flush_pcpu_ex *flush,
+				    const struct cpumask *cpus)
+{
+	int cur_bank, cpu, vcpu, nr_bank = 0;
+	bool has_cpus;
+
+	/*
+	 * We can't be sure that translated vcpu numbers will always be
+	 * in ascending order, so iterate over all possible banks and
+	 * check all vcpus in it instead.
+	 */
+	for (cur_bank = 0; cur_bank < ms_hyperv.max_vp_index/64; cur_bank++) {
+		has_cpus = false;
+		for_each_cpu(cpu, cpus) {
+			vcpu = hv_cpu_number_to_vp_number(cpu);
+			if (vcpu/64 != cur_bank)
+				continue;
+			if (!has_cpus) {
+				flush->hv_vp_set.valid_bank_mask |=
+					1 << vcpu / 64;
+				flush->hv_vp_set.bank_contents[nr_bank] =
+					1 << vcpu % 64;
+				has_cpus = true;
+			} else {
+				flush->hv_vp_set.bank_contents[nr_bank] |=
+					1 << vcpu % 64;
+			}
+		}
+		if (has_cpus)
+			nr_bank++;
+	}
+
+	return nr_bank;
+}
+
 static void hyperv_flush_tlb_others(const struct cpumask *cpus,
 				    struct mm_struct *mm, unsigned long start,
 				    unsigned long end)
@@ -102,16 +151,112 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,
 	native_flush_tlb_others(cpus, mm, start, end);
 }
 
+static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
+				       struct mm_struct *mm,
+				       unsigned long start,
+				       unsigned long end)
+{
+	struct hv_flush_pcpu_ex *flush;
+	unsigned long cur, flags;
+	u64 status = -1ULL;
+	int nr_bank = 0, max_gvas, gva_n;
+
+	if (!pcpu_flush_ex || !hv_hypercall_pg)
+		goto do_native;
+
+	if (cpumask_empty(cpus))
+		return;
+
+	local_irq_save(flags);
+
+	flush = this_cpu_ptr(pcpu_flush_ex);
+
+	if (mm) {
+		flush->address_space = virt_to_phys(mm->pgd);
+		flush->flags = 0;
+	} else {
+		flush->address_space = 0;
+		flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
+	}
+
+	flush->hv_vp_set.valid_bank_mask = 0;
+
+	if (cpumask_equal(cpus, cpu_present_mask)) {
+		flush->hv_vp_set.format = HV_GENERIC_SET_ALL;
+		flush->flags |= HV_FLUSH_ALL_PROCESSORS;
+	} else {
+		flush->hv_vp_set.format = HV_GENERIC_SET_SPARCE_4K;
+		nr_bank = cpumask_to_vp_set(flush, cpus);
+	}
+
+	/*
+	 * We can flush not more than max_gvas with one hypercall. Flush the
+	 * whole address space if we were asked to do more.
+	 */
+	max_gvas = (PAGE_SIZE - sizeof(*flush) - nr_bank*8) / 8;
+
+	if (end == TLB_FLUSH_ALL ||
+	    (end && ((end - start)/(PAGE_SIZE*PAGE_SIZE)) > max_gvas)) {
+		if (end == TLB_FLUSH_ALL)
+			flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
+
+		status = hv_do_rep_hypercall(
+			HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
+			0, nr_bank + 2, flush, NULL);
+	} else {
+		cur = start;
+		gva_n = nr_bank;
+		do {
+			flush->gva_list[gva_n] = cur & PAGE_MASK;
+			/*
+			 * Lower 12 bits encode the number of additional
+			 * pages to flush (in addition to the 'cur' page).
+			 */
+			if (end >= cur + PAGE_SIZE * PAGE_SIZE)
+				flush->gva_list[gva_n] |= ~PAGE_MASK;
+			else if (end > cur)
+				flush->gva_list[gva_n] |=
+					(end - cur - 1) >> PAGE_SHIFT;
+
+			cur += PAGE_SIZE * PAGE_SIZE;
+			++gva_n;
+
+		} while (cur < end);
+
+		status = hv_do_rep_hypercall(
+			HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX,
+			gva_n, nr_bank + 2, flush, NULL);
+	}
+
+	local_irq_restore(flags);
+
+	if (!(status & 0xffff))
+		return;
+do_native:
+	native_flush_tlb_others(cpus, mm, start, end);
+}
+
 void hyperv_setup_mmu_ops(void)
 {
-	if (ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED) {
+	if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
+		return;
+
+	if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) {
 		pr_info("Hyper-V: Using hypercall for remote TLB flush\n");
 		pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others;
+	} else {
+		pr_info("Hyper-V: Using ext hypercall for remote TLB flush\n");
+		pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others_ex;
 	}
 }
 
 void hyper_alloc_mmu(void)
 {
-	if (ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED)
+	if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
+		return;
+
+	if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
 		pcpu_flush = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
+	else
+		pcpu_flush_ex = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
 }
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h
index 3d44036..c697e20 100644
--- a/arch/x86/include/uapi/asm/hyperv.h
+++ b/arch/x86/include/uapi/asm/hyperv.h
@@ -152,6 +152,9 @@
  */
 #define HV_X64_DEPRECATING_AEOI_RECOMMENDED	(1 << 9)
 
+/* Recommend using the newer ExProcessorMasks interface */
+#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED	(1 << 11)
+
 /*
  * Crash notification flag.
  */
@@ -242,6 +245,8 @@
 #define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE	0x0002
 #define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST	0x0003
 #define HVCALL_NOTIFY_LONG_SPIN_WAIT		0x0008
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX  0x0013
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX   0x0014
 #define HVCALL_POST_MESSAGE			0x005c
 #define HVCALL_SIGNAL_EVENT			0x005d
 
@@ -263,6 +268,11 @@
 #define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY	0x00000004
 #define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT	0x00000008
 
+enum HV_GENERIC_SET_FORMAT {
+	HV_GENERIC_SET_SPARCE_4K,
+	HV_GENERIC_SET_ALL,
+};
+
 /* Hypercall interface */
 union hv_hypercall_input {
 	u64 as_uint64;
-- 
2.9.3

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web