如何进行mpiGraph测试

摘要

本文介绍我运行mpiGraph的过程,因为这玩意在LLNL的源码中本来就是有bug的,所以果断优化了,所以直接可以从我的Github上拉下来我的改进版直接跑。同时里面还有一些自动化脚本,可以遍历size和window,并自动调整iters数量使运行时间大于1分钟.

下载

到GitHub上下载源码即可 https://github.com/LLNL/mpiGraph

编译

编译安装主程序

unzip mpiGraph-master.zip
cd mpiGraph-master/
module load IMPI/2018.1.163-icc-18.0.1

编辑makefile

all: clean
        mpiicc -O3 -xhost -ipo -o mpiGraph mpiGraph.c

debug:
        mpiicc -g -O0 -o mpiGraph mpiGraph.c

clean:
        rm -rf mpiGraph.o mpiGraph

然后直接make

安装netpbm

wget http://hfs.sysu.tech/software/linux/mpiGraph/netpbm/netpbm-10.79.00-7.el7.x86_64.rpm
wget http://hfs.sysu.tech/software/linux/mpiGraph/netpbm/netpbm-progs-10.79.00-7.el7.x86_64.rpm
rpm2cpio netpbm-10.79.00-7.el7.x86_64.rpm | cpio -idvm
rpm2cpio netpbm-progs-10.79.00-7.el7.x86_64.rpm | cpio -idvm

运行

参数

mpiGraph <size> <iters> <window>

第一个参数size 为消息大小,单位为byte

第二个参数iters 为迭代次数

第三个参数window为每次迭代同时发送的消息的数量

srun -N 32 -p test_docker ./mpiGraph 1048576 1000 30 > mpiGraph.out

或者

mpirun -n 32 -ppn 1 -hosts cpn1,cpn2,cpn3,cpn4,cpn5,cpn6,cpn7,cpn8,cpn9,cpn10,cpn11,cpn12,cpn13,cpn14,cpn15,cpn16,cpn106,cpn107,cpn108,cpn109,cpn110,cpn111,cpn112,cpn113,cpn114,cpn115,cpn116,cpn117,cpn118,cpn119,cpn120,cpn121 ./mpiGraph 1048576 1000 30 > mpiGraph.out

后处理

export PATH=$PATH:/GPUFS/nsccgz_yfdu_16/fgn/sriov-test/mpigraph/usr/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/GPUFS/nsccgz_yfdu_16/fgn/sriov-test/mpigraph/usr/lib64
./crunch_mpiGraph mpiGraph.out

生成带图的html网页

debug

bug1

crunch_mpiGraph第120行

push @ret, sprintf("%3.1f%", $val / $base * 100);
改为
push @ret, sprintf("%3.1f%%", $val / $base * 100);

不改会出现如下bug

Missing argument in sprintf at ./crunch_mpiGraph line 120.
Invalid conversion in sprintf: end of string at ./crunch_mpiGraph line 120.

生成的HTML在有些地方会有undefined,不知道这个算不算bug

bug2

crunch_mpiGraph注释掉305行的

print HTML "<tr><td>Run by:</td><td>" . $parts[0] . " (" . $parts[4]. ")</td></tr>\n";

因为有的HPC集群上无法正确获取用户名

bug3

mpiGraph超级坑的bug,要不是openmpi给我报错了,还真发现不了它的下标写错了……

第171行两个数组下标计算错误,都多了一个-1

MPI_Testall((k+1)/2, &request_array[(k+1)/2-1], &flag_sends, &status_array[(k+1)/2-1]);

改为

MPI_Testall((k+1)/2, &request_array[(k+1)/2], &flag_sends, &status_array[(k+1)/2]);

优化

因为对小消息计时非常不准,所以使用CPU周期计时器对代码进行优化

将81行至116行的代码替换为如下

long long int CPU_FREQUENCY=2700000000;

inline long long int getCurrentCycle() {
	unsigned low, high;
	__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
	return ((unsigned long long)low) | (((unsigned long long)high)<<32);
}

#define __TIME_START__    (g_timeval__start    = getCurrentCycle())
#define __TIME_END_SEND__ (g_timeval__end_send = getCurrentCycle())
#define __TIME_END_RECV__ (g_timeval__end_recv = getCurrentCycle())
#define __TIME_USECS_SEND__ ((g_timeval__end_send - g_timeval__start) / 2700)
#define __TIME_USECS_RECV__ ((g_timeval__end_recv - g_timeval__start) / 2700)
long long int g_timeval__start, g_timeval__end_send, g_timeval__end_recv;

生成的结果说明

每一行对角线上的元素为全局带宽最大值!

超强优化

每个节点跑两个进程,一个收,一个发,以实现更精确的计时,且互不干扰

详细见代码