Menu

ASC20选拔纪事

优化组第一题

题面

CFD 应用物理量梯度求解算法优化

PAC2019-初赛题

即群文件FYArray.tar.tgz

简介

计算流体力学程序中,粘性项离散的关键是计算物理量在界面处的梯度。求梯度的原理是高斯-格林公式:

\[\oint_{V}\triangledown Q dV=\iint_{\partial V}Q\cdot\vec{n}dS\]

即单元中心的梯度可以积分面心的值得到。

\[(\triangledown\phi)_{i,j,k}=\frac{1}{V_{i,j,k}}[(\phi S)_{i+1/2,j,k}-(\phi S)_{i-1/2,j,k}+(\phi S)_{i,j+1/2,k} -(\phi S)_{i,j-1/2,k}+(\phi S)_{i,j,k+1/2}-(\phi S)_{i,j,k-1/2}]\]

二维示例图

0

注:公式及示例图来自 NSMB 文档

题目要求

  1. 解压源码包后,根目录下有 2 个文件夹 include 和 src,一个 Makefile 文件以及 一个结果验证文件的软连接 check.txt。头文件在 include 路径中。源码在 src 路 径中,分别是 main.cpp 和 FYStorage.cpp,src 中 Makefile 为实际调用的文件, 参赛队员可根据优化需求自行修改两个 Makefile。check.txt 用于程序最后的结果 验证,不可修改。
  2. rdtsc 为计时函数,程序计时以该函数在计算前后调用两次的时间差为准,该部分不可修改。
  3. main.cpp 中数据初始化部分不包括在程序计时内,不可修改。
  4. preccheck 为结果正确性验证函数,参赛队员不可修改该函数中包括参数以内的任何代码。
  5. 主要计算过程结果是会用于粘性通量计算的,不可以删减循环次数来减少计算量

使用方法

  1. 解压缩后,进入 FYArray 路径:

    1
    2
    
    tar xzf FYArray.tar.tgz
    cd FYArray
    
  2. 本程序可直接输入 make 编译:

    1
    
    make
    
  3. 编译完成后在 src 和当前路径下分别生成可执行程序 FYArray.exe,可直接./ FYArray.exe 运行,运行前注意一下 check.txt 软链接所指文件是否正确,计算完成后程 序自动输出墙钟计时”The programe elapsed”单位秒,若结果误差小于等于精度设定值 10^-6,程序将会在最后输出”Result check passed!”。(check.txt 实际放在 /home/public 中)
  4. 若计算结果的误差大于精度设定值 10^-6,程序将输出第一个出错位置及其对应的实际值、正确值
  5. 本程序最多使用 64 线程运行
  6. 本程序修改自 PAC2019 初赛题目,请不要直接使用 PAC 官方原版代码

需要提交文件

  1. 优化后源代码
  2. 优化报告
    1. 优化思路
    2. 每一步优化的结果
    3. 其他体现你的工作的内容

解答

为了控制变量,以下所有的测试结果都是在 kn103 节点上跑出来的。最终跑出的最佳成绩如下:

1

第 0 步:优化之前

本步完成之后的内容在src0\目录下。本步的运行结果(这一步除了代码格式化和调整文件链接没有做任何修改,因此可以用于和后面每一步优化的结果做对比):

1
2
The programe elapsed 83.9225 s
Result check passed!
登陆计算节点

因为控制变量(懒),以下所有的测试结果都是在 kn103 节点上跑出来的。

1
2
ssh -p 12345 [email protected]
ssh -p 12343 [email protected]
代码格式化&文件编码

原来提供的代码风格非常混杂,有时候花括号换行有时候又不换,还有各种不一样的缩进,修改起来有一些难受。为方便起见,用 VSCodeC/C++插件的默认格式化配置,打开src\main.cpp,按Shift+Alt+S即可。

原来中文注释的编码是 GB2312,我用的编辑器 VSCode 自作主张把它换成 UTF-8 了。

优化范围

根据注释,应当优化的部分应该在start = rdtsc();end = rdtsc();之间。

然而解压出的目录include下还有很多内容,大致看了一下,是一个可以自定义区间和跨度的、类似于 STL 中已经弃用的valarray的模板类。好在出题人非常良心,在main.cpp中已经用#ifdef EXPANDED宏把用到这个鬼畜模板的部分展开了,要给一个大大的赞。因此,这些个奇妙头文件(以及另一个文件src\FYStorage.cpp)和我的优化部分没有什么关系了。

因此,需要修改的内容只有src/main.cpp中的部分代码和src/Makefile

分析代码结构

虽然出题人已经帮我们把原来的部分展开了,但是展开前的代码还是有用的,比如方便理解算法在这部分在做什么。现在用伪代码稍微描述一下原先代码的大致逻辑:

对于三个维度里的每一维:

  1. 初始化 dqdx_4d(dqdy_4d、dqdz_4d 同理)
  2. 用 xfn、area 算 worksx(worksy、worksz 同理)
  3. 对于$[mst,med]$区间内的每个 m
    • 用 worksx 和 q_4d 更新 dqdx_4d(dqdx_4d、dqdx_4d 同理)
  4. 对于$[mst,med]$区间内的每个 m
    • 用 worksx 和 q_4d 更新 dqdx_4d(dqdx_4d、dqdx_4d 同理),这里的更新和第三步略有差异
  5. 当前不是第二维且共两维时:
    1. 用 xfn 和 area 更新 worksx(worksy、worksz 同理)
    2. 计算 q_4d 的二位均值 workqm
    3. 用 worksx 和 workqm 更新 dqdx_4d(dqdy_4d、dqdz_4d 同理)
    4. 用 worksx 和 workqm 更新 dqdx_4d(dqdy_4d、dqdz_4d 同理),这里的更新和第七步略有差异
  6. 当前不是第一维且共两维时:
    1. 用 xfn 和 area 更新 worksx(worksy、worksz 同理)
    2. 计算 q_4d 的二位均值 workqm
    3. 用 worksx 和 workqm 更新 dqdx_4d(dqdy_4d、dqdz_4d 同理)
    4. 用 worksx 和 workqm 更新 dqdx_4d(dqdy_4d、dqdz_4d 同理),这里的更新和第七步略有差异
  7. 用 vol 计算 workqm
  8. 用 workqm 更新 dqdx_4d(dqdy_4d、dqdz_4d 同理)
修正错误部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifdef EXPANDED
for (int m = mst; m <= med; ++m)
{
	for (int k = 1; k <= nk + 1; ++k)
	{
		for (int j = 1; j <= nj + 1; ++j)
		{
			for (int i = 1; i <= ni + 1; ++i)
			{
				Pdqdx_4d[LOC4D(i, j, k, m)] = 0.0;
				Pdqdx_4d[LOC4D(i, j, k, m)] = 0.0; //修正为Pdqdy_4d
				Pdqdx_4d[LOC4D(i, j, k, m)] = 0.0; //修正为Pdqdz_4d
			}
		}
	}
}
#else
dqdx_4d(I, J, K, M) = 0.0;
dqdy_4d(I, J, K, M) = 0.0;
dqdz_4d(I, J, K, M) = 0.0;
#endif

对比展开前的代码,似乎这段初始化代码的展开部分有问题,暂时先修正了。

确定并行框架

根据代码来看,所有循环迭代的次数在运行前已经确定了,并且代码中每次迭代的消耗都差不多,也不需要动态调度。由于只用一台计算节点,不需要分布式,直接共享内存,所以选用 OpenMP 即可。其实大量相似且简单的多维向量计算感觉用 CUDA 最合适,可惜没有显卡资源。

一开始觉得在CXXFLAGS中加上-qopenmp即可,然而这样做编译时报错,大致是 omp 的一系列函数在 link 时未定义的引用。以为是 OpenMP 环境配置的问题,但是多次尝试未能解决。后来无意中发现单文件的编译情况是正常的。无奈之下,修改了 Makefile 文件和main.cpp,改为在main.cpp中直接直接加入FYStorage.cpp的内容(反正就几行),从而避免了多编译文件的链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TARGET=FYArray.exe

CXX=icpc
CXXFLAGS=-qopenmp
LDFLAGS=

INCLUDE=../include

$(TARGET):main.cpp
	$(CXX) $< $(CXXFLAGS) -I$(INCLUDE) -o $@
	cp $(TARGET) ../

.PHONY:clean
clean:
	rm *.o -f

第 1 步:串行逻辑的优化

本步完成之后的内容在src1\目录下。本步的运行结果:

1
2
The programe elapsed 39.7008 s
Result check passed!
只保留展开部分

保留所有#ifdef EXPANDED内的部分,删去所有#else的部分,方便后面调整循环顺序和循环的合并。

条件分支等的优化

下面这两个条件分支是必定成立的,因为nDim是常数 3,条件必定成立。因此删去两个判断语句,方便后面循环间的合并。

1
2
if ((nsurf != 2) || (nDim != TWO_D)) {/* */}
if ((nsurf != 1) || (nDim != TWO_D)) {/* */}

下面的代码也看的人非常不舒服。使用条件表达式去掉分支,心情舒畅。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
int index[] = {1, 2, 3, 1, 2};
int ns1 = nsurf;
int ns2 = index[nsurf];
int ns3 = index[nsurf + 1];
int il1 = 0;
int il2 = 0;
int il3 = 0;
int jl1 = 0;
int jl2 = 0;
int jl3 = 0;
int kl1 = 0;
int kl2 = 0;
int kl3 = 0;
if (nsurf == 1)
{
	il1 = 1;
	jl2 = 1;
	kl3 = 1;
}
else if (nsurf == 2)
{
	jl1 = 1;
	kl2 = 1;
	il3 = 1;
}
else if (nsurf == 3)
{
	kl1 = 1;
	il2 = 1;
	jl3 = 1;
}
*/
const int
	ns[3] =
		{nsurf,
		 nsurf + 1 > THREE_D ? nsurf + 1 - THREE_D : nsurf + 1,
		 nsurf + 2 > THREE_D ? nsurf + 2 - THREE_D : nsurf + 2},
	il[3] = {nsurf == 1, nsurf == 3, nsurf == 2},
	jl[3] = {nsurf == 2, nsurf == 1, nsurf == 3},
	kl[3] = {nsurf == 3, nsurf == 2, nsurf == 1},
	d[3] =
		{il[0] * s0 + jl[0] * s1 + kl[0] * s2,
		 il[1] * s0 + jl[1] * s1 + kl[1] * s2,
		 il[2] * s0 + jl[2] * s1 + kl[2] * s2},
	d0 = d[0];

上面 d 数组是为了方便后面优化宏的部分,见下。

宏的展开

代码中定义了两个宏,然而这些宏基本上是运行时求解的。手动展开,并预处理展开的值,像这样:

1
2
3
4
5
6
/*
#define LOC4D(i0, i1, i2, i3) ((i0)*s0 + (i1)*s1 + (i2)*s2 + (i3)*s3)
#define LOC3D(i0, i1, i2) ((i0)*s0 + (i1)*s1 + (i2)*s2)
*/
const int p1 = i * s0 + j * s1 + k * s2;
const int p0 = p1 + m * s3, o0 = p0 - d[0];

同时,这样做也绝对有利于后面多层循环的合并。

worksx、worksy、worksz、workqm 的优化

原先的代码中申请了这些地址用于计算一些「中转值」的计算,我经过多次循环合并之后把他们优化成「对于每一个 kji」的一个$3\times 3$矩阵和三维向量间的乘法运算了。这样既减少了内存需求,也增加了代码的局部性,因为 works 的值求出来之后马上就被使用,不需要再从内存中加载进缓存。

第 2 步:并行部分的优化

本步的文件保存在src2\目录,运行结果如下。虽然运行前已经有预计,不过运行结果出来的时候还是感觉非常不可思议。也许这就是并行计算的魅力吧。

1
2
The programe elapsed 2.04332 s
Result check passed!
循环依赖和数据竞争的去除
1
2
3
4
5
6
7
8
9
10
11
Pdqdx_4d[p0] = -tmp[0] * worksx[0] - tmp[1] * worksx[1] - tmp[2] * worksx[2];
Pdqdy_4d[p0] = -tmp[0] * worksy[0] - tmp[1] * worksy[1] - tmp[2] * worksy[2];
Pdqdz_4d[p0] = -tmp[0] * worksz[0] - tmp[1] * worksz[1] - tmp[2] * worksz[2];
for (int y = 0; y < 3; ++y)
{
	const int q0 = p0 - d[y];
	//这里q0这个位置已经先于p0赋值了,因此直接在此之上更新即可
	Pdqdx_4d[q0] += worksx[y] * tmp[y];
	Pdqdy_4d[q0] += worksy[y] * tmp[y];
	Pdqdz_4d[q0] += worksz[y] * tmp[y];
}

以上代码串行没有问题,但是并行化就会引入循环依赖和数据竞争的问题。

  • 循环依赖:对q0这个下标的更新操作依赖于之前的循环的赋值。
  • 数据竞争:多线程同时访问p0q0会产生竞争。

最简单无脑的解决方法是设置锁/临界区/原子操作,但是这样做显然会导致严重的性能下降。因此考虑手动修改算法逻辑消除问题。

1
2
3
4
5
6
7
8
9
10
for (int y = 0; y < 3; ++y)
	if (1 <= k + kl[y] && k + kl[y] <= nk + 1 && 1 <= j + jl[y] && j + jl[y] <= nj + 1 && 1 <= i + il[y] && i + il[y] <= ni + 1)
		for (int m = mst, q1 = p1 + d[y]; m <= med; ++m)
		{
			const int p0 = p1 + m * s3, q0 = p0 + d[y], t1WORKS = q1 + ns[y] * s3, t2WORKS = t1WORKS - d0;
			const double tmp = y ? fourth * (Pq_4d[q0] + Pq_4d[q0 - d0] + Pq_4d[p0] + Pq_4d[p0 - d0]) : Pq_4d[q0 - d0];
			Pdqdx_4d[p0] += tmp * (Pxfn[t1WORKS] * Parea[t1WORKS] + Pxfn[t2WORKS] * Parea[t2WORKS]);
			Pdqdy_4d[p0] += tmp * (Pyfn[t1WORKS] * Parea[t1WORKS] + Pyfn[t2WORKS] * Parea[t2WORKS]);
			Pdqdz_4d[p0] += tmp * (Pzfn[t1WORKS] * Parea[t1WORKS] + Pzfn[t2WORKS] * Parea[t2WORKS]);
		}

如上,对于每个位置 p0 和 y,我在这里不是计算要去更新哪个位置p0-d[y],而是计算p0会被哪个位置q0=p0+d[y]更新,这样我们就同时消除了循环依赖和数据竞争问题。当然有一点不好的地方是对应的tmpworks两个变量需要重新计算,不过比起引入锁/临界区/原子操作之类比起来已经好了太多了。

循环迭代的合并

虽然 OpenMP 的使用简单无脑到#pragma omp parallel for,但是要让并行化的代码跑到最快,还是要做一些不同于串行版本的调整的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
for (int k = 1; k <= nk + 1; ++k)
	for (int j = 1; j <= nj + 1; ++j)
		for (int i = 1; i <= ni + 1; ++i)
		{
			const int p1 = i * s0 + j * s1 + k * s2;
			{/*  */}
		}
*/
#pragma omp parallel for num_threads(64)
for (int p1 = 0; p1 < s3; ++p1)
{
	const int k = p1 / s2, j = (p1 - k * s2) / s1, i = (p1 - k * s2 - j * s1) / s0;
	if (1 <= k && k <= nk + 1 && 1 <= j && j <= nj + 1 && 1 <= i && i <= ni + 1)
	{/* */}
}

原先 kji 的三层迭代被我合并到了一层。理由是,最外层的 k 只有 300 次迭代,64 各线程每个线程平均是分配到 4-5 次迭代。然而单次 k 迭代的时间其实是非常高的,因此如果只对最外层的 k 做并行化展开的话会造成严重的负载不均衡问题。此外还有一个好,就是原先串行版本中最后每一个位置上都是需要乘一个系数,然而他的迭代次数和前一个处理的循环有小的差异。在合并之后的逻辑下,只要判断是否是处于这个区间即可。合并循环同时也减少了多个循环#pragma omp parallel for之后多线程等 barrier 的时间,一举多得。

1
2
3
4
5
6
7
8
9
10
11
if (1 <= k && k <= nk && 1 <= j && j <= nj && 1 <= i && i <= ni)
{
	const double scale = 1.0 / (Pvol[p1] + Pvol[p1 - d0]);
	for (int m = mst; m <= med; ++m)
	{
		const int p0 = p1 + m * s3;
		Pdqdx_4d[p0] *= scale;
		Pdqdy_4d[p0] *= scale;
		Pdqdz_4d[p0] *= scale;
	}
}

根据测试来看,三层循环合并之前直接加#pragma omp parallel for(同时计算p0-d[y]的循环独立开)的运行时间在 2.4s 左右,说明这样的合并是能够带来肉眼可见的提速的。

阿姆达尔定律的体现

和串行部份优化的结果相比,六十四线程下加速比还不到二十倍。除了并行本身带来的开销之外,自己分析了下还有以下几个方面带来了性能下降:

  • 每一步都要计算k,i,j,并且中间有四个除法运算。整数的除法运算是非常慢的,据说需要二十个计算周期。
  • 每一轮迭代都要判断k,i,j是否在待处理区间,并且不在待处理区间的迭代就会空转,浪费了时间。
  • 为了消除数据依赖,WORKS(q1, x, y)需要单独计算,而不能用之前计算出来的矩阵works的结果,这里是最耗时的(被执行了最多次数)。

第 3 步:向量化与编译参数优化

本步的文件保存在src3\目录,运行结果如下。

1
2
The programe elapsed 0.565649 s
Result check passed!
向量化

针对 KLN 计算平台的向量化指令集,在 Makefile 的 CXXFLAGS 里面加上-xMIC-AVX512,同时在上一步的#pragma omp parallel for改成#pragma omp parallel for simd

值得一提的是,必须要在编译参数指定指令集之后才会有提速效果,否则运行速度会下降到2.8s(据此猜测向量化是四路进行的)。

编译参数优化
  • -no-prec-div,允许丢精度的浮点数除法
  • -no-prec-sqrt,允许丢精度的开方(这个程序里似乎没什么用)
  • -fp-model fast=2:允许丢精度的浮点数优化
  • -O3:最高级别的优化,比起-O2牺牲编译时间,开启一些激进的优化项目

第 4 步:运行参数优化

1
2
The programe elapsed 0.407478 s
Result check passed!

根据后来永锋放在群里的一些参考文件,一开始先按下面的语句执行,使程序分配在四个 Node 中的一个上(计算过占用内存,是小于单节点的 24GB 的,所以没问题):

1
numactl -m 1 ./FYArray.exe

结果程序反而慢到了1.8s。找到一篇博客:NUMA 架构的 CPU – 你真的用好了么?|cenalulu’s Tech Blog

根本原因是 Linux 服务器的大多数 workload 分布都是随机的:即每个线程在处理各个外部请求对应的逻辑时,所需要访问的内存是在物理上随机分布的。而 Interleave 模式就恰恰是针对这种特性将内存 page 随机打散到各个 CPU Core 上,使得每个 CPU 的负载和 Remote Access 的出现频率都均匀分布。相较 NUMA 默认的内存分配模式,死板的把内存都优先分配在线程所在 Core 上的做法,显然普遍适用性要强很多。

因此,在多线程并行的情况下,如果我们把内存和计算资源分配固定在一个 numactl 节点上的话,会增加这个节点北桥的负载,因此,反其道而行之,将其均匀打散之后反而取得了更优的性能提升。

为什么 PPT 上把分配内存绑定在一个节点上获得了性能提升?仔细研究了一下 PPT 上的分配,发现是这么一回事:PPT 上的配置只有两个 numa 节点,并且两个 node 绑定的内存和核心数量有明显差异。这时候把内存绑定到第一个 node 上,就避免了大 node 频繁访问小 node 带来的降速。而我们使用的计算节点上的四个 NUMA 是完全相同的,这时候绑定到某个(某些)NUMA 上就没有那么划算了。

1
numactl --interleave=all ./FYArray.exe

根据官方手册,这颗Intel(R) Xeon Phi(TM) CPU 7210支持 Intel64,因此登陆计算节点编译前都需要配置 icpc 的环境变量为intel64。为了省事,写了一个benchmark.sh,内容如下:

1
2
3
4
source /opt/intel/parallel_studio_xe_2018.1.038/psxevars.sh intel64
make clean
make
numactl --interleave=all ./FYArray.exe

一点感想

  • 还是觉得这个问题用 CUDA 是更加合适的方案,我的代码最后压缩到只有一个#pragma omp parallel for simd,差不多就是在用 OpenMP 去写 CUDA 了。
  • 看了一下后面检测代码正确性的preccheck函数,发现其比较的逻辑比较粗暴,就是和原始未优化代码代码的结果做暴力对比。但我个人认为,对于这个物理量梯度求解的算法而言,其实三维网格的边缘(比如 k=0,i=0,j=0 以及 k>nk,j>nj,i>ni 这块区域)这一部分计算的正确性其实不那么重要。而原始未优化代码写的也是非常「一言难尽」,比如前面的计算循环一直是循环到nk+1,最后乘系数的时候又只迭代到nk。因此,为了通过正确性检测,不得不在代码中增加了很多范围检测(例如if (1 <= k && k <= nk && 1 <= j && j <= nj && 1 <= i && i <= ni)),使得性能下降。
  • x、y、z 三个维度上的运算基本类似。因此,更优的组织方法是把 x、y、z 三维封装成一个结构体,不但有更强的内存局部性,也更方便去做 simd 的向量化(优化报告中多次提到例如irregularly indexed load was emulated for the variable <...>, part of index is read from memory),还可以做内存对齐。然而既然之前已经提供了数据的指针,重新组织数据存储、计算结束再拷贝回去的代价还是太高了(我这么做并各种调整后运行时间也需要 0.5s)。同理,优化之后调整循环次序,使得 m 在最内层;对应的多维数组的时候 m 也是在内层比较合适。
  • 做优化组第一问总共用了两天,实际工作量大概在十到十二个小时左右(串行/并行部分刚好各占一半)。总之还是因为自己菜,最开始一通乱合并循环之后的东西错了没有通过正确性检测,导致要重新来过;终于学会每一步优化都存档,每做几步都要上传测试了(最开始串行版本每次都要跑一两分钟,心疼浪费的计算资源)。另外还是非常感谢良心出题人将原数据结构FYArray展开了,不然那个蜜汁数据结构自己展开可能还要花上不少时间。
  • 其实我觉得自己在刚开始优化的时候并没有完全理解算法的每一步究竟是在做什么,差不多是在串行部份整理完成的时候才对代码的整体思路有了一个理解(原来将近十个循环确实有点难看)。
  • 英特尔的编译器优化还是非常厉害,期间也尝试了别的编译器,都要比英特尔的编译器慢。
  • 感觉高性能计算大有可为,每一次优化的结果都已经感觉是极限了,然而进一步的学习总能从柠檬里挤出一点水来。因此我觉得即使是目前的成绩仍然有提升的可能。

优化组第二题

题面

对 covariance 的代码进行优化,目标平台是 KNL 计算卡。源代码有 FORTRAN 和 C 两个版本,任选其一进行优化,优化目标是 Covariance.c 或 Covariance.f90 中的协方差计算函数(即计时部分)。

可以在 Makefile 中选定变编译的版本,下图选中的是 C 版本。

运行

执行 exe/benchmark.sh 进行算例测试,脚本中共有三个算例,第三个算例要跑的时间相当长,可以进行一定程度的优化之后再取消注释运行。

执行完毕之后,会有计时(total time)和验证(verification),当 verification 为 correct 时说明算例结果正确。

完成要求

  1. 此题作为选拔题中的附加题,为选做性质,注意是选做,面试成绩主要以必做题为基准,当然如果此题完成质量较高会有加分。
  2. (若学有余力)可以两种形式完成:
    1. 提交一份优化思路即可,其中包括对现有性能瓶颈的分析,以及给出你的解决方案。
    2. 也可直接修改代码,使用运行时间来说明你的优化效果。并在报告中说明你具体的优化方法,以及提交代码文件。

TIPS

  1. 默认使用 intel 编译器编译,所以运行之前需要通过命令source /opt/intel/parallel_studio_xe_2018.1.038/psxevars.sh来配置 Intel 编译器环境变量。
  2. 需要使用 KNL 平台进行优化,具体操作请阅读 KNL 上机指南。
  3. Linux 基础请自行熟悉。

优化的小提示

向量化计算访存优化(需要对体系结构有一定了解)指令集矩阵的常用优化手法

解答

优化后时间

2

优化前时间

第三个算例没有算完就从服务器掉线了(其实是爆 int 导致的死循环)。

1
2
3
4
5
6
7
8
9
10
11
12
exp1:
 NVAR, NROW, NV =         4000        8000          10
 total time:   0.3347000
 verification: correct
exp2:
 NVAR, NROW, NV =        12000       10000          16
 total time:    2.770200
 verification: correct
exp3:
 NVAR, NROW, NV =        50000       50000          20
Connection to asc20.asmodeus.cn closed by remote host.
Connection to asc20.asmodeus.cn closed.

Covariance.c

比较短,就直接贴代码了。 改了以下几部分:

  • IsMissingPheno这个函数有点一言难尽,里面要先判断浮点数是不是nan。但是其实有一个性质,就是nan和任何「平凡」的浮点数进行大小比较的时候结果都是false。有了这个性质,我们可以去写它的反值函数IsNotMissingPheno,这样就不用调用isnan了。
  • 此外,翻看了main.f90中数据构造部分,发现输入数据中的minx=65,因此 d 是天生大于等于 65 的。因此直接#define IsNotMissingPheno(d) ((d) > 65.001),相当粗暴。
  • 原来的两层循环,第一层是iv1,第二层是iv2,第三层ibos,这样两层循环的方式会导致大量的 CacheMiss。而且各层迭代之间没有的依赖和写冲突。这里把iv2放到最内层的循环,使得最内层循环访问的都是邻近的地址,也更方便向量化。
  • iobs*NVAR会爆int。和永锋确认之后换用long long避免了溢出。
  • NumMissing处逻辑修改,改成计算其反值RetNum,从而去掉else分支,便于simd
  • 优化了一些计算。因为除法运算比较慢,尽量减少了除法和取模运算。同理乘法也尽量用加法代替了。
  • numactl --interleave=all ./cov运行时内存均匀分布
  • _mm_malloc_mm_free,分配 64 位对齐的地址。同时,修改编译指令(见下),使得主程序传进来的地址也是 64 位对齐的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#define IsNotMissingPheno(d) ((d) > 65.001)
void findcov_(int *_NVAR, int *_NROW, int *_NV, double *_MType, double *_COV)
{
#pragma omp parallel for
#pragma vector aligned
#pragma ivdep
	for (int iv1 = 0, NVAR = *_NVAR, NROW = *_NROW, NV = *_NV; iv1 < NVAR; ++iv1)
	{
		double
			*MeanX0 = (double *)_mm_malloc(NV * sizeof(double), 64),
			*MeanX1 = (double *)_mm_malloc(NV * sizeof(double), 64),
			*Covariance = (double *)_mm_malloc(NV * sizeof(double), 64),
			*RetNum = (double *)_mm_malloc(NV * sizeof(double), 64);
#pragma omp simd
#pragma vector aligned
#pragma ivdep
		for (int iv2 = 0; iv2 < NV; ++iv2)
			MeanX0[iv2] = MeanX1[iv2] = Covariance[iv2] = RetNum[iv2] = 0;
#pragma vector aligned
#pragma ivdep
		for (double *iobs = _MType + iv1, *iobsEnd = iobs + (long long)NROW * NVAR; iobs < iobsEnd; iobs += NVAR)
		{
			const double t0 = *iobs;
			if (IsNotMissingPheno(t0))
#pragma omp simd
#pragma vector aligned
#pragma ivdep
				for (int iv2 = 0; iv2 < NV; ++iv2)
				{
					const double t1 = *(iobs + (iv1 + iv2 + 1 < NVAR ? iv2 + 1 : iv2 + 1 - NVAR));
					if (IsNotMissingPheno(t1))
						MeanX0[iv2] += t0, MeanX1[iv2] += t1, Covariance[iv2] += t0 * t1, RetNum[iv2] += 1;
				}
		}
#pragma omp simd
#pragma vector aligned
#pragma ivdep
		for (int iv2 = 0; iv2 < NV; ++iv2)
		{
			const double tmp = 1 / RetNum[iv2];
			_COV[iv1 + iv2 * NVAR] = (Covariance[iv2] - MeanX0[iv2] * MeanX1[iv2] * tmp) * tmp;
		}
		_mm_free(MeanX0);
		_mm_free(MeanX1);
		_mm_free(Covariance);
		_mm_free(RetNum);
	}
}
#undef IsNotMissingPheno

Makefile

和优化第一题差不多,几次调整之后得到最优的结果。下面只列出和第一题不同的部分。

  • -align array64byte,配合代码中的_mm_malloc_mm_free,这样代码中所有地址都 64 位对齐了,耶(原来 Fortran 直接改编译指令就可以让所有的数组地址对齐了)
  • -ipo多文件开启英特尔过程间编译(本题中毫无卵用,因为只调用了一次)
  • -std=c99,因为我把变量声明在 for 循环的头部了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FC=ifort
CC=icc
LD=ifort
OPT=
FFLAGS=-qopenmp -align array64byte -ipo
CFLAGS=-std=c99 -ipo -qopenmp -qopt-report=5 -xMIC-AVX512 -no-prec-div -no-prec-sqrt -fp-model fast=2 -O3

cov: main.o Covariance1.o Covariance${DBG}.o check.o
	${FC} ${FFLAGS} main.o Covariance1.o Covariance.o check.o -o cov
main.o: main.f90
	${FC} ${FFLAGS} -c main.f90
Covariance1.o: Covariance1.f90
	${FC} ${FFLAGS} -c Covariance1.f90
Covariance.o: Covariance.f90
#	${FC} ${FFLAGS} -c Covariance.f90
	${CC} ${CFLAGS} -c Covariance.c
check.o: check.f90
	${FC} ${FFLAGS} -c check.f90

clean:
	rm -rf *.o *.i cov

系统组

VMSetup&Module

3

如上图,wuk是我创建的非 root 用户。

分别使用环境模组加载 gcc-5.5、gcc-6.5、gcc-7.4,且均开启了 c、c++、fortran 语言支持。

用环境模组加载 intelPSXE2018/2019。

用环境模组加载了 cuda-toolkit-9.2/10.1。

4

用环境模组加载了 mpich、openmpi1/2/3/4。注意的是,由于 mpich 是通过包管理器安装的,所以安装在了默认目录。

绕坑步骤

一开始是按照题目上的顺序去安装软件的,然后再配置环境模组。事实上,完全完成系统的配置之后感觉很多过程都绕了很多。假如让我重新配置一次系统,我会按照以下步骤来:

  1. 安装系统
  2. 设置虚拟机网卡为桥接模式,开启 SSH 服务(以后步骤均可通过 SSH 远程去做)
  3. 安装包管理器 yum 扩展包、多线程下载插件、第三方软件仓库源,常用工具如 curl、tar、bzip2、environment-module、git、cmake 等
  4. yum 安装 gcc(刚安装的 CentOS 里面居然没有),这里 CentOS 默认源的 gcc 版本非常老(4.8.2),虽然不是我们要安装的版本但是需要有一个默认编译器去编译其他软件源码
  5. 安装 Intel PSXE 2018/2019,并配置对应的环境模组。psxe 安装的时候还需要一些安装的依赖包,按照安装脚本的提示去装就可以了。
  6. 源码编译安装 gcc5/6/7。这里在配置configure的时候可以设定CC=icc CXX=icpc F77=ifort FC=ifort或者加载环境模组,这样就可以使用上一步安装好的英特尔编译器了(以下同理)。同时也要配置对应版本的环境模组。
  7. yum 安装 mpich,配置对应的环境模组
  8. 源码安装openmpi-1.10.7openmpi-2.1.6openmpi-3.1.4openmpi-4.0.1。注意这里官网首页好像很难找到之前版本的下载地址,需要在地址栏手动修改链接里的版本号.同时配置对应环境模组。
  9. 安装 NVIDIA 显卡驱动(由于我的电脑不是英伟达显卡,跳过此步)
  10. rpm 安装 cuda-toolkit-9.2 和 cuda-toolkit-10.1,并配置对应版本的环境模组。

参考博客

一点感想

  • 发现最后一个参考博客的博主是中大 ASC18 队员…
  • gcc 编译时间是真的久。
  • OpenMPI 编译时间也很久。
  • 很多操作报 Error 之后重新执行一遍就好了…
  • 一开始题意理解错了,以为两个系统是要一个 UbuntuServer 一个 CentOS。后来和永锋吐槽的时候说只用配置一个系统,第二个可以直接硬盘拷贝…
  • 然而硬盘拷贝时间也是非常久,因为我自己电脑存储空间不够(总共 240G 且剩余不到一半),因此专门买了移动硬盘用于虚拟机…然而移动硬盘(心理感觉)是真的慢。克隆硬盘大概花了两个小时。
  • 直接在虚拟机上配置不大爽。结合之前的优化题做题经历,我发现 VSCode 的 Remote SSH 插件意外的舒适。因此尝试在虚拟机上开启 SSH 服务,并将虚拟机的网卡设置为桥接,再配置静态 IP 地址,成功开启了虚拟机的 SSH 服务。
  • 用 SSH 远程配置还有一个好处,就是一个窗口正在下载/编译的时候,可以新开一个终端重新登陆主机,尝试配置下一项项目或者做一些其他不占资源的任务(不幸的是yum install被单线程锁定不能多开)。
  • 遇到了使用 SSH 导致环境变量设置错误的问题,然而又找到了解决方案
  • MPI 库安装完成后发现运行不了,报错信息 ImportError: /lib64/libstdc++.so.6: version `CXXABI_1.3.9’ not found (required by…………),根据链接里的方案解决了。
  • 由于暑假还在参加 ACM 集训,导致真正有空准备 ASC 选拔的时间只有两个礼拜左右,于是系统组还有很多看起来蛮有意思额外选项都没有继续摸索。
  • 护肝养生重要。

HPL & HPCG

我本地机器的性能较弱,运行在提供的 kn103 节点上了。

MPI Version HPL

以下为我调的参数,运行性能大概在1.73168e+03GFlops,(N,NB,P,Q)=(44800,256,1,1)。P 和 Q 取 1 是因为只有一个计算节点。

顺便同步录下还有另外一个 linpack 是不调参的版本,跑了一下结果在1.76168e+03GFlops…参考链接上说调参版本调参得当的话可以比不调参的快,我还是太菜了啊…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
$ numactl --interleave=all mpirun -n 1 -env OMP_NUM_THREADS=64 ./xhpl_intel64_static
Number of Intel(R) Xeon Phi(TM) coprocessors : 0
================================================================================
HPLinpack 2.1  --  High-Performance Linpack benchmark  --   October 26, 2012
Written by A. Petitet and R. Clint Whaley,  Innovative Computing Laboratory, UTK
Modified by Piotr Luszczek, Innovative Computing Laboratory, UTK
Modified by Julien Langou, University of Colorado Denver
================================================================================

An explanation of the input/output parameters follows:
T/V    : Wall time / encoded variant.
N      : The order of the coefficient matrix A.
NB     : The partitioning blocking factor.
P      : The number of process rows.
Q      : The number of process columns.
Time   : Time in seconds to solve the linear system.
Gflops : Rate of execution for solving the linear system.

The following parameter values will be used:

N        :   44800
NB       :     256
PMAP     : Row-major process mapping
P        :       1
Q        :       1
PFACT    :   Right
NBMIN    :       2
NDIV     :       2
RFACT    :   Crout
BCAST    :   1ring
DEPTH    :       0
SWAP     : Binary-exchange
L1       : no-transposed form
U        : no-transposed form
EQUIL    : no
ALIGN    :    8 double precision words

--------------------------------------------------------------------------------

- The matrix A is randomly generated for each test.
- The following scaled residual check will be computed:
      ||Ax-b||_oo / ( eps * ( || x ||_oo * || A ||_oo + || b ||_oo ) * N )
- The relative machine precision (eps) is taken to be               1.110223e-16
- Computational tests pass if scaled residuals are less than                16.0

knl03           : Column=000256 Fraction=0.005 Kernel=    0.04 Mflops=9125140.13
knl03           : Column=000512 Fraction=0.010 Kernel=2008572.25 Mflops=3304572.65
knl03           : Column=000768 Fraction=0.015 Kernel=1846508.59 Mflops=2622302.41
knl03           : Column=001024 Fraction=0.020 Kernel=1878283.68 Mflops=2389744.02
knl03           : Column=001280 Fraction=0.025 Kernel=1736789.56 Mflops=2226222.24
knl03           : Column=001536 Fraction=0.030 Kernel=1719992.88 Mflops=2125001.75
knl03           : Column=001792 Fraction=0.035 Kernel=1718810.85 Mflops=2057943.82
knl03           : Column=002048 Fraction=0.040 Kernel=1737734.61 Mflops=2013453.91
knl03           : Column=002304 Fraction=0.050 Kernel=1739224.75 Mflops=1980375.61
knl03           : Column=002560 Fraction=0.055 Kernel=1728167.39 Mflops=1953365.20
knl03           : Column=002816 Fraction=0.060 Kernel=1723727.41 Mflops=1931341.89
knl03           : Column=003072 Fraction=0.065 Kernel=1736854.95 Mflops=1914626.72
knl03           : Column=003328 Fraction=0.070 Kernel=1725443.04 Mflops=1899732.25
knl03           : Column=003584 Fraction=0.075 Kernel=1747580.83 Mflops=1888883.18
knl03           : Column=003840 Fraction=0.080 Kernel=1715036.41 Mflops=1877243.15
knl03           : Column=004096 Fraction=0.090 Kernel=1740938.36 Mflops=1868907.23
knl03           : Column=004352 Fraction=0.095 Kernel=1731355.18 Mflops=1861032.42
knl03           : Column=004608 Fraction=0.100 Kernel=1737828.51 Mflops=1854463.64
knl03           : Column=004864 Fraction=0.105 Kernel=1725133.62 Mflops=1847950.80
knl03           : Column=005120 Fraction=0.110 Kernel=1746297.29 Mflops=1843191.89
knl03           : Column=005376 Fraction=0.115 Kernel=1732698.30 Mflops=1838274.41
knl03           : Column=005632 Fraction=0.120 Kernel=1724115.61 Mflops=1833447.50
knl03           : Column=005888 Fraction=0.130 Kernel=1757096.18 Mflops=1830443.92
knl03           : Column=006144 Fraction=0.135 Kernel=1739172.48 Mflops=1826998.94
knl03           : Column=006400 Fraction=0.140 Kernel=1727269.05 Mflops=1823393.83
knl03           : Column=006656 Fraction=0.145 Kernel=1732452.87 Mflops=1820270.75
knl03           : Column=006912 Fraction=0.150 Kernel=1757082.91 Mflops=1818227.95
knl03           : Column=007168 Fraction=0.155 Kernel=1738535.72 Mflops=1815739.28
knl03           : Column=007424 Fraction=0.160 Kernel=1721469.96 Mflops=1812894.86
knl03           : Column=007680 Fraction=0.170 Kernel=1740963.92 Mflops=1810838.49
knl03           : Column=007936 Fraction=0.175 Kernel=1762457.39 Mflops=1809527.47
knl03           : Column=008192 Fraction=0.180 Kernel=1717576.54 Mflops=1807073.24
knl03           : Column=008448 Fraction=0.185 Kernel=1758191.15 Mflops=1805847.90
knl03           : Column=008704 Fraction=0.190 Kernel=1722131.58 Mflops=1803787.37
knl03           : Column=008960 Fraction=0.195 Kernel=1762073.52 Mflops=1802820.99
knl03           : Column=009216 Fraction=0.200 Kernel=1720682.59 Mflops=1800943.85
knl03           : Column=009472 Fraction=0.210 Kernel=1748822.75 Mflops=1799813.67
knl03           : Column=009728 Fraction=0.215 Kernel=1738635.17 Mflops=1798526.20
knl03           : Column=009984 Fraction=0.220 Kernel=1736779.47 Mflops=1797270.30
knl03           : Column=010240 Fraction=0.225 Kernel=1749420.77 Mflops=1796336.78
knl03           : Column=010496 Fraction=0.230 Kernel=1739225.65 Mflops=1795253.46
knl03           : Column=010752 Fraction=0.235 Kernel=1745513.98 Mflops=1794344.23
knl03           : Column=011008 Fraction=0.240 Kernel=1755111.91 Mflops=1793654.00
knl03           : Column=011264 Fraction=0.250 Kernel=1751449.64 Mflops=1792933.62
knl03           : Column=011520 Fraction=0.255 Kernel=1728545.47 Mflops=1791855.27
knl03           : Column=011776 Fraction=0.260 Kernel=1740681.63 Mflops=1791030.71
knl03           : Column=012032 Fraction=0.265 Kernel=1748045.64 Mflops=1790362.18
knl03           : Column=012288 Fraction=0.270 Kernel=1718097.65 Mflops=1789253.68
knl03           : Column=012544 Fraction=0.275 Kernel=1735026.20 Mflops=1788454.79
knl03           : Column=012800 Fraction=0.280 Kernel=1752253.77 Mflops=1787942.39
knl03           : Column=013056 Fraction=0.290 Kernel=1728479.74 Mflops=1787114.39
knl03           : Column=013312 Fraction=0.295 Kernel=1726641.95 Mflops=1786296.14
knl03           : Column=013568 Fraction=0.300 Kernel=1741260.25 Mflops=1785709.38
knl03           : Column=013824 Fraction=0.305 Kernel=1727933.53 Mflops=1784972.67
knl03           : Column=014080 Fraction=0.310 Kernel=1730959.53 Mflops=1784304.77
knl03           : Column=014336 Fraction=0.315 Kernel=1749990.42 Mflops=1783896.92
knl03           : Column=014592 Fraction=0.320 Kernel=1726802.88 Mflops=1783228.57
knl03           : Column=014848 Fraction=0.330 Kernel=1756663.81 Mflops=1782931.39
knl03           : Column=015104 Fraction=0.335 Kernel=1730426.16 Mflops=1782351.68
knl03           : Column=015360 Fraction=0.340 Kernel=1741855.43 Mflops=1781919.75
knl03           : Column=015616 Fraction=0.345 Kernel=1727521.28 Mflops=1781350.82
knl03           : Column=015872 Fraction=0.350 Kernel=1726799.50 Mflops=1780795.69
knl03           : Column=016128 Fraction=0.355 Kernel=1720151.74 Mflops=1780193.08
knl03           : Column=016384 Fraction=0.360 Kernel=1755139.81 Mflops=1779955.69
knl03           : Column=016640 Fraction=0.370 Kernel=1739962.81 Mflops=1779583.74
knl03           : Column=016896 Fraction=0.375 Kernel=1732330.78 Mflops=1779154.23
knl03           : Column=017152 Fraction=0.380 Kernel=1730688.25 Mflops=1778725.13
knl03           : Column=017408 Fraction=0.385 Kernel=1743678.69 Mflops=1778425.38
knl03           : Column=017664 Fraction=0.390 Kernel=1717326.99 Mflops=1777909.03
knl03           : Column=017920 Fraction=0.395 Kernel=1703337.02 Mflops=1777290.69
knl03           : Column=018176 Fraction=0.400 Kernel=1724933.57 Mflops=1776873.42
knl03           : Column=018432 Fraction=0.410 Kernel=1746749.97 Mflops=1776642.64
knl03           : Column=018688 Fraction=0.415 Kernel=1723368.85 Mflops=1776239.99
knl03           : Column=018944 Fraction=0.420 Kernel=1726898.28 Mflops=1775877.73
knl03           : Column=019200 Fraction=0.425 Kernel=1733791.22 Mflops=1775578.15
knl03           : Column=019456 Fraction=0.430 Kernel=1730001.06 Mflops=1775261.66
knl03           : Column=019712 Fraction=0.435 Kernel=1705207.01 Mflops=1774781.31
knl03           : Column=019968 Fraction=0.440 Kernel=1725985.26 Mflops=1774459.56
knl03           : Column=020224 Fraction=0.450 Kernel=1719324.18 Mflops=1774104.36
knl03           : Column=020480 Fraction=0.455 Kernel=1711277.53 Mflops=1773708.60
knl03           : Column=020736 Fraction=0.460 Kernel=1722823.78 Mflops=1773398.74
knl03           : Column=020992 Fraction=0.465 Kernel=1711917.64 Mflops=1773032.11
knl03           : Column=021248 Fraction=0.470 Kernel=1717266.20 Mflops=1772709.52
knl03           : Column=021504 Fraction=0.475 Kernel=1701002.10 Mflops=1772302.09
knl03           : Column=021760 Fraction=0.480 Kernel=1719763.47 Mflops=1772014.82
knl03           : Column=022016 Fraction=0.490 Kernel=1731109.95 Mflops=1771798.66
knl03           : Column=022272 Fraction=0.495 Kernel=1682021.84 Mflops=1771323.77
knl03           : Column=023296 Fraction=0.515 Kernel=1719554.11 Mflops=1770331.22
knl03           : Column=024064 Fraction=0.535 Kernel=1701814.35 Mflops=1769427.25
knl03           : Column=025088 Fraction=0.555 Kernel=1699066.40 Mflops=1768308.43
knl03           : Column=025856 Fraction=0.575 Kernel=1700560.79 Mflops=1767579.13
knl03           : Column=026880 Fraction=0.595 Kernel=1691589.61 Mflops=1766594.75
knl03           : Column=027648 Fraction=0.615 Kernel=1675918.19 Mflops=1765797.04
knl03           : Column=028672 Fraction=0.635 Kernel=1666525.98 Mflops=1764753.58
knl03           : Column=029440 Fraction=0.655 Kernel=1654181.57 Mflops=1763973.06
knl03           : Column=030464 Fraction=0.675 Kernel=1649915.87 Mflops=1763023.58
knl03           : Column=031232 Fraction=0.695 Kernel=1670719.93 Mflops=1762523.87
knl03           : Column=035840 Fraction=0.795 Kernel=1584903.45 Mflops=1758594.31
knl03           : Column=040192 Fraction=0.895 Kernel=989210.43 Mflops=1749180.75
================================================================================
T/V                N    NB     P     Q               Time                 Gflops
--------------------------------------------------------------------------------
WR00C2R2       44800   256     1     1              34.62            1.73168e+03
HPL_pdgesv() start time Thu Aug 15 12:44:56 2019

HPL_pdgesv() end time   Thu Aug 15 12:45:31 2019

--------------------------------------------------------------------------------
||Ax-b||_oo/(eps*(||A||_oo*||x||_oo+||b||_oo)*N)=        0.0042951 ...... PASSED
================================================================================

Finished      1 tests with the following results:
              1 tests completed and passed residual checks,
              0 tests completed and failed residual checks,
              0 tests skipped because of illegal input values.
--------------------------------------------------------------------------------

End of Tests.
================================================================================

HPCG

这里使用默认配置如下(这一题好像只有四个参数可调,然后就没去管它了)。

1
2
$ mpirun -n 1 -env OMP_NUM_THREADS=64 ./xhpcg_knl
HPCG result is VALID with a GFLOP/s rating of 37.717879

Distributed File System

在之前配置系统的时候,为了方便用 SSH 访问,我的虚拟机的网卡是桥接在宿主机上的,它们的静态 IP 地址如下。

IP 地址 对应机器
192.168.56.1 宿主机
172.26.76.119 用于 NFS 服务器
172.26.36.158 NFS 客户端

服务器的配置按照上面链接里的步骤很顺利地做完了。发现系统里连showmount都没有…CentOS4 个 G 的安装包里面到底都是些什么啊(习惯了什么指令都没有,但还是想吐槽)…

1
yum install -y showmount

成功挂载 NFS。

1
2
3
4
5
[root@localhost ~]# showmount -e 172.26.76.119
Export list for 172.26.76.119:
/home/share 172.26.36.158
[root@localhost ~]# mkdir -p /mnt/share
[root@localhost ~]# mount -t nfs 172.26.76.119:/home/share /mnt/share/ -o nolock,nfsvers=3,vers=3

推测把软件make install在共享的目录下,在客户机上的环境模组里面改一下地址变量就可以加载服务器上的软件了,就没做了(实在是不想从头编译那些软件了…心疼电脑风扇)。

安装GlusterFS也没有遇到多大波折,唯一遇到问题的地方是 CentOS 默认源里没有glusterfs-server,需要先把完整版本装进来。

1
yum install -y centos-release-gluster*
1
2
3
4
5
6
7
8
9
[root@localhost glusterfs]# systemctl start glusterd
[root@localhost glusterfs]# systemctl enable glusterd
Created symlink from /etc/systemd/system/multi-user.target.wants/glusterd.service to /usr/lib/systemd/system/glusterd.service.
[root@localhost glusterfs]#  gluster peer probe 172.26.76.119
peer probe: success.
[root@localhost glusterfs]# gluster pool list
UUID                                    Hostname        State
694ffa9c-97dc-4b84-94b1-6919def4abbf    172.26.76.119   Connected
9781afb0-05d5-44df-a26d-1cdc05f267c1    localhost       Connected

GlusterFS 支持多种配置的分布式存储。我这里先和上面博客一样做一个 2 副本的 replicated volume 了。剩下的过程和博客差不多,最终测试文件在两个节点里各有一份拷贝。

MPI Benchmark

单机下的 mpi 环境配好了,可是多机情况下却摸索了很久…先要配置 SSH 公钥使得同一网络下的主机可以直接登陆,然后将两台虚拟机的 ip 地址保存到/etc/hosts,最后在运行参数里手动指定-machinefile或者host

这里遇到一个问题,笔记本连校园网的时候多机运行不成功。最后只好连手机热点了。

顺便庆幸自己先做了最后一问的分布式文件系统,这样只要把运行的文件放在 NFS 挂载的目录下就不用多台机器复制同一个编译后文件到同一目录了。

1
mpirun -n 2 ./IMB-EXT -machinefile machine.txt

通过阅读imb目录下的ReadMe_IMB.txt文件,该目录下有多项测试。这里放出运行IMB-EXT的结果one-sided communications benchmarks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
[root@localhost imb]# mpirun -n 2 -machinefile machine.txt ./IMB-EXT

#------------------------------------------------------------
#    Intel(R) MPI Benchmarks 2019 Update 3, MPI-2 part
#------------------------------------------------------------
# Date                  : Mon Aug 19 23:41:54 2019
# Machine               : x86_64
# System                : Linux
# Release               : 3.10.0-957.27.2.el7.x86_64
# Version               : #1 SMP Mon Jul 29 17:46:05 UTC 2019
# MPI Version           : 3.1
# MPI Thread Environment:


# Calling sequence was:

# ./IMB-EXT

# Minimum message length in bytes:   0
# Maximum message length in bytes:   4194304
#
# MPI_Datatype                   :   MPI_BYTE
# MPI_Datatype for reductions    :   MPI_FLOAT
# MPI_Op                         :   MPI_SUM
#
#

# List of Benchmarks to run:

# Window
# Unidir_Get
# Unidir_Put
# Bidir_Get
# Bidir_Put
# Accumulate

#----------------------------------------------------------------
# Benchmarking Window
# #processes = 2
#----------------------------------------------------------------
       #bytes #repetitions  t_min[usec]  t_max[usec]  t_avg[usec]
            0          100      1403.72      1406.68      1405.20
            4          100      1371.82      1372.18      1372.00
            8          100      1492.68      1493.16      1492.92
           16          100      1552.52      1553.81      1553.16
           32          100      1373.03      1374.06      1373.55
           64          100      1415.10      1415.31      1415.20
          128          100      1461.03      1461.18      1461.11
          256          100      1459.94      1461.21      1460.57
          512          100      1576.40      1584.17      1580.28
         1024          100      1753.37      1753.62      1753.50
         2048          100      1099.08      1099.14      1099.11
         4096          100      1142.49      1142.99      1142.74
         8192          100      1089.42      1091.36      1090.39
        16384          100      1129.67      1132.30      1130.99
        32768          100      1162.14      1169.32      1165.73
        65536          100      1185.38      1188.01      1186.69
       131072          100      1113.56      1114.80      1114.18
       262144          100      1537.35      1537.38      1537.37
       524288           80      1255.55      1255.59      1255.57
      1048576           40      1154.01      1158.06      1156.04
      2097152           20      1365.64      1373.79      1369.71
      4194304           10      1559.95      1579.93      1569.94

#---------------------------------------------------
# Benchmarking Unidir_Get
# #processes = 2
#---------------------------------------------------
#
#    MODE: AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0         1000         0.35         0.00
            4         1000        37.47         0.11
            8         1000        57.33         0.14
           16         1000        47.62         0.34
           32         1000        36.48         0.88
           64         1000        37.80         1.69
          128         1000        19.91         6.43
          256         1000        25.98         9.85
          512         1000        21.15        24.20
         1024         1000        37.62        27.22
         2048         1000        78.56        26.07
         4096         1000        70.22        58.33
         8192         1000        87.98        93.12
        16384         1000       164.27        99.74
        32768         1000       206.92       158.36
        65536          640       543.38       120.61
       131072          320       729.33       179.72
       262144          160      1718.96       152.50
       524288           80      3067.05       170.94
      1048576           40      5192.29       201.95
      2097152           20     11262.97       186.20
      4194304           10     23979.74       174.91

#---------------------------------------------------
# Benchmarking Unidir_Get
# #processes = 2
#---------------------------------------------------
#
#    MODE: NON-AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0          100       505.19         0.00
            4          100       860.93         0.00
            8          100       700.01         0.01
           16          100       655.33         0.02
           32          100       706.68         0.05
           64          100       915.70         0.07
          128          100       580.05         0.22
          256          100      1085.79         0.24
          512          100       535.91         0.96
         1024          100       603.03         1.70
         2048          100       467.67         4.38
         4096          100       504.24         8.12
         8192          100       611.90        13.39
        16384          100       618.52        26.49
        32768          100       637.86        51.37
        65536          100       845.38        77.52
       131072          100      2537.87        51.65
       262144          100      1666.37       157.31
       524288           80      4259.63       123.08
      1048576           40      5102.06       205.52
      2097152           20     12013.16       174.57
      4194304           10     25326.92       165.61

#---------------------------------------------------
# Benchmarking Unidir_Put
# #processes = 2
#---------------------------------------------------
#
#    MODE: AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0         1000         1.94         0.00
            4         1000         7.87         0.51
            8         1000         7.56         1.06
           16         1000         7.76         2.06
           32         1000        11.13         2.88
           64         1000        24.55         2.61
          128         1000         9.34        13.70
          256         1000        15.02        17.04
          512         1000        20.35        25.16
         1024         1000        33.35        30.71
         2048         1000        41.05        49.89
         4096         1000        64.89        63.12
         8192         1000        99.42        82.40
        16384         1000        85.15       192.42
        32768         1000       240.36       136.33
        65536          640       422.28       155.20
       131072          320       668.78       195.99
       262144          160      1671.81       156.80
       524288           80      3236.54       161.99
      1048576           40      5575.72       188.06
      2097152           20     11934.73       175.72
      4194304           10     23992.82       174.81

#---------------------------------------------------
# Benchmarking Unidir_Put
# #processes = 2
#---------------------------------------------------
#
#    MODE: NON-AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0          100       282.07         0.00
            4          100       414.72         0.01
            8          100       487.02         0.02
           16          100       422.30         0.04
           32          100       640.98         0.05
           64          100       470.09         0.14
          128          100       878.88         0.15
          256          100       918.08         0.28
          512          100      1004.25         0.51
         1024          100       631.68         1.62
         2048          100       941.49         2.18
         4096          100       896.53         4.57
         8192          100       871.60         9.40
        16384          100       604.04        27.12
        32768          100       878.96        37.28
        65536          100       670.42        97.75
       131072          100      1236.28       106.02
       262144          100      1937.21       135.32
       524288           80      3061.06       171.28
      1048576           40      6934.68       151.21
      2097152           20     10520.35       199.34
      4194304           10     23918.25       175.36

#---------------------------------------------------
# Benchmarking Bidir_Get
# #processes = 2
#---------------------------------------------------
#
#    MODE: AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0         1000         0.58         0.00
            4         1000        14.36         0.28
            8         1000        19.92         0.40
           16         1000        42.29         0.38
           32         1000        16.94         1.89
           64         1000        33.56         1.91
          128         1000        31.63         4.05
          256         1000        36.81         6.95
          512         1000        41.97        12.20
         1024         1000        36.43        28.11
         2048         1000        54.35        37.68
         4096         1000       162.54        25.20
         8192         1000       166.63        49.16
        16384         1000       258.75        63.32
        32768         1000       418.11        78.37
        65536          640       459.10       142.75
       131072          320      1225.63       106.94
       262144          160      1948.36       134.55
       524288           80      4169.02       125.76
      1048576           40      8133.14       128.93
      2097152           20     18691.10       112.20
      4194304           10     30663.20       136.79

#---------------------------------------------------
# Benchmarking Bidir_Get
# #processes = 2
#---------------------------------------------------
#
#    MODE: NON-AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0          100       350.20         0.00
            4          100       870.16         0.00
            8          100       930.82         0.01
           16          100      1099.50         0.01
           32          100       911.81         0.04
           64          100       858.79         0.07
          128          100       816.23         0.16
          256          100       924.43         0.28
          512          100       797.45         0.64
         1024          100      1351.76         0.76
         2048          100      1059.61         1.93
         4096          100       654.34         6.26
         8192          100       770.59        10.63
        16384          100       762.31        21.49
        32768          100       798.65        41.03
        65536          100      1296.03        50.57
       131072          100      1706.00        76.83
       262144          100      2303.22       113.82
       524288           80      4426.38       118.45
      1048576           40      8764.67       119.64
      2097152           20     13678.57       153.32
      4194304           10     32218.98       130.18

#---------------------------------------------------
# Benchmarking Bidir_Put
# #processes = 2
#---------------------------------------------------
#
#    MODE: AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0         1000         0.53         0.00
            4         1000        64.34         0.06
            8         1000        86.13         0.09
           16         1000        73.03         0.22
           32         1000        80.30         0.40
           64         1000         8.45         7.58
          128         1000        20.96         6.11
          256         1000        15.38        16.65
          512         1000        33.35        15.35
         1024         1000        43.04        23.79
         2048         1000        49.67        41.23
         4096         1000        77.21        53.05
         8192         1000        90.80        90.22
        16384         1000       150.81       108.64
        32768         1000       300.54       109.03
        65536          640       593.10       110.50
       131072          320      1257.66       104.22
       262144          160      2356.17       111.26
       524288           80      4088.90       128.22
      1048576           40      7763.74       135.06
      2097152           20     13998.02       149.82
      4194304           10     29054.57       144.36

#---------------------------------------------------
# Benchmarking Bidir_Put
# #processes = 2
#---------------------------------------------------
#
#    MODE: NON-AGGREGATE
#
       #bytes #repetitions      t[usec]   Mbytes/sec
            0          100       581.56         0.00
            4          100       993.12         0.00
            8          100       823.19         0.01
           16          100       967.19         0.02
           32          100       829.17         0.04
           64          100       797.47         0.08
          128          100       874.61         0.15
          256          100       805.71         0.32
          512          100       672.68         0.76
         1024          100       456.21         2.24
         2048          100       617.82         3.31
         4096          100       517.67         7.91
         8192          100       522.99        15.66
        16384          100       572.82        28.60
        32768          100       786.58        41.66
        65536          100       946.46        69.24
       131072          100      2420.10        54.16
       262144          100      2551.87       102.73
       524288           80      3654.18       143.48
      1048576           40      8323.86       125.97
      2097152           20     14392.07       145.72
      4194304           10     28081.68       149.36

#----------------------------------------------------------------
# Benchmarking Accumulate
# #processes = 2
#----------------------------------------------------------------
#
#    MODE: AGGREGATE
#
       #bytes #repetitions  t_min[usec]  t_max[usec]  t_avg[usec]
            0         1000         0.43         0.51         0.47
            4         1000         5.42         5.62         5.52
            8         1000        11.94        12.14        12.04
           16         1000         7.37         8.33         7.85
           32         1000         9.77        10.05         9.91
           64         1000         9.95         9.99         9.97
          128         1000        10.59        11.69        11.14
          256         1000         7.30        14.39        10.84
          512         1000         8.99        20.33        14.66
         1024         1000        17.23        29.60        23.42
         2048         1000        31.66        37.68        34.67
         4096         1000        34.76        36.94        35.85
         8192         1000        92.53        94.01        93.27
        16384         1000        94.56        97.34        95.95
        32768         1000       224.07       226.93       225.50
        65536          640       413.55       416.15       414.85
       131072          320       890.87       891.42       891.14
       262144          160      1539.97      1541.22      1540.60
       524288           80      3032.38      3075.55      3053.97
      1048576           40      6516.13      6554.05      6535.09
      2097152           20     12038.61     12172.17     12105.39
      4194304           10     27524.28     27610.04     27567.16

#----------------------------------------------------------------
# Benchmarking Accumulate
# #processes = 2
#----------------------------------------------------------------
#
#    MODE: NON-AGGREGATE
#
       #bytes #repetitions  t_min[usec]  t_max[usec]  t_avg[usec]
            0          100       439.95       443.00       441.47
            4          100       474.63       475.28       474.96
            8          100       541.94       542.50       542.22
           16          100       448.52       449.82       449.17
           32          100       450.10       450.75       450.43
           64          100       483.85       484.50       484.18
          128          100       439.85       440.49       440.17
          256          100       597.58       597.66       597.62
          512          100       536.01       539.24       537.62
         1024          100       441.78       442.33       442.05
         2048          100       561.88       566.52       564.20
         4096          100       638.56       640.12       639.34
         8192          100       593.92       602.88       598.40
        16384          100       638.56       656.32       647.44
        32768          100       649.16       669.93       659.55
        65536          100       586.46       600.62       593.54
       131072          100      1084.49      1096.54      1090.51
       262144          100      2010.86      2024.91      2017.88
       524288           80      3072.98      3079.71      3076.35
      1048576           40      6330.86      6334.87      6332.87
      2097152           20     10342.87     10358.13     10350.50
      4194304           10     21857.79     21934.06     21895.92


# All processes entering MPI_Finalize

根据上面博文所说,还有在使用 IntelMPI 的时候可以配置InfiniBand来优化连接带宽。这里略过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@localhost pt2pt]# mpirun -host centos1,centos2 -n 2 ./osu_bibw

# OSU MPI Bi-Directional Bandwidth Test v5.4.3
# Size      Bandwidth (MB/s)
1                       0.03
2                       0.06
4                       0.10
8                       0.30
16                      0.59
32                      1.09
64                      2.44
128                     3.86
256                     6.20
512                     9.56
1024                   17.52
2048                   30.87
4096                   65.83
8192                  115.35
16384                 162.66
32768                 244.40
65536                 296.09
131072                277.40
262144                258.82
524288                263.98
1048576               269.99
2097152               264.29
4194304               302.26

FLUIDITY

首先根据前面安装其他软件的经验,直接尝试一下解压之后./configure & make & make install。果然第一步就报错了…提示缺少某个 python 开发版本的包(?)…

1
2
3
4
5
6
7
8
9
10
11
12
13
configure: error: in `/home/fluidity/SRC/fluidity-4.1.12':
configure: error:
  Could not link test program to Python. Maybe the main Python library has been
  installed in some non-standard library path. If so, pass it to configure,
  via the LDFLAGS environment variable.
  Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
  ============================================================================
   ERROR!
   You probably have to install the development version of the Python package
   for your distribution.  The exact name of this package varies among them.
  ============================================================================

See `config.log' for more details

干脆把 python 相关的包都装起来(几千个好多啊)…

1
yum install -y python-*

一觉醒来发现发现又报 Error 了…

1
2
3
4
5
6
7
8
9
10
11
12
Downloading packages:
Delta RPMs disabled because /usr/bin/applydeltarpm not installed.
Running transaction check
Running transaction test


Transaction check error:
  file /usr/lib/python2.7/site-packages/tests/__init__.pyc conflicts between attempted installs of python-ipmi-0.4.1-3.el7.noarch and python-django-federated-login-1.0.0-1.el7.noarch
  file /usr/lib/python2.7/site-packages/tests/__init__.pyo conflicts between attempted installs of python-ipmi-0.4.1-3.el7.noarch and python-django-federated-login-1.0.0-1.el7.noarch

错误概要
-------------

在 GitHub 上面找到了这个项目FluidityProject/fluidity…然后就找到了wiki,顺便找到了官方主页

按照官方 QA,进行到这一步报错。

1
2
3
4
5
6
7
$ yum-config-manager --add-repo http://fluidityproject.github.com/yum/fluidity-rhel7.repo
Failed to set locale, defaulting to C
Loaded plugins: axelget, fastestmirror,
              : priorities
adding repo from: http://fluidityproject.github.com/yum/fluidity-rhel7.repo
grabbing file http://fluidityproject.github.com/yum/fluidity-rhel7.repo to /etc/yum.repos.d/fluidity-rhel7.repo
Could not fetch/save url http://fluidityproject.github.com/yum/fluidity-rhel7.repo to file /etc/yum.repos.d/fluidity-rhel7.repo: [Errno 14] curl#56 - "Recv failure: Connection reset by peer"

搜了一下,大致是因为虚拟机的 IP 被白名单拦住了(?)。回到官方 GitHub 下面看看,找到这么个 Repo:FluidityProject/yum-rhel7

1
git clone https://github.com/FluidityProject/yum-rhel7.git

上面这个命令进度条卡在 4%了,只好宿主机用 guthubDesktop 下好这个 Repo 传进去(一开始直接下 zip 运行不了也不知道是什么原因)。接下来就可以用 yum 安装了。

1
2
yum-config-manager --add-repo fluidity.repo
yum install -y fluidity fluidity-*

再次报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
错误:软件包:libpetsc3-openmpi-3.8.3-4.7.x86_64 (Fluidity)
          需要:libparmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.6.3-4.7.x86_64 (Fluidity)
              libparmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.8.3-4.7.x86_64 (Fluidity)
              libparmetis.so()(64bit)
          正在安装: petsc-openmpi-devel-3.9.3-5.el7.x86_64 (epel)
              未找到
错误:软件包:fluidity-4.1.15+petsc38fixes-4.el7.centos.x86_64 (Fluidity)
          需要:libmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.6.3-4.7.x86_64 (Fluidity)
              libmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.8.3-4.7.x86_64 (Fluidity)
              libmetis.so()(64bit)
          正在安装: petsc-openmpi-devel-3.9.3-5.el7.x86_64 (epel)
              未找到
错误:软件包:fluidity-4.1.15+petsc38fixes-4.el7.centos.x86_64 (Fluidity)
          需要:libparmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.6.3-4.7.x86_64 (Fluidity)
              libparmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.8.3-4.7.x86_64 (Fluidity)
              libparmetis.so()(64bit)
          正在安装: petsc-openmpi-devel-3.9.3-5.el7.x86_64 (epel)
              未找到
错误:软件包:libpetsc3-openmpi-3.8.3-4.7.x86_64 (Fluidity)
          需要:libmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.6.3-4.7.x86_64 (Fluidity)
              libmetis.so()(64bit)
          可用: petsc-openmpi-devel-3.8.3-4.7.x86_64 (Fluidity)
              libmetis.so()(64bit)
          正在安装: petsc-openmpi-devel-3.9.3-5.el7.x86_64 (epel)
              未找到

按照上面提示petsc-openmpi-devel-3.9.3-5.el7.x86_64 (epel)是未找到的包。

1
yum install -y petsc-openmpi-devel-3.9.3

没这个包。从官网上手动下载编译安装呢?

1
2
3
4
5
6
7
8
petsc_makefile:10: /usr/lib64/openmpi/lib64/petsc/3.8.3/linux-gnu-c-opt/conf/variables: No such file or directory
petsc_makefile:11: /usr/lib64/openmpi/lib64/petsc/3.8.3/linux-gnu-c-opt/conf/rules:
No such file or directory
make: *** No rule to make target `/usr/lib64/openmpi/lib64/petsc/3.8.3/linux-gnu-c-opt/conf/rules'.  Stop.
configure: PETSc modules don't work, using headers instead.
configure: error: in `/home/fluidity/SRC/fluidity-4.1.12':
configure: error: Failed to compile and link PETSc program.
See `config.log' for more details

结果还是不行。换个编译器看看呢?

1
./configure --prefix=/usr/local/fluidity OMPI_ALLOW_RUN_AS_ROOT=1 OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 CC=icc CXX=icpc F77=ifort FC=ifort PETSC_DIR=/home/petsc PETSC_ARCH=arch-linux2-c-debug --with-mpi-dir=/usr/local/openmpi-4.0.1

果断失败了。由于这几天一直在 acm 集训和打百度之星,开始做这一项的时候(8.19)已经没几天时间了,所以一开始选择性忽略了出题人的提示「Docker」(从前只是稍微听说过 Docker 是轻量级的虚拟机技术,但是一开始觉得时间紧凑,不想再去从头学一个东西)。然而两个晚上来一直报 Error,只好上菜鸟教程重头学一个了(同时注意到官方 GitHub 新一点版本的仓库下有一个docker/的目录,猜测可以用这个来加载那些缺失的包),果然想偷一点懒都不行啊。

我又回去仔细阅读了一下官方 wiki:Running Fluidity with Docker

At present, release images are hand-rolled after new packages are released, using Dockerfiles in the FluidityProject github docker repository.

然后找到这么个仓库FluidityProject/docker,宣告了我这两天的工作都是无用功。

最后的最后,发现是有打包好的 docker 供下载的。选择了这个版本,建立的 docker 的 tag 为fl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# DockerFile for Fluidity CentOS 7
# Use a Centos7 base image
FROM fluidity/buildbot:centos7-mpich-dev-build

# This DockerFile is looked after by
MAINTAINER Tim Greaves

# Get the Fluidity source
## Temporary pull from the branch with changes for PETSc 3.8
RUN git clone -b petsc38-changes https://github.com/FluidityProject/fluidity.git
WORKDIR /home/fluidity/fluidity
# Remove Ensight which is currently missing on CentOS
RUN rm -rf tools/vtu2ensight.py tests/vtu2ensight/
# Configure and build Fluidity, tools, and manual
RUN ./configure --enable-2d-adaptivity && make && make fltools && make manual
USER root

看到-b petsc38-changes,原来 github 上是有修复前面出现那个问题的 branch 的,我又回到了原点。

1
docker run -v $PWD:/rundir -w="/rundir" -a stdout -t fl ./configuremake all

成功编译。然而这下好了,连环境变量都找不到。

1
2
3
4
5
6
[root@localhost flow_past_sphere_Re1]# docker run -v $PWD:/rundir -w="/rundir" -a stdout -t fl make preprocess run
/bin/sh: which: command not found
/bin/sh: which: command not found
/bin/sh: which: command not found
/bin/sh: which: command not found
*** ERROR ***\nThe Fluidity binaries needed to run this example can't be found.\nTo fix this either:\n\n   (a) install the Fluidity binary package if you are on Ubuntu\n   (b) compile Fluidity from source and install it in a system-accessable\n         location\n   (c) set your PATH environment variable to point to a built version of\n         Fluidity.\n\nRefer to the Fluidity manual for more instructions on any of the above,\nor contact the [email protected] mailing list.\n

高版本的FluidityRepo 下面有个新的docker/目录下有两个Dockerfile.centos,和Dockerfile.ubuntu,显然是基于两个不同环境下的。先来试试 centos 的版本。

1
2
Could not fetch/save url http://fluidityproject.github.com/yum/fluidity-rhel7.repo to file /etc/yum.repos.d/fluidity-rhel7.repo: [Errno 14] curl#56 - "Recv failure: Connection reset by peer"
The command '/bin/sh -c yum-config-manager --add-repo http://fluidityproject.github.com/yum/fluidity-rhel7.repo' returned a non-zero code: 1

和前面本机环境遇到的问题一样…再试试 Ubuntu 环境下的。

出现某些文件 apt 失败的问题。根据上面的指引,把apt-install的源换成清华源就解决问题了。这时候,能够编译的环境已经有了。

顺便吐槽 texlive 的那几个包是真的又大又烦,每次下载都是好几个上百 M 的包,每次都要等二十多分钟才能看问题有没有解决。

此外,尝试次数过多,docker build 产生的缓存把系统盘都写满了…根据这篇文章如何清理 docker 占用的磁盘空间,清理掉重新来过。

(!!!感觉自己离胜利一步之遥!虽然编译的时候满屏红色 Warning)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost flow_past_sphere_Re1]# docker run -v $PWD:/rundir -w="/rundir" -a stdout -t flu make preprocess run
**********Converting the gmsh mesh to triangle format:
gmsh2triangle unit_sphere.msh
**********Calling flredecomp in parallel with verbose log output enabled:
mpiexec -n  flredecomp -i 1 -o  -v -l flow_past_sphere_Re1 flow_past_sphere_Re1_flredecomp
----------------------------------------------------------------------------
Open MPI has detected that a parameter given to a command line
option does not match the expected format:

  Option: n
  Param:  flredecomp

This is frequently caused by omitting to provide the parameter
to an option that requires one. Please check the command line and try again.
----------------------------------------------------------------------------
Makefile:4: recipe for target 'preprocess' failed
make: *** [preprocess] Error 213

再次报错,缺少环境变量NPROCS。顺便为了省事,我是在 root 账户下操作的,因此虽然不是推荐做法,还要在运行指令里面加上--allow-run-as-root

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@localhost flow_past_sphere_Re1]# docker run -v $PWD:/rundir -w="/rundir" -a stdout -t flu make preprocess run
**********Converting the gmsh mesh to triangle format:
gmsh2triangle unit_sphere.msh
**********Calling flredecomp in parallel with verbose log output enabled:
mpiexec --allow-run-as-root -n 1 flredecomp -i 1 -o 1 -v -l flow_past_sphere_Re1 flow_past_sphere_Re1_flredecomp
Unexpected end of /proc/mounts line `overlay / overlay rw,seclabel,relatime,lowerdir=/var/lib/docker/overlay2/l/4YGTDGV5ADDR4VIU4AXNQLPVFM:/var/lib/docker/overlay2/l/XQXYPVNZKKIJ344SRT76FVX3UB:/var/lib/docker/overlay2/l/RMOQ7FWHTVC7BWXKADRXW3OOQX:/var/lib/docker/overlay2/l/HWPYNIC2L5BGG6DSLXLXEDDL5C:/var/lib/docker/overlay2/l/UCHEVIWGJ3PL2ROSRYZJY75PHY:/var/lib/docker/overlay2/l/IHKADZ7TT534D7P6GEBPXZAUOR:/var/lib/docker/overlay2/l/J77QQ25DJNMMH2DMHR2FUPIJMS:/var/lib/docker/overlay2/l/J4XJPWY6XVLLAX4QM257RWLQQE:/var/lib/docker/overlay2/l/T7GU'
Unexpected end of /proc/mounts line `HSMXSWXWTNCOT7GKKGAGFQ:/var/lib/docker/overlay2/l/UKNCE6KNK64B2YITKMQ7RFDDAR:/var/lib/docker/overlay2/l/3GTI7B6MUU5JTUQ7FHW74NA3RO:/var/lib/docker/overlay2/l/26L66F4UTYFT5WSU2TUZ54BSTW:/var/lib/docker/overlay2/l/S4FK3MOHZBCTDZUXV74VFKPTTF:/var/lib/docker/overlay2/l/TIU7DQAYLUXMGUOQHUOKZRHWQH:/var/lib/docker/overlay2/l/KIAXC44X372XADCTBKFEQJE5AC:/var/lib/docker/overlay2/l/ZQTH5AXI5XHIRRTSBB7TL4UBL4:/var/lib/docker/overlay2/l/R5XZ2WST4ZUIVHBUFPVWST4FO5:/var/lib/docker/overlay2/l/EO5NJKT4XXB7JELUFKD46ZQUUT:/v'
--------------------------------------------------------------------------
MPI_ABORT was invoked on rank 0 in communicator MPI_COMM_WORLD
with errorcode 16.

NOTE: invoking MPI_ABORT causes Open MPI to kill all MPI processes.
You may or may not see output from other processes, depending on
exactly when Open MPI kills them.
--------------------------------------------------------------------------
-------------------------------------------------------
Primary job  terminated normally, but 1 process returned
a non-zero exit code.. Per user-direction, the job has been aborted.
-------------------------------------------------------
--------------------------------------------------------------------------
mpiexec detected that one or more processes exited with non-zero status, thus causing
the job to be terminated. The first process to do so was:

  Process name: [[32949,1],0]
  Exit code:    16
--------------------------------------------------------------------------
Makefile:6: recipe for target 'preprocess' failed
make: *** [preprocess] Error 16

淦!

根据上面的内容,这回是软件 hwloc 的一个 bug,文件单行内容不能超过 512,有一条回答据说新版的hwloc修了这个 BUG?docker 会给运行的每个虚拟机生成一个很长的 hash 值,因此很容易就超过 512 了。

手动从官网上下一个安装来看看;然而还是没用。考虑手动修改/proc/mounts文件使得每行长度不超过 512 呢?

1
vim /proc/mounts

这文件是只读且被占用的…

然而这个单行长度不超过 512 的 bug 全网搜了一下都没有好的解决方案,唯一搜到的几个都像上面这个一样需要官方去更新…

emm 有点绝望了,想在官方 github 仓库发个 issule 啥的…

感觉离能运行就差一点了,我还是太菜了啊…

花絮

按关键字fluidity + Docker搜索的时候搜到了如下新闻

在超级团队对抗赛中,中山大学代表队的表现同样让人眼前一亮。中山大学队员另辟蹊径,使用了 Docker 技术制造镜像,并分发给团队中的兄弟队伍使用,避免了复杂的安装过程,最终帮助团队获得了「超级团队奖」。

前辈 NB!