【问题标题】:Can we get core id on which the process is running in MPI?我们可以得到进程在 MPI 中运行的核心 id 吗?
【发布时间】:2013-11-25 15:24:27
【问题描述】:

我开发了 MPI 程序,它可以在分布式环境中的不同内核上执行matrix multiplication,我可以通过获取节点的主机名来演示在不同节点上的执行。但是当我们在单节点上运行程序时,我可以获得核心 id,它演示了在多节点上的执行示例代码如下

#include"stdio.h"
#include"stdlib.h"
#include"mpi.h"

int main(int argc , char **argv)
{
int size,rank;
int a,b,c;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

if(rank==0)
{
for(i=0;i<size;i++)
{
    printf("insert a and b");
    scanf("%d",&b);
    scanf("%d",&c);
    MPI_Send(&b,1,MPI_INT,i+1,6,MPI_COMM_WORLD);
    MPI_Send(&c,1,MPI_INT,i+1,6,MPI_COMM_WORLD);
}
} 

if(rank!=0)
{
MPI_Recv(&b,1,MPI_INT,0,6,MPI_COMM_WORLD,&s);
MPI_Recv(&c,1,MPI_INT,0,6,MPI_COMM_WORLD,&s);
a=b*c;
printf("Mul = %d\n",a);
//Print name of core on which my process is running
}

MPI_Finalize();
return 0;
}

【问题讨论】:

    标签: linux gcc operating-system mpi


    【解决方案1】:

    虽然可以获得当前执行代码的逻辑处理器的 ID,但这通常是没有意义的,除非您启用 MPI 进程绑定,也称为进程固定(用英特尔的话说) .绑定(或固定)限制了每个 MPI 进程的 CPU 亲和性集,即允许该进程执行的 CPU 集。如果关联集仅包含一个逻辑 CPU,则该进程将仅在该逻辑 CPU 上执行。逻辑 CPU 通常对应于具有 SMT/超线程的 CPU 上的硬件线程或非 SMT/非超线程 CPU 上的 CPU 内核。给定包含多个逻辑 CPU 的关联集,允许调度程序迁移进程以保持集合中的 CPU 同等繁忙。默认关联集通常包括所有可用的逻辑 CPU,即可以安排进程在任何内核或硬件线程上执行。

    只有当 MPI 进程绑定到位并且每个进程都绑定到单个逻辑 CPU 时,才有意义实际向操作系统查询进程的位置。您必须查阅 MPI 实施手册以了解如何启用它。例如,使用 Open MPI,您可以执行以下操作:

    mpiexec --bind-to-core --bycore -n 120 ...
    

    --bind-to-core 告诉 Open MPI 将每个进程绑定到单个 CPU 内核,--bycore 告诉它在多插槽机器上连续分配内核(即首先在第一个插槽中分配所有内核,然后在第二个插槽中分配内核等)使用英特尔 MPI,通过将环境变量 I_MPI_PIN 设置为 1 来启用绑定(英特尔称为 pinning)。进程放置策略由I_MPI_PIN_DOMAIN 的值控制。要实现与上面显示的 Open MPI 命令行相同,可以使用 Intel MPI 进行以下操作:

    mpiexec -n 120 -env I_MPI_PIN 1 -env I_MPI_PIN_DOMAIN "core:compact" ...
    

    要以独立于平台的方式获取进程的位置,您可以使用hwloc library 中的hwloc_get_last_cpu_location()。它是作为 Open MPI 项目的一部分开发的,但可以用作独立库。它提供了一个抽象接口来查询系统拓扑和操作进程和线程的亲和性。 hwloc 支持 Linux、Windows 和许多其他操作系统。

    【讨论】:

      【解决方案2】:

      我们可以使用 utmpx.h 头文件中的 sched_getcpu() 函数来获取核心 id 来自网络的示例程序如下所示

      #include <stdio.h>
      #include<mpi.h>
      #include <utmpx.h>
      
      int main( int argc , char **argv )
      {
      MPI_Init(&argc, &argv);
      printf( "cpu = %d\n", sched_getcpu() );
      MPI_Finalize();
      return 0;
      }
      

      【讨论】:

      • 正如其man 页面所说,sched_getcpu 是特定于 Linux 的并且正在调用 getcpu ....
      【解决方案3】:

      您可以使用 Linux 特定的 getcpu(2) 系统调用(或者,如 Krishna answered,Linux 特定的 sched_getcpu(3) 函数包装它)。仔细阅读手册页(getcpu syscall 没有任何 libc 包装器!)。请注意,它可能会为您提供一些过时的信息(因为内核可以-并且确实-迁移进程或任务-例如线程-在任何时间从一个CPU内核到另一个) .

      否则,您的 MPI 实现可能正在使用线程或进程。您可以使用gettid(2)(需要一些包装器)查询线程,或使用getpid(2) 查询进程。

      您可能想要编码:

      #include <unistd.h>
      #include <asm/unistd.h>
      #include <sys/syscall.h>
      
      static inline long my_gettid(void)
      { return syscall(SYS_gettid); }
      

      getcpu.... 可能也有类似的东西。

      您也可以使用proc(5),例如查询/proc/self/stat(第 39th 字段给出了 processor 编号)...也许只显示所有这些是最简单的方法:

      {
         char line[128];
         FILE *fs = fopen("/proc/self/stat","r");
         if (!fs) { perror("/proc/self/stat"); exit(EXIT_FAILURE); };
         while (!feof(fs)) {
           memset(line, 0, sizeof(line));
           fgets(line, sizeof(line), fs);
           fputs(line, stdout);
         };
         fclose(fs);
       }
      

      请记住,Linux 内核(其调度程序)随时将任务(即进程或线程)从一个 CPU 内核迁移到另一个 CPU 内核。因此,查询几乎是无用的(任务可能在您查询它的那一刻和您显示它的那一刻之间迁移)。

      【讨论】:

      • my_gettid() 函数返回随机递增的起始值,例如 8732、8733、8734 ..... 如果我有两个内核,它应该返回介于 0 和 1 之间的值。我不是了解这种增加值的重要性
      • 请阅读gettid 的手册页。它返回一个线程 ID。如果您只想要核心编号,请使用/proc/self/statprocessor 字段)或getcpu。但请注意,内核可以在您查询其 cpu 的那一刻和您打印它的那一刻之间迁移任务。
      • getcpu() 也是 Linux 特定的系统调用。
      猜你喜欢
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 2011-09-17
      • 2018-11-14
      • 2015-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多