395 Star 1.4K Fork 1.3K

GVPopenEuler / kernel

 / 详情

[openEuler-20.03 SP2] ARM64 一个 DIE 上部署多台虚拟机测试 unixbench spawn 性能下降

已完成
任务 成员
创建于  
2021-09-24 09:49

输入图片说明

一个 DIE 32 个核,虚拟机配置 4U8G。则一个 DIE 最多可以配置 8 台。
发现,一个 DIE 上配置的虚拟机越多,测试 unixbenc spawn 性能越差

虚拟机数量 性能 pct/117/1024
1 3000/3900
2 2500/NA
8 850/950

跨 DIE 配置,性能反而没有下降的十分严重。

其他场景的测试也对的上这个现象。
8U16G 的时候,一个 DIE 内部署,性能也下降。
但是 32U 配置的时候,性能反而不下降。

进一步测试发现,标红的这几项测试线性度都会下降
输入图片说明

评论 (17)

Hi gatieme, welcome to the openEuler Community.
I'm the Bot here serving you. You can find the instructions on how to interact with me at
https://gitee.com/openeuler/community/blob/master/en/sig-infrastructure/command.md.
If you have any questions, please contact the SIG: Kernel, and any of the maintainers: @Xie XiuQi, @YangYingliang, @成坚 (CHENG Jian).

成坚 (CHENG Jian) 创建了任务
成坚 (CHENG Jian) 关联仓库设置为openEuler/kernel
openeuler-ci-bot 添加了
 
sig/Kernel
标签
成坚 (CHENG Jian) 修改了描述
成坚 (CHENG Jian) 修改了描述
成坚 (CHENG Jian) 修改了描述
成坚 (CHENG Jian) 修改了描述
展开全部操作日志

4U8G 一个 DIE 上配置 8 台虚拟机
输入图片说明

HOST 上测试有同样问题。

模拟在虚拟机中的类似场景。
每组单独把 unixbench 的目录拷贝出一份,单独进行测试,防止 page cache 影响测试结果。

组数 线程数目 是否跨 NUMA 结果
1 32 N 10838
2 4 N 3305/3267
1 4 N 3869
1 8 N 6358
8 4 N 133x
2 4 Y(分别绑核 0-3, 60-63) 3296.0/3335.5

host 上测试,基本现象一致。只是跨了 numa 以后,性能也有影响,也合理。
虚拟机里面部署 unixbench 测试,跨了 numa 以后,两台虚拟机内 unixbench 性能都没有下降。

perf list| grep flux_wr
perf list| grep flux_rd

按照die来封装的,就是SCCL,每个SCCL下有4个DDRC
然后分读写flux_rd和flux_wr,然后乘以32Byte就是带宽
DMC的位宽是256bits

perf内存带宽

perf stat -e hisi_sccl1_ddrc0/flux_rd/ -e hisi_sccl1_ddrc0/flux_wr/ -e hisi_sccl3_ddrc0/flux_rd/ -e hisi_sccl3_ddrc0/flux_wr/ -e hisi_sccl5_ddrc0/flux_rd/ -e hisi_sccl5_ddrc0/flux_wr/ -e hisi_sccl7_ddrc0/flux_rd/ -e hisi_sccl7_ddrc0/flux_wr/ -I 1000

后面加 -o out.log会输出到文件

拉上芯片相关的兄弟讨论后,多虚机下,Unixbench 某些子项性能损耗较大。主要是我们的MN调度问题,在大量 tlbi i s场景下跨 die 跨 P 调度不均衡。
spawn 子项的调优效果。

输入图片说明

但是我们当前这个问题,并没有跨越 DIE。

成坚 (CHENG Jian) 修改了描述
成坚 (CHENG Jian) 上传了附件0001-rm-kvm-FB-bit.patch
成坚 (CHENG Jian) 上传了附件0001-arm64-Add-IPI-based-tlb-flush-helpers.patch

结论: tlbi 广播风暴, ARM 存在此问题.

暂时规避手段: 从tlb.is 到IPI的方式

文件 描述
0001-rm-kvm-FB-bit.patch host 上的补丁
0001-arm64-Add-IPI-based-tlb-flush-helpers.patch guest 上的补丁

补丁为验证补丁,不保证功能完善和稳定性。

使用 IPI 的方式,CPU 核间通讯开销增大。
多数清凉下,还是 tlb.is 广播的方式性能比较好。

从 tlb.is 到 IPI 的方式,是否可以借鉴 lazy tlb 的方式降低 TLB 刷新频率,甚至根据 CPUID 来选择合适的 ARM 指令 ?

这个可以缓解问题,在 core1 dvm sync 会回得快,但是 MN 还是要发往所有核,而且 MN 的 outstanding 是 1

之前 PCIe hot-unlug 新机制也引入了类似的问题。

  1. core 1 正在与移除的 PCIe 设备交互, 等待响应。
  2. 这时 Core 2 广播一个无关的 TLBI+DSB(刷 TLB 和 Cache) 到 Core 1, 并等待 Core 1 确认。

问题:理由情况下 Core 1 会很快响应,因此此 TLBi 指令无效的地址与其无关,不存在 pending 事务。但是 Core 1 在回复 TLBi 之前必须等待所有事务完成,导致 Core 2 也要等待超时结束(例如 50MS) 后才能收到应答。

输入图片说明
PCIe XS 属性提供了一个有效的机制来避免这种情况,PCIe 设备映射 XS=1,说明可能存在较长的延迟。其他区域,如 RAM,标记 XS=0.

在示例场景中,CORE 1 知道只有 XS=1 的访问未完成,因此,在这种情况下,可以设置 XS=0 允许快速响应 CORE 2 的 TLBI 请求,然后继续等待设备超时。
输入图片说明

原版的补丁有问题

host依然能统计到大量dvm的原因找到了,是guest的patch没有打全,只改了一部分,这个函数中的is没有去掉。
输入图片说明

做如下修正

  1. 首先 flush_tlb_mm_nosync 还是想使用广播的方式的,因此需要用 aside1is(IS) 的方式。
  2. ipi_flush_tlb_page -=> local_flush_tlb_page 是想发 IPI 的,因此不需要用 IS 的方式。

输入图片说明

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 9c1912570823..5b2e81813dbc 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -269,8 +269,9 @@ static inline void flush_tlb_mm_nosync(struct mm_struct *mm)
        unsigned long asid = __TLBI_VADDR(0, ASID(mm));
 
        dsb(ishst);
-       __tlbi(aside1, asid);
-       __tlbi_user(aside1, asid);
+       __tlbi(aside1is, asid);
+       __tlbi_user(aside1is, asid);
+       dsb(ish);
 }
 
 static inline void flush_tlb_page_nosync(struct vm_area_struct *vma,
@@ -289,8 +290,8 @@ static inline void local_flush_tlb_page(struct vm_area_struct *vma,
        unsigned long addr = __TLBI_VADDR(uaddr, ASID(vma->vm_mm));
 
        dsb(nshst);
-       __tlbi(vale1is, addr);
-       __tlbi_user(vale1is, addr);
+       __tlbi(vale1, addr);
+       __tlbi_user(vale1, addr);
        dsb(nsh);
 }

补丁见附件中 V2

成坚 (CHENG Jian) 上传了附件0001-arm64-Add-IPI-based-tlb-flush-helpers-v.patch
成坚 (CHENG Jian) 删除了附件0001-arm64-Add-IPI-based-tlb-flush-helpers-v.patch
成坚 (CHENG Jian) 上传了附件0001-arm64-Add-IPI-based-tlb-flush-helpers-v2.patch

这里已经有 ish 了。
输入图片说明

因此, flush_tlb_mm_nosyn() 中的可以删掉了

diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 5b2e81813dbc..3dd2488ea37f 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -271,7 +271,6 @@ static inline void flush_tlb_mm_nosync(struct mm_struct *mm)
        dsb(ishst);
        __tlbi(aside1is, asid);
        __tlbi_user(aside1is, asid);
-       dsb(ish);
 }

参见 V3

成坚 (CHENG Jian) 上传了附件0001-arm64-Add-IPI-based-tlb-flush-helpers-v3.patch

多 VM 验证效果如下:
输入图片说明

用于对于的单 VM 数据:
输入图片说明

成坚 (CHENG Jian) 任务状态待办的 修改为已完成

虚拟机固定绑核的时候,测试没有问题。
但是虚拟机设置成范围绑核的时候,测试出现了批量虚拟机无法启动的问题。

固定绑核如下所示:

输入图片说明

范围绑核如下所示:
输入图片说明

输入图片说明

进一步分析测试发现:
5220 上 HOST 没去掉 FB,虚拟机打了 patch,满虚拟机能正常起了,目前跑着也都正常。无异常启动的问题,
7260 HOST 不去掉FB用原始的内核,范围绑核也没出现虚拟机挂掉的情况。

HOST 不去掉 FB,就应该不会出现虚拟机挂掉的问题,但是这样性能数据上不去。

这个FB的特性为啥影响虚机稳定性?

实质上是vcpu迁移带来的tlbi不一致问题。
FB的作用是,将虚拟机发出来的 TLBI 强制转换为广播型 TLBI IS,若关掉,则可能发生:vcpu0本来在cpu0中,但中途被迁移到了cpu1,此时发出TLBI,host 只会在 cpu1 进行刷 tlb 操作,vcpu0 再返回 cpu0 时,tlb 依然是旧的,就会导致问题出现。

输入图片说明

输入图片说明

输入图片说明

那为什么 X86 这边用 IPI 的方式没问题呢?
因为 X86 tlb shotdown 没有 tlb.IS 的方案,因此 X86 本身刷 other CPU 的 tlb, 就是用的 IPI 方式。
因此 host 测 KVM 里面做了保证,上面 ARM64 出问题的这个情况, x86上, vcpu每迁到一个别的物理cpu,就会刷tlb.

理论上在 ARM 上也应该可以用同样的方式解决关FB之后的。

但是这种不确定会不会有性能下降,本来有 asid 保证迁移回来的 vcpu 可以直接使用tlb,现在迁移一次就要 flush all tlb, 会造成大量tlb miss。

之前 HISI 的汤年耀 KVM 里面的修改
https://www.spinics.net/lists/kvm-arm/msg42855.html

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 64ce29378467..f85ea9c649cb 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -75,7 +75,7 @@
  * PTW:		Take a stage2 fault if a stage1 walk steps in device memory
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
-			 HCR_BSU_IS | HCR_FB | HCR_TAC | \
+			 HCR_BSU_IS | HCR_TAC | \
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
 			 HCR_FMO | HCR_IMO | HCR_PTW )
 #define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index acf9a993dfb6..845be911f885 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -334,8 +334,10 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	/*
 	 * We might get preempted before the vCPU actually runs, but
 	 * over-invalidation doesn't affect correctness.
+	 * Dirty tlb might still exist when vcpu ran on other pcpu
+	 * and modified page mapping.
 	 */
-	if (*last_ran != vcpu->vcpu_id) {
+	if (*last_ran != vcpu->vcpu_id || vcpu->cpu != cpu) {
 		kvm_call_hyp(__kvm_tlb_flush_local_vmid, mmu);
 		*last_ran = vcpu->vcpu_id;
 	}
-- 
2.7.4

vcpu 切了 CPU 之后,通过 __kvm_tlb_flush_local_vmid 刷掉所有的 TLB.
但是 HCR_FB 本身的作用除了刷 TLB 以外, 还有 flush icache. 这个补丁当前遗留的问题就是没有刷 icache.

host 上增加刷 icache 的补丁
0001-KVM-arm64-don-t-force-broadcast-tlbi-and-ic.patch

From fdc9ff90003d39c52e2ae53cc9f90ec86a1cc30e Mon Sep 17 00:00:00 2001
From: t00358190 <tangnianyao@huawei.com>
Date: Mon, 25 Oct 2021 11:47:27 +0800
Subject: [PATCH] KVM:arm64:don't force broadcast tlbi and ic

Signed-off-by: t00358190 <tangnianyao@huawei.com>
---
 arch/arm64/include/asm/kvm_arm.h | 2 +-
 arch/arm64/kvm/arm.c             | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 0cafa405c7f6..7a72c7de0884 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -80,7 +80,7 @@
  * PTW:		Take a stage2 fault if a stage1 walk steps in device memory
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
-			 HCR_BSU_IS | HCR_FB | HCR_TAC | \
+			 HCR_BSU_IS | HCR_TAC | \
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
 			 HCR_FMO | HCR_IMO | HCR_PTW )
 #define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index eb645005d80d..928c8f5532e2 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -435,9 +435,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	/*
 	 * We might get preempted before the vCPU actually runs, but
 	 * over-invalidation doesn't affect correctness.
+	 * For HCR_FB=0, we need to invalid icache and tlb in cases
+	 * that vCPU modified page mapping or instruction memory on
+	 * other pCPU and then comes back.
 	 */
-	if (*last_ran != vcpu->vcpu_id) {
+	if (*last_ran != vcpu->vcpu_id || vcpu->cpu != cpu) {
 		kvm_call_hyp(__kvm_tlb_flush_local_vmid, mmu);
+		asm volatile("ic iallu");
 		*last_ran = vcpu->vcpu_id;
 	}
 
-- 
2.30.0

4.19.90-2112.4.0

虚拟化合入

823f53c21805 KVM: arm64: Allow vcpus running without HCR_EL2.FB
0190e611bcf9 KVM: arm64: Set kvm_vcpu::pre_pcpu properly
fe48bc793859 KVM: arm64: Ensure I-cache isolation between vcpus of a same VM

HULK 合入

b4e67accd958 arm64/tlbi: mark tlbi ipi as EXPERIMENTAL
d717b3ebd9fb arm64/tlb: restore no IPi code
bab7ce2efbac arm64/configs: enable TLBI_IPI
a3dbee092508 arm64/tlbi: split disable_tlbflush_is to control flush
fd48e2aece31 arm64/tlb: add CONFIG_ARM64_TLBI_IPI
1f280b9201d8 arm64: tlb: Add boot parameter to disable TLB flush within the same inner shareable domain
7816d8f27354 arm64: mm: Restore mm_cpumask (revert commit 38d96287504a ("arm64: mm: kill mm_cpumask usage"))

kernel 增加命令行参数 disable_tlbflush_is,在 inner shareable 域内,控制所有 PE 刷新 tlb 的方式。

刷 tlb 方式 描述
IPI 方式 采用类似于 X86_64 的方式,跟踪进程运行过的 CPU 核(记录在 mm_cpumask),使用 IPI 方式发 tlb invalid 请求给这些核。
TLBI 方式 不跟踪记录进程运行过的 CPU, 通过 ARM64 TLBI 指令由硬件完成 tlb invalid

使用:

需要配置 CONFIG_ARM64_TLBI_IPI 使能时生效,默认功能禁用,然后启动参数添加 disable_tlbflush_is= [page,range,switch,]mm。其中每个子项分别控制 flush_tlb_xxxx 下是否禁用 TLBI 而使用 IPI 方法。

配置项 描述
page 配置 page 后, flush_tlb_page 将使用 IPI 方式
range 配置 range 后, flush_tlb_range 将使用 IPI 方式
switch 配置 switch 后, 进程切换时,将flush 掉所在核的 tlb entry
mm 配置 mm 后,flush_tlb_mm 将使用 IPI 方式

kvm补丁,通过一个内核启动参数 实现特性的开关,默认关闭。
开启方法:在内核启动参数中添加“kvm-arm.hcr_nofb=1”,重启主机后生效。
开启后,KVM 将关闭 HCR_FB 功能,guest 发送的 TLB 请求,不会转换为 TLBI 请求,配合 disable_tlbflush_is 使用。

登录 后才可以发表评论

状态
负责人
项目
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
预计工期 (小时)
参与者(2)
5329419 openeuler ci bot 1632792936
C
1
https://gitee.com/openeuler/kernel.git
git@gitee.com:openeuler/kernel.git
openeuler
kernel
kernel

搜索帮助