【问题标题】:Matlab limits TBB but not OpenMPMatlab 限制 TBB 但不限制 OpenMP
【发布时间】:2013-06-26 18:48:24
【问题描述】:

我只是想了解我花了 24 小时试图解决的问题。

我的系统: Ubuntu 12.04.2, Matlab R2011a, 它们都是基于 Nehalem 的 64 位 Intel Xeon 处理器。

问题很简单,Matlab 允许基于 OpenMP 的程序使用启用了超线程的所有 CPU 内核,但不允许 TBB 使用相同的 CPU 内核。

运行 TBB 时,我只能启动 4 个线程,即使我将 maxNumCompThreads 更改为 8。而使用 OpenMP,我可以使用我想要的所有线程。如果没有超线程,TBB 和 OpenMP 当然会使用全部 4 个内核。

我了解超线程,并且它是虚拟的,但 matlab 的限制实际上确实会导致性能下降(额外的 reference)。

我使用 2 个程序测试了这个问题,一个简单的 for 循环

#pragma omp parallel for

还有一个基于 tbb 示例代码的非常简单的循环。

tbb::task_scheduler_init init(tbb::task_scheduler_init::deferred);
tbb::parallel_for_each(tasks.begin(),tasks.end(),invoker<mytask>());

并用 matlab mexFunction 将它们都包裹起来。

有人对此有解释吗?允许matlab限制TBB但不允许OpenMP这种限制的线程创建方法或结构是否存在固有差异?

参考代码:

OpenMP:

#include "mex.h"

void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ){
    threadCount = 100000;
#pragma omp parallel for
    for(int globalId = 0; globalId < threadCount ; globalId++)
    {
        for(long i=0;i<1000000000L;++i) {} // Deliberately run slow
    }
}

待定:

#include "tbb/parallel_for_each.h"
#include "tbb/task_scheduler_init.h"
#include <iostream>
#include <vector>
#include "mex.h"

struct mytask {
  mytask(size_t n)
    :_n(n)
  {}
  void operator()() {
    for (long i=0;i<1000000000L;++i) {}  // Deliberately run slow
    std::cerr << "[" << _n << "]";
  }
  size_t _n;
};

template <typename T> struct invoker {
  void operator()(T& it) const {it();}
};

void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const
mxArray* prhs[]) {

  tbb::task_scheduler_init init(tbb::task_scheduler_init::deferred);  // Automatic number of threads

  std::vector<mytask> tasks;
  for (int i=0;i<10000;++i)
    tasks.push_back(mytask(i));

  tbb::parallel_for_each(tasks.begin(),tasks.end(),invoker<mytask>());

}

【问题讨论】:

  • 尝试用8初始化tbb::task_scheduler_init,而不是使用deferred
  • 尝试显式控制线程数:MATLAB 中的maxNumCompThreads,OpenMP 中的omp_set_num_threads 函数或OMP_NUM_THREADS 环境变量,TBB 中的equivalent
  • 我尝试了您的两个建议,但没有奏效。

标签: matlab openmp mex tbb hyperthreading


【解决方案1】:

抱歉这么久才回复。指定deferred 只会阻止任务调度程序创建线程池,直到第一个并行构造开始。默认情况下,线程数为automatic,对应于内核数(代码设置在src/tbb/tbb_misc_ex.cpp,还取决于CPU亲和力等。见initialize_hardware_concurrency_info()

我稍微修改了你的代码:

#include "tbb/parallel_for_each.h"
#include "tbb/task_scheduler_init.h"
#include "tbb/atomic.h"
#include "tbb/spin_mutex.h"
#include <iostream>
#include <vector>

// If LOW_THREAD == 0, run with task_scheduler_init(automatic), which is the number
// of cores available.  If 1, start with 1 thread.

#ifndef NTASKS
#define NTASKS 50
#endif
#ifndef MAXWORK
#define MAXWORK 400000000L
#endif
#ifndef LOW_THREAD
#define LOW_THREAD 0  // 0 == automatic
#endif

tbb::atomic<size_t> cur_par;
tbb::atomic<size_t> max_par;

#if PRINT_OUTPUT
tbb::spin_mutex print_mutex;
#endif

struct mytask {
  mytask(size_t n) :_n(n) {}
  void operator()() {
      size_t my_par = ++cur_par;
      size_t my_old = max_par;
      while( my_old < cur_par) { my_old = max_par.compare_and_swap(my_par, my_old); }

      for (long i=0;i<MAXWORK;++i) {}  // Deliberately run slow
#if PRINT_OUTPUT
      {
          tbb::spin_mutex::scoped_lock s(print_mutex);
          std::cerr << "[" << _n << "]";
      }
#endif
      --cur_par;
  }
  size_t _n;
};

template <typename T> struct invoker {
  void operator()(T& it) const {it();}
};

void mexFunction(/*int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]*/) {

    for( size_t thr = LOW_THREAD; thr <= 128; thr = thr ? thr * 2: 1) {
        cur_par = max_par = 0;
        tbb::task_scheduler_init init(thr == 0 ? (unsigned int)tbb::task_scheduler_init::automatic : thr);

        std::vector<mytask> tasks;
        for (int i=0;i<NTASKS;++i) tasks.push_back(mytask(i));

        tbb::parallel_for_each(tasks.begin(),tasks.end(),invoker<mytask>());
        std::cout << " for thr == ";
        if(thr) std::cout << thr; else std::cout << "automatic";
        std::cout << ", maximum parallelism == " << (size_t)max_par << std::endl;
    }
}

int main() {
    mexFunction();
}

我在这里的 16 核系统上运行了这个:

for thr == automatic, maximum parallelism == 16
for thr == 1, maximum parallelism == 1
for thr == 2, maximum parallelism == 2
for thr == 4, maximum parallelism == 4
for thr == 8, maximum parallelism == 8
for thr == 16, maximum parallelism == 16
for thr == 32, maximum parallelism == 32
for thr == 64, maximum parallelism == 50
for thr == 128, maximum parallelism == 50

50的限制是程序创建的任务总数。

TBB创建的线程是由程序启动的并行构造共享的,所以如果你有两个并行的for_each同时运行,最大线程数不会改变;每个 for_each 都会运行得更慢。 TBB 库不控制 OpenMP 构造中使用的线程数,因此 OpenMP parallel_for 和 TBB parallel_for_each 通常会超额订阅机器。

【讨论】:

    猜你喜欢
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多