使用mpi4py并行化Python脚本的Profile

4
我有一个名为main_parallel.py的Python脚本,使用了mpi4py。我可以通过cli使用time来测量时间,但是如何像cProfile一样进行分析呢?我想要看到代码的每个部分调用的次数。由于cProfile只适用于串行代码,所以我不能使用它。
谢谢!
2个回答

7

正如Rob Latham所说,您可以使用cProfile。您可以将每个进程的输出保存在不同的文件中。如果您想对一个函数进行分析,可以使用以下装饰器:

from mpi4py import MPI
import cProfile

def profile(filename=None, comm=MPI.COMM_WORLD):
  def prof_decorator(f):
    def wrap_f(*args, **kwargs):
      pr = cProfile.Profile()
      pr.enable()
      result = f(*args, **kwargs)
      pr.disable()

      if filename is None:
        pr.print_stats()
      else:
        filename_r = filename + ".{}".format(comm.rank)
        pr.dump_stats(filename_r)

      return result
    return wrap_f
  return prof_decorator

@profile(filename="profile_out")
def my_function():
  # do something

每个进程的输出可以使用 snakeviz 进行可视化。

在最内层函数中使用import cProfile有什么原因吗?这样每次都会重新导入... - NichtJens
根据此处所述,导入模块是被缓存且仅在第一次导入时运行。然而,在最内层函数中保留导入的模块是没有必要的,因此你可以在顶层导入它。 - hnfl
是的,你说得对。我忘记了重新导入没有惩罚。尽管如此,这不是通常的风格...另外,添加MPI单例的导入行可能会很好,以使代码完整。编辑:我提出了一个编辑来实现这一点。 - NichtJens

5

为什么您不能使用cprofile?您尝试过了吗?

对于MPICH,我是这样运行的:

$ mpiexec -l -np 4 python -m cProfile ./simple-io.py doodad 

这会给我4组输出,但是“-l”参数在每个输出位前列出了MPI排名。注意:该“-l”参数是MPICH特定的。OpenMPI使用--tag-output。其他实现可能使用其他内容。
我看到cprofile可以带一个文件名参数。创建一个按排名分类的输出文件,然后使用统计信息处理它。
% python 
Python 2.7.10 (default, Oct 14 2015, 16:09:02) 
[GCC 5.2.1 20151010] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pstats
>>> pstats.Stats("simple-io.cprofile").sort_stats('cumulative').print_stats()

提供了大量的 cprofile 信息... 但我的小程序太微不足道,无法提供有用信息。


我的 mpiexec(来自 Ubuntu 16.04 包管理器的 1.10.2 版本)似乎没有 -l 开关。没有它,我只得到一个输出文件,显然是针对排名为 0 的进程。考虑到我的安装比你的回答更新,也许你的回答已经过时了? - NichtJens
1.10.2来自OpenMPI。我已经更新了我的答案,以反映在前面获取排名的方式是特定于实现的,并记录了两个主要的实现。谢谢。 - Rob Latham
太好了。看起来标准化的mpiexec以如此不一致的方式执行这个任务有点奇怪。我原以为它的目的是取代mpirun,因为后者由于缺乏标准化而存在这些不一致性问题... - NichtJens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接