高性能算法
数据结构+算法+体系结构
1. 稠密类
GEMM矩阵乘法
2. 稀疏类
稀疏矩阵向量乘(SPMV)
常用表示方法
- COO 三元组
Row Column Data - CSR (常用)一行一行记录
前i-1行有多少个 Row Data - CSC 一列一行记录
3. 优化分类
改良存储结构
利用CPU体系结构
SIMD Pipeline Prefetch
多核平台 多线程
考虑方面
- io性能(文件读取)
- 单核:cache命中率 SIMD 计算访存比
- 共享存储式并行性能:OPENMP
- 异构:CPU->GPU
- valgrind内存泄漏分析…
基础性能知识点
计算
单核CPU 1GHz 主频核 浮点计算部件数
1GHz * 24 * 1000 * 4 * 2 双精度 64位 8 字节
1GHz * 24 * 1000 * 4 * 2 * 2 单精度 32位 4 字节
加法示例
取指令 -> 译码 -> 取a -> 取b -> 求和 ->送数 c = a + b
10 1 10 10 1 10
- 提高主频
- cache 111111 是否命中?
- 流水线技术 理想全部占满 能否维持不断?
- 并行技术 超标量 多指令 多数据流 是否需要等待别的输出?
循环优化
局部性:时间 空间
cache是有多个cacheline堆叠
流水线利用cpu结构
1. 循环合并 loop fusion
// 原始
for (int i = 0; i < N; i ++)
x[i] = a[i] + b[i];
for (int i = 0; i < N; i ++)
y[i] = a[i] - b[i];
// 合并
for (int i = 0; i < N; i ++)
x[i] = a[i] + b[i];
y[i] = a[i] - b[i];
2. 循环展开 loop unrolling
// 原始
for (int i = 0; i < N; i ++)
A[i] = A[i] + B[i];
// 展开
for (int i = 0; i < N; i ++){
A[i] = A[i] + B[i];
A[i + 1] = A[i + 1] + B[i + 1];
}
减少循环分支,指令级并行、寄存器宠用
g++ loopUnrool.c -o loopUnroll2
yhrun -n1 -p thpc1 ./loopUnroll2
3. 循环交换
// 编译器
gcc -floop-interchange
for (int j = 0 ; j < N; j ++)
for (int i = 0; i < M; i ++)
A[i][j] = A[i][j];
4. 循环分布 Loop Distribute
for (int i = 0; i < N; i ++){
A[i] = i;
B[i] = 2 + B[i];
C[i] = 3 + C[i - 1];
}
for (int i = 0; i < N; i ++){
A[i] = i;
B[i] = 2 + B[i];
}
for (int i = 0; i < N; i ++){
C[i] = 3 + C[i - 1];
}
串行转换了多个并行,但一次循环做的事情就变少了
5. 循环不变量外提
避免重复计算
6. 循环分块
for (int i = 0; i < N; i ++)
for (int j = 0; j < M; j ++)
A[i] = A[i] + B[j];
// A:N/b B:N*M/b
for (int j = 0; j < M; j +=T)
for (int i = 0; i < N; i ++)
for (int jj = j; jj < j + T; jj ++)
A[i] = A[i] + B[jj];
// A: M/T*N/b B:M/T*T/b
// 获得cacheline大小
cat /sys/devices/system/cpu/cpu0/cache/index0;coherency_line_size
7. 循环分裂
// 原始
for (int i = 0; i < N; i ++)
A[i] = A[i] + B[M];
// 分裂
for (int i = 0; i < K; i ++)
A[i] = A[i] + B[M];
for (int i = K+1; i < N; i ++)
A[i] = A[i] + B[M];
// 编译器
gcc -O3 -fopt-infoo loopSplit1.c -o loop1
PETS安装
B站教学
安装目录放在了解压文件下了
export PETSC_DIR=/home/lhc/petsc16/petsc-3.16.6
export PETSC_ARCH=test1 // petsc-3.16.6下简历test1文件夹
python3 ./configure --with-fPIC CXXFLAGS="-O3 -fPIC" --download-mpich --download-f2cblaslapack=1 --with-fc=0 --with-debugging=0 COPTFLAGS="-O3 -fPIC" FOPTFLAGS="-fPIC -O3" CXXOPTFLAGS="-O3 -fPIC" --download-hypre -with-c2html=0 --with-shared-libraries=1 --with-64-bit-indices
make PETSC_DIR=/home/lhc/petsc16/petsc-3.16.6 PETSC_ARCH=test1 all
make PETSC_DIR=/home/lhc/petsc16/petsc-3.16.6 PETSC_ARCH=test1 check
cd $PETSC_DIR/src/ksp/ksp/tutorials
make ex2 && ./ex2
安装到指定petscinstall目录下
cp ~/software/petsc-3.18.1.tar ~/trainees/username
trainees/username$: tar -xf petsc-3.18.1.tar
// 下载petsc-pkg-fblaslapack.zip
trainees/username$: unzip petsc-pkg-fblaslapack.zip
mv ~/trainees/username/petsc-pkg-fblaslapack ~/trainees/username/petsc-3.18.1
//获取MPI
module avail | grep mpi-n
module load mpich/mpi-n-gcc9.3.0
which mpif90
// 设置基本变量
trainees/username/petsc-3.18.1$: export PETSC_DIR=$PWD
trainees/username/petsc-3.18.1$: mkdir arch-linux-c-debug # 这里的文件夹命名随意, 自己记得就行
trainees/username/petsc-3.18.1$: export PETSC_ARCH=arch-linux-c-debug
// 安装配置
trainees/username/petsc-3.18.1$: ./configure --prefix=~/trainees/username/petscinstall --with-mpi-dir=/thfs1/software/mpich/mpi-n-gcc9.3.0/ --download-fblaslapack=petsc-pkg-fblaslapack
// 安装
trainees/username/petsc-3.18.1$: make PETSC_DIR=~/trainees/username/petsc-3.18.1 PETSC_ARCH=arch-linux-c-debug all
// 安装后执行,文件夹下有include lib
trainees/username/petsc-3.18.1$: make PETSC_DIR=~/trainees/username/petsc-3.18.1 PETSC_ARCH=arch-linux-c-debug install
// 拷贝ex1.c
cp ~/trainees/username/petsc-3.18.1/src/ksp/ksp/tutorials/ex1.c ~/trainees/username
// 添加lib到环境变量
export LD_LIBRARY_PATH=~/trainees/username/petscinstall/lib
// 动态编译
trainees/username$: mpicc -o ex1 ex1.c -I ~/trainees/username/petscinstall/include -L ~/trainees/username/petscinstall/lib -l petsc
// 运行ex1.c
trainees/username$: yhrun -n 1 -N 1 -p thcp1 ./ex1