---
title: QE性能优化
description: "QE（Quantum-espresso）以第一性原理密度泛函理论为基础，其主要包括两大模块PWscf和CPMD。"
url: https://www.hikunpeng.com/document/detail/zh/perftuning/gputuing-wp/kunpenggpu_19_0038.html
sourcePath: /source/zh/perftuning/gputuing-wp/kunpenggpu_19_0038.html
indexId: 7a6297c1a124af0dda3d69c215893313ba83ea2e8a4a9988837eab6902ae29cf57
---
# QE性能优化

QE（Quantum-espresso）以第一性原理密度泛函理论为基础，其主要包括两大模块PWscf和CPMD。

- 优点
  计算材料费米面（金属）、电声耦合作用、超导性质（包括各向同性、异性超导特征）、功能模块化（易于添加新模块）、开源免费、易于上手（有专门的后处理程序包PP）等特征。

- 缺点
  同种原子赝势种类多、多组份化合物中的各元素赝势较难凑齐、vc-relax特慢等。


QE更多信息请参考官网：http://www.quantum-espresso.org/(http://www.quantum-espresso.org/)

自2016年以来，QE开发了一个用CUDA Fortran编写的GPU加速版本，该版本是由NVIDIA和QE开发人员联合开发的。它是用于GPU的CUDA Fortran和用于CPU的MPI + OpenMP的混合实现。目前最新版本v7.0. QE-GPU被认为是稳定的，也会定期进行更新。以下为GPU加速的模块列表。


QE使用最广泛的软件包是PWscf。该软件包在平面波的基础上求解K-S方程，并迭代直到形成自洽场。PWscf代表平面波自洽场。它是一种迭代方法，用于解决了相互依赖的多个方程。从一个非常简化的角度来看，可以把这个过程看作是解第1个方程，然后是解第2个方程，最后是解第3个方程。然后用第3次的解再次求解第1个方程，但比第1次的求解结果更准确，一开始，计算的结果将波动很大，但我们可以持续迭代这个循环，直到计算的结果开始收敛。这就是所谓的自洽。在每个循环中，都有多个步骤和问题需要解决，这些步骤和问题通常涉及许多线性代数和快速傅里叶变换。整个算法流程如下图所示。


带有绿色阴影方块的步骤中的主要计算模式：

A. 3D-FFT +矩阵运算 +Lapack运算

B. 3D-FFT +矩阵运算

C. 3D-FFT

QE-GPU版本中有两个主要的并行优化可用。因为它们可以在运行时进行选择，可以提供显著的性能增益。求解QM方程的方式提供了一些并行代码的方法，这些方法如下所示。从上到下，代码的目标是计算波函数（△），因为它需要解决一组称为k点的独立子问题。然后，对于每个k点，每个频带上的环路，我们有一组PW系数。QE在所有MPI进程之间分割所有系数。这具有分割内存使用的优点，但作为一种权衡，它在这些MPI进程之间引起了大量的通信。因此，当有足够的内存可用时，最好使用通过划分K点池的策略。k点级别是一个令人尴尬的并行级别，比如我们可以为每个GPU分配一个k点，并且这些GPU之间根本没有通信。

接下来基于ZNO-SCF算例进行测试，测试软件栈如下所示。

| 软件栈 | X86 6348(2P) A100\*2 | Kunpeng 920\-7265(2P) A100\*2 |
| --- | --- | --- |
| OS | Kylin V10 | Kylin V10 |
| Memory | 16\*16GB | 16\*16GB |
| MPI | 英伟达GPU版openMPI4 | 英伟达GPU版openMPI4 |
| Compiler | Intel 2021 | 鲲鹏GCC 9.3.1 |


在鲲鹏上采集的热点函数分布如下所示，可以看到GPU占比非常高（80%以上），比较适合拿来优化。


先用NSYS将GPU上面的代码进行性能采集，如下所示：


从热点情况来看，以GPU的热点为主，占据热点的50%~70%；但是GPU内的核函数热点较分散，主要耗时的核函数均提示利用率较低且网格划分过小。

使用命令nvidia-smi查看GPU卡利用率，发现双卡的利用率看起来也不高，说明还有比较大的优化空间。

#### GPU编译选项参数优化

QE主要是以Fortran语言实现为主，基于GPU编译参数优化的编译选项进行测试，发现如下选项有小幅提升。

| 编译选项 | 描述 |
| --- | --- |
| \-O 0 1 2 3 4 | 代码优化级别，这里选择O4 |
| \-Mipa | 进行过程分析优化 |
| \-Munroll | 循环展开 |
| \-Mvect | 自动向量化 |
| \-use\_fast\_math | 使能向量化、cache对齐、FTZ等内容 |
| \-\-fma | 是否使能乘加合并计算，这里设为\-\-fma=true |


#### MPS优化

通过性能特征分析发现GPU利用率比较低，GPU的功耗也没有达到最高，因此考虑使用MPS服务，多进程服务是一种使多个 CPU 进程提交的计算内核能够在同一GPU上同时执行的工具。这种重叠可能实现更彻底的资源使用和更好的总体吞吐量。而且测试发现，当进程数为8时K-S方程的负载均衡最佳。


#### 跨卡优化

默认情况下两张卡都共用一个CPU，因此会抢占PCIe总线，造成不必要的资源冲突，因此需要固定CPU各使用一张卡，如下所示：

```
mpirun --allow-run-as-root -np 8 -x CUDA_VISIBLE_DEVICES=0,2 -x OMP_NUM_THREADS=1
pw.x -nk 8 -input scf.in
```


#### kernel代码优化

针对热点Kernel代码vexx_k_gpu，根据特征分析发现存在线程发散和Block数目过少现象，因此将循环内的判断条件外提，并且适当增加Block数目，如下所示：

优化前：

```
all_start_tmp=all_start(wegrp)
DO jbnd=jstart, jend
!$cuf kernel do (1)
DO ir = 1, nrxxs
IF (noncolin) THEN
result_nc_d(ir,1,ii) = result_nc_d(ir,1,ii) &
+ vc(ir,jbnd-jstart+1) * exxbuff(ir,jbnd-all_start_tmp+iexx_start,ikq)
result_nc_d(ir,2,ii) = result_nc_d(ir,2,ii) &
+ vc(ir,jbnd-jstart+1) * exxbuff(ir+nrxxs,jbnd-all_start_tmp+iexx_start,ikq)
ELSE
result_d(ir,ii) = result_d(ir,ii) &
+ vc(ir,jbnd-jstart+1)*exxbuff(ir,jbnd-all_start_tmp+iexx_start,ikq)
ENDIF
ENDDO
ENDDO
```

优化后：

```
all_start_tmp=all_start(wegrp)
IF (noncolin) THEN
DO jbnd=jstart, jend
!$cuf kernel do <<<16,*,stream=cudaGetStreamDefault()>>>
DO ir = 1, nrxxs
result_nc_d(ir,1,ii) = result_nc_d(ir,1,ii) &
+ vc(ir,jbnd-jstart+1) * exxbuff(ir,jbnd-all_start_tmp+iexx_start,ikq)
result_nc_d(ir,2,ii) = result_nc_d(ir,2,ii) &
+ vc(ir,jbnd-jstart+1) * exxbuff(ir+nrxxs,jbnd-all_start_tmp+iexx_start,ikq)
ENDDO
ENDDO
ELSE
DO jbnd=jstart, jend
!$cuf kernel do <<<16,*,stream=cudaGetStreamDefault()>>>
DO ir = 1, nrxxs
result_d(ir,ii) = result_d(ir,ii) &
+ vc(ir,jbnd-jstart+1)*exxbuff(ir,jbnd-all_start_tmp+iexx_start,ikq)
ENDDO
ENDDO
ENDIF
```

经过上述优化，鲲鹏平台性能实现倍增，持平C1下一代芯片。
