Openmp for loop:工作不平衡的静态计划

时间:2018-06-04 03:35:08

标签: c++ openmp

我有一个有序整数向量的循环。在循环内部,我对整数执行一些操作,以确定是否为程序的其余部分保留或丢弃它们。在循环之后,我需要一个包含保持整数的向量,也是有序的。

由于整数向量相当大(可能大约为50亿),我使用openmp来并行化循环,我想出了以下代码。为了保持良好的整数排序,我使用静态子句和私有向量,它们在循环完成后合并。

std::vector<unsigned> large_int_vector;
// vector filling and ordered...

std::vector<std::vector<unsigned> > good_int_threads;
#pragma omp parallel
{
  int num_threads = omp_get_num_threads();
  int i_thread = omp_get_thread_num();
  #pragma omp single
  {
    good_int_threads.resize(num_threads);
  }
  #pragma omp for schedule(static)
  for (std::size_t i = 0; i < large_int_vector.size(); i++) {
    bool is_good_int = true;
    // some operations on large_int_vector[i]
    if (is_good_int)
      good_int_threads[i_thread].push_back(large_int_vector[i]);
  }
}

std::vector<unsigned> good_int;
for (unsigned i = 0; i != good_int_threads.size(); i++) {
  good_int.insert(good_int.end(),good_int_threads[i].begin(),good_int_threads[i].end());
}

这可以正常工作,但不能很好地扩展。原因是大多数(它取决于线程的数量,但通常> 50%,如果仅使用2或3个线程,则可以高达100%)良好整数位于large_int_vector的“开头”。

更确切地说,for循环中完成的工作是将一些操作应用于整数。如果单个失败,则丢弃整数,我们可以立即移动到下一个整数。另一方面,对于要保留的整数,它必须通过所有操作。显然,这会导致工作不平衡,这可以解释不良规模。

good_int的大小通常为~large_int_vector / 50,因此大约为10亿。

我怎样才能改进我的代码?

1 个答案:

答案 0 :(得分:0)

为每个线程的每个线程分配向量,并运行这样的块:

std::vector<unsigned> large_int_vec;
std::size_t n = large_int_vec.size();
std::size_t chunk = n/10;  //10 chunks, adjust by performance.
#pragma omp parallel
{
  std::vector<unsigned> good_int_local;
  for(std::size_t j = 0; j < n; j += chunk) {
    std::size_t n2 = (j + chunk) >= n ? n - j : chunk;
    #pragma omp for nowait schedule(static)
    for (std::size_t i = 0; i < n2; i++) {
      bool is_good_int = true;
      // some operations on large_int_vec[i]
      if (is_good_int) good_int_local.push_back(large_int_vec[j + i]);
    }
    #pragma omp for schedule(static) ordered
    for(int i=0; i<omp_get_num_threads(); i++) {
      #pragma omp ordered
      good_int.insert(good_int.end(), good_int_local.begin(), good_int_local.end());
    }
    good_int_local.clear();
  }
}

这应该更好地平衡负载并保持顺序。您可以使用schedule(static, chunk)来提供一个解决方案,它可以在不使用外部循环的情况下保留顺序,但对我来说这似乎并非易事。你也许可以提出一个custom dynamic solution但是再次保持秩序似乎并非易事。