c++ - 基准问题 : execution time varies between two values

标签 c++ mpi openmp benchmarking slurm

我正在尝试对三个不同的应用程序进行基准测试。它们都是使用 MPI 和 OpenMP 用 C++ 编写的,并使用 gcc7.1 和 OpenMPI3.0 编译。我使用一个包含多个节点和 2 个 24 核 Intel CPU 的集群。每个节点上运行一个进程,每个节点上的并行化是使用 OpenMP 完成的。

编辑:这是最短的基准测试,我正在测试自定义缩减操作:

#include <mpi.h>
#include <omp.h>
#include <vector>
#include <chrono>

int process_id = -1;

std::vector<double> values(268435456, 0.1);

void sum(void *in, void *inout, int *len, MPI_Datatype *dptr){
    double* inv = static_cast<double*>(in);
    double* inoutv = static_cast<double*>(inout);   
    *inoutv = *inoutv + *inv;
} 

int main(int argc, char** argv) {
  MPI_Init(&argc, &argv);   
  int mpi_world_size = 0;
  MPI_Comm_size(MPI_COMM_WORLD, &mpi_world_size);   
  MPI_Comm_rank(MPI_COMM_WORLD, &process_id);

  #pragma omp declare reduction(sum : double : omp_out = omp_out + omp_in) initializer(omp_priv = omp_orig)

  MPI_Op sum_mpi_op;
  MPI_Op_create( sum, 0, &sum_mpi_op );
  double tmp_result = 0.0;
  double result = 0.0;

  std::chrono::high_resolution_clock::time_point timer_start = std::chrono::high_resolution_clock::now();

  #pragma omp parallel for simd reduction(sum:tmp_result)
  for(size_t counter = 0; counter < 268435456; ++counter){
    tmp_result = tmp_result + values[counter];
  }     

  MPI_Allreduce(&tmp_result, &result, sizeof(double), MPI_BYTE, sum_mpi_op, MPI_COMM_WORLD); 
  std::chrono::high_resolution_clock::time_point timer_end = std::chrono::high_resolution_clock::now();
  double seconds = std::chrono::duration<double>(timer_end - timer_start).count();

  if(process_id == 0){
    printf("Result: %.5f; Execution time: %.5fs\n", result, seconds);
  }

  MPI_Finalize();
  return EXIT_SUCCESS;
}

我观察到所有基准测试的执行时间在两个值之间变化,例如对于基准 A,我有 10 次运行,其中 5 次大约需要 0.6 秒,5 次大约需要 0.73 秒(+/- 一点)。 对于基准 B,它是相同的,但执行时间是 77 秒或 85 秒(同样是 +/-)。 Benchmark C 的等效结果。因此两者之间没有任何区别。 我用 std::chrono:high_resolution_clock 测量时间:

std::chrono::high_resolution_clock::time_point timer_start = std::chrono::high_resolution_clock::now();

// do something

std::chrono::high_resolution_clock::time_point timer_end = std::chrono::high_resolution_clock::now();
double seconds = std::chrono::duration<double>(timer_end - timer_start).count();

Slurm 用作批处理系统,我使用独占选项来确保节点上没有其他作业在运行。 对于 Slurm 作业,我基本上使用以下文件:

 #!/bin/bash
 #SBATCH --ntasks 4
 #SBATCH --nodes 4
 #SBATCH --ntasks-per-node 1
 #SBATCH --exclusive
 #SBATCH --cpus-per-task 24
 export OMP_NUM_THREADS=24
 RUNS=10
 for ((i=1;i<=RUNS;i++)); do
   srun /path/bench_a
 done

为了构建代码,我使用 CMake 并设置标志

-O3 -DNDEBUG -march=haswell -DMPICH_IGNORE_CXX_SEEK -std=c++14

由于所有基准测试都是一样的,我不认为原因在于实现,而是关于我构建代码或开始工作的方式。

你知道我应该寻找什么来解释这种行为吗? 谢谢

最佳答案

这是基准测试的常见问题... 通常基准测试执行 10'000 次然后取平均值。 10%以下的执行时间波动是难以避免的。

您的集群是否只有 4 个节点? 可以解释它的一个原因是网络使用,特别是如果通信时间实际上占执行时间的很大一部分(因为您可能不是当时唯一在集群上运行的人)。避免此问题的唯一方法是对整个集群或在整个集群的预留范围内运行基准测试。您应该询问 IT 人员他们喜欢什么,尤其是当您在集群上有给定的预算时。但通常 10'000 次运行可以很好地估计您的执行时间。

(关于给定 slurm 脚本中的多个 srun,您是正确的,始终在同一脚本中运行您想要比较的所有基准测试:-))

关于c++ - 基准问题 : execution time varies between two values,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49736622/

相关文章:

c++ - 如果调用了子类的析构函数,是否可以停止调用其基类的析构函数?

c++ - 通过 OpenMPI 进行非阻塞数据共享

c - OpenMP:并行程序并不比串行程序快(或不是非常快)。我究竟做错了什么?

c++ - 赋值运算符和深拷贝

c++ - 如何增加MFC静态控件中的字符限制

c++ - Netbeans MPI c++ 如何启动?

c++ - 如何使用 MPI 广播 boost vector ?

c - 为什么 openmp 不并行化这段代码?

c++ - OpenMP 线程创建

c++ - 有条件的? : operator with class constructor