在上一篇中我们介绍了 mpi4py 中初始化和运行时设置,下面我们将介绍 mpi4py 中的 profiling。
API
下面是 mpi4py 中 profiling 相关的函数:
mpi4py.profile(name, **kargs)
MPI profiling 支持。name
是要导入的 profiler 库。其它可设置参数有:path
,一系列由字符串表示的路径,用来搜寻所用的 profiler;logfile
,profiler 所产生的日志文件前缀。在 mpi4py 中可用的 profiler 库有 MPE (Multi-Processing Environment) 和 VampirTrace。如果要使用 MPE,name
需要设置为 'mpe',此时可以通过参数 logfile
设置生成的日志文件的前缀,或等价地通过环境变量 MPE_LOGFILE_PREFIX 来设置生成的日志文件的前缀。如果使用 VampirTrace,则 name
可以设置为 'vt','vt-mpi' 和 'vt-hyb' 任意一个 profiler,此时可以通过参数 logfile
设置生成的日志文件的前缀,或等价地通过环境变量 VT_FILE_PREFIX 来设置生成的日志文件的前缀。
mpi4py.MPI.Pcontrol(int level)
MPI profiling 控制。level
参数设定 profiling 级别,level = 0 会关闭 profiling 操作,level = 1 使用默认的 profiling 详细等级, level = 2 会刷新 profile 缓冲区(有些 profiler 可能不会执行任何操作)。
MPE 简介
MPE (Multi-Processing Environment) 的主要功能是为用户提供一组性能调试、正确性验证和可视化的工具,包括:
- 用于创建日志信息的函数,所输出的日志信息供可视化工具进行处理,可视化工具包括 upshot,nupshot,jumpshot 等。
- 并行的 X-图形库。
- 用于对并行代码进行串行化控制的函数。
- 设置 Debugger 的函数。
可利用 MPE 提供的 3 种函数库——跟踪函数库、动画函数库和日志函数库进行应用程序的性能分析。
MPE 的功能非常丰富,但目前 mpi4py 仅支持使用其日志功能,所以这里只介绍日志的使用。
在创建日志文件之前,需考虑设置两个环境变量——MPE_LOG_FORMAT 和 TMPDIR。其中 MPE_LOG_FORMAT 用于定义 MPE 创建日志文件的类型,如果不设置,则默认使用 CLOG 格式。TMPDIR 定义各个进程临时存放日志数据的目录,默认目录为 /temp,为减少开销一般将其设置为当前目录。
CLOG 中包含了带时间标记的事件(events)信息,SLOG 中包含了带时间标记的状态(states)信息。在运行程序后会生成一个 *.clog2 文件,这是 MPE 库所默认使用的日志文件格式。可使用 clog2TOslog2 将该文件转换为 slog2 格式,然后就可以使用 jumpshot 打开该文件进行可视化分析。
安装和使用 MPE
有些版本的 MPICH/MPICH2 中包含 MPE。如果你所使用的 MPI 实现未包含 MPE 软件工具,则可以前往 https://www.mcs.anl.gov/research/projects/perfvis/download/index.htm 下载并使用类似下面的命令进行安装:
$ ./configure MPI_CC=mpicc CC=gcc MPI_F77=mpif77 F77=gfortran --enable-PIC --prefix=/paht/to/mpe2-x.x.x
$ make
$ make install
要在 mpi4py 程序中使用 MPE 生成日志,只需在 import MPI 之前加上类似下面的语句:
import mpi4py
mpi4py.profile('mpe‘, logfile='ring')
日志文件前缀也可以通过环境变量 MPE_LOGFILE_PREFIX 来设置。
加上以上语句后,运行 mpi4py 程序后就会生成 *.clog2 日志文件。
VampirTrace
VampirTrace 是一个可以生成并行应用程序(包括 MPI,OpenMP,Pthreads 等)的详细执行日志的开源软件库。除了以上典型的并行应用程序外,VampirTrace 还可以生成 GPU 加速的应用程序的执行日志。VampirTrace 生成的日志文件为 OTF (Open Trace Format) 格式,该格式的日志文件可以使用 Vampir 工具进行可视化分析。
安装和使用 VampirTrace
VampirTrace 已经包含在 OpenMPI (版本 1.3 及更高)中,因此,如果你使用的是高于 1.3 版本的 OpenMPI,则 VampirTrace 直接可用,在其它情况下,可以在 https://tu-dresden.de/zih/forschung/projekte/vampirtrace 下载 VampirTrace 并安装。
要在 mpi4py 程序中使用 VampirTrace 生成日志,只需在 import MPI 之前加上类似下面的语句:
import mpi4py
mpi4py.profile('vt', logfile='ring')
可以根据需要将其中的 'vt' 改为 'vt-mpi' 或者 'vt-hyb'。日志文件前缀也可以通过环境变量 VT_FILE_PREFIX 来设置。
加上以上语句后,运行 mpi4py 程序后就会生成 *.otf 日志文件。前往 https://vampir.eu/downloads 下载并安装 Vampir 后,就可以使用 vampir 工具可视化分析生成的日志文件了。
使用 mpi4py 的 profiling 功能
mpi4py 的 profiling 功能需要有 PAPI (Performance Application Programming Interface) 的支持,前往 http://icl.cs.utk.edu/papi/software/index.html 下载并安装 PAPI。
较早的 mpi4py 软件由于一些编译选项设置不合理导致 mpi4py 程序在加上 profiling 语句后不生成日志文件(程序可以正常并正确执行),不过最新的 mpi4py 已经改正了这个问题,可以在 https://bitbucket.org/mpi4py/mpi4py/overview 下载最新的 mpi4py,安装后就可以使用其 profiling 功能了。
例程
下面这个例程展示 MPE profiler 的使用。
# ring_mpe.py
"""
Demonstrates mpi4py profiling with MPE.
Run this with 8 processes like:
$ mpiexec -n 8 python ring_mpe.py
"""
import os
os.environ['MPE_LOGFILE_PREFIX'] = 'ring'
import mpi4py
mpi4py.profile('mpe')
# or
# mpi4py.profile('mpe', logfile='ring')
from mpi4py import MPI
from array import array
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
src = rank-1
dest = rank+1
if rank == 0:
src = size-1
if rank == size-1:
dest = 0
try:
from numpy import zeros
a1 = zeros(1000000, 'd')
a2 = zeros(1000000, 'd')
except ImportError:
from array import array
a1 = array('d', [0]*1000); a1 *= 1000
a2 = array('d', [0]*1000); a2 *= 1000
comm.Sendrecv(sendbuf=a1, recvbuf=a2,
source=src, dest=dest)
MPI.Request.Waitall([
comm.Isend(a1, dest=dest),
comm.Irecv(a2, source=src),
])
运行结果如下:
$ mpiexec -n 8 python ring.py
Writing logfile....
Enabling the Default clock synchronization...
Finished writing log file ring.clog2
$ clog2TOslog2 ring.clog2
...
$ jumpshot ring.slog2
在上图中可以看到消息在各个进程间的交换及执行时间。
下面这个例程展示 VampirTrace 中 vt profiler 的使用。
# ring_vt.py
"""
Demonstrates mpi4py profiling with VampirTrace.
Run this with 8 processes like:
$ mpiexec -n 8 python ring_vt.py
"""
# If you want VampirTrace to log MPI calls, you have to add the two
# lines below at the very beginning of your main bootstrap script.
import mpi4py
mpi4py.rc.threads = False
mpi4py.profile('vt', logfile='ring')
from mpi4py import MPI
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
src = rank-1
dest = rank+1
if rank == 0:
src = size-1
if rank == size-1:
dest = 0
try:
from numpy import zeros
a1 = zeros(1000000, 'd')
a2 = zeros(1000000, 'd')
except ImportError:
from array import array
a1 = array('d', [0]*1000); a1 *= 1000
a2 = array('d', [0]*1000); a2 *= 1000
comm.Sendrecv(sendbuf=a1, recvbuf=a2,
source=src, dest=dest)
MPI.Request.Waitall([
comm.Isend(a1, dest=dest),
comm.Irecv(a2, source=src),
])
运行结果如下:
$ mpiexec -n 8 python ring_vt.py
$ vampir ring.otf.
以上介绍了 mpi4py 中的 profiling,在下一篇中我们将介绍 mpi4py 中的 futures 模块。