OpenMP共享文件处理程序

时间:2013-04-18 19:33:57

标签: c++ performance io openmp

我有一个循环,我使用OpenMP进行并行化。在这个循环中,我从文件中读取一个三角形,并对该数据执行一些操作。这些操作从每个三角形到另一个三角形是独立的,所以我认为这很容易并行化,只要我在关键部分保持实际读取文件。

  • 读取三角形的顺序并不重要
  • 读取一些三角形并快速丢弃,有些需要更多的算法工作(bbox构造......)
  • 我在做二进制I / O
  • 使用C ++ ifstream * tri_data *
  • 我在SSD上测试这个

ReadTriangle调用file.read()并从ifstream读取12个浮点数。

#pragma omp parallel for shared (tri_data)
for(int i = 0; i < ntriangles ; i++) {
    vec3 v0,v1,v2,normal;
#pragma omp critical
    {
        readTriangle(tri_data,v0,v1,v2,normal);
    }
    (working with the triangle here)
}

现在,我观察到的行为是,启用OpenMP后,整个过程会变慢。 我在代码中添加了一些计时器来跟踪在I / O方法上花费的时间,以及在循环中花费的时间。

没有OpenMP:

Total IO IN time       : 41.836 s.
Total algorithm time   : 15.495 s.

使用OpenMP:

Total IO IN time       : 48.959 s.
Total algorithm time   : 44.61 s.

我的猜测是,由于读取位于关键部分,因此线程只是在等待彼此完成使用文件处理程序,从而导致更长的等待时间。

有关如何解决此问题的任何指示?我的程序将真正受益于处理具有多个进程的读取三角形的可能性。我尝试过使用线程调度和相关的东西,但在这种情况下,这似乎没什么帮助。

由于我正在研究一种核外算法,因此引入缓冲区来容纳多个三角形并不是一种选择。

1 个答案:

答案 0 :(得分:1)

所以,我建议的解决方案是基于主/从策略,其中:

  1. 主(线程0)执行所有I / O
  2. 奴隶对检索到的数据做了一些工作
  3. 伪代码将读取如下内容:

    #include<omp.h>
    
    vector<vec3> v0;
    vector<vec3> v1;
    vector<vec3> v2;
    vector<vec3> normal;
    
    vector<int> tdone;
    
    int nthreads;
    int triangles_read = 0;
    
    /* ... */
    
    #pragma omp parallel shared(tri_data)
    {
      int id = omp_get_thread_num();
      /*
       * Initialize all the buffers in the master thread.
       * Notice that the size in memory is similar to your example.
       */
    #pragma omp single
      {
        nthreads = omp_get_num_threads();
        v0.resize(nthreads);
        v1.resize(nthreads);
        v2.resize(nthreads);
        normal.resize(nthreads);
        tdone.resize(nthreads,1);
      }
    
      if ( id == 0 ) { // Producer thread
    
        int next = 1; 
        while( triangles_read != ntriangles ) {
          if ( tdone[next] ) { // If the next thread is free
            readTriangle(tri_data,v0[next],v1[next],v2[next],normal[next]); // Read data and fill the correct buffer
            triangles_read++;
            tdone[next] = 0; // Set a flag for thread next to start working
    #pragma omp flush (tdone[next],triangles_read) // Flush it
          }
          next = next%(nthreads - 1) + 1; // Set next
        } // while
    
      } else { // Consumer threads
    
        while( true  ) { // Wait for work                  
          if( tdone[id] == 0) {
            /* ... do work here on v0[id], v1[id], v2[id], normal[id] ... */
            tdone[id] == 1;
    #pragma omp flush (tdone[id]) // Flush it   
          }      
          if( tdone[id] == 1 && triangles_read == ntriangles) break; // Work finished for all
        }
    
      }
    #pragma omp barrier
    
    }
    

    我不确定这对你是否仍然有价值,但无论如何这是一个很好的预告片!