如何进行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;
生成的结果说明
每一行对角线上的元素为全局带宽最大值!
超强优化
每个节点跑两个进程,一个收,一个发,以实现更精确的计时,且互不干扰
详细见代码