c++ - VS 自动并行化

标签 c++ visual-studio parallel-processing

我试图了解自动并行化如何加速我正在编写的程序的执行。我创建了一个更简单的示例:

#include <iostream>
#include <vector>
#include <chrono>

using namespace std;
using namespace std::chrono;

class matrix
{
public:
   matrix(int size, double value) 
   {
       A.resize(size, vector<double>(size, value));
       B.resize(size, vector<double>(size, value));
   };
   void prodScal(double valore)
   {
        for (int m = 0; m < A.size(); m++)
            for (int n = 0; n < A.size(); n++)
            {
                B[m][n] = A[m][n] * valore;
            };
    };
    double elemento(int riga, int column) { return B[riga][column]; }

protected:
    vector<vector<double>> A, B;
};


void main()
{
    matrix* M;
    M = new matrix(1000, 174.9);
    high_resolution_clock::time_point t1 = high_resolution_clock::now();

    #pragma loop(hint_parallel(4))
    for (int i = 0; i < 1000; i++)
        M->prodScal(567.3);

    high_resolution_clock::time_point t2 = high_resolution_clock::now();
    auto duration = duration_cast<milliseconds>(t2 - t1).count();
    cout << "execution time [ms]: " << duration << endl;
 }
当我尝试使用 cl main.cpp /O2 /Qpar /Qpar-report:2 编译此代码时,我收到以下消息:

c:\users\utente\documents\visual studio 2017\projects\parallel\parallel\main.cpp(39) : info C5012: ciclo non parallelizzato a causa del motivo '500'

c:\users\utente\documents\visual studio 2017\projects\parallel\parallel\main.cpp(39) : info C5012: ciclo non parallelizzato a causa del motivo '500'

c:\users\utente\documents\visual studio 2017\projects\parallel\parallel\main.cpp(38) : info C5012: ciclo non parallelizzato a causa del motivo '1000'


你能帮我用正确的方法来并行化这个循环吗?
谢谢。

最佳答案

自动并行化的努力(或信念?)是一把双刃剑:

机器只能在一定程度上“猜测”一个意图(并且可以放弃,只要这种意图对于一组预先连接的转换策略不明确),所以不要指望大规模的任何聪明的技巧可能的不同方法。营销人员会鼓起勇气吹响所有的口哨来推销自动“思考”的产品,但现实却不同。即使是最优秀的人也承认,最好的性能来自指令级分析,有时他们甚至避免使用超标量流水线处理器编织技巧,以便获得最后几纳秒,在最后一级的并行代码性能中损失CPU uop 指令流。所以,最好不要指望仅仅通过使用 #pragma 就能获得这样的专业知识。代码部分相信,“机器”会发明一条最聪明的方法。

所以,测试它(总是彻底):

尝试“并行化”最外层 for(){...}不是最好的开始。无论是性能方面还是资源方面。让我们从另一个方面来解决这个问题,即计算本身:

#include <iostream>              // https://stackoverflow.com/questions/48033769/auto-parallelization-with-vs
#include <vector>
#include <chrono>                // g++ FLAGS.ADD: -std=c++11
#include <omp.h>                 // g++ FLAGS.ADD: -fopenmp -lm
#define   OMP_NUM_OF_THREADS 4

using namespace std;
using namespace std::chrono;

class matrix {
public:
   matrix( int size, double value ) {
           A.resize( size, vector<double>( size, value ) );
           B.resize( size, vector<double>( size, value ) );
   }
   void prodScal( double aScalarVALORE ) {
     // #pragma loop( hint_parallel(4) )                                           // matrix_(hint_parallel(4)).cpp:18:0: warning: ignoring #pragma loop  [-Wunknown-pragmas]
        #pragma omp parallel num_threads( OMP_NUM_OF_THREADS )                     // _____ YET, AGNOSTIC TO ANY BETTER CACHE-LINE RE-USE POLICY        
        for (     unsigned int m = 0; m < A.size(); m++ )
            for ( unsigned int n = 0; n < A.size(); n++ )
                  B[m][n] = A[m][n] * aScalarVALORE;
   }
   double elemento( int riga, int column ) { return B[riga][column]; }

protected:
    vector<vector<double>> A, B;
};

int main() {                              // matrix_(hint_parallel(4)).cpp:31:11: error: ‘::main’ must return ‘int’

    matrix* M;
    M = new matrix( 1000, 174.9 );
    high_resolution_clock::time_point t1 = high_resolution_clock::now();
 // *******************
 // DEFINITELY NOT HERE
 // *******************
 // #pragma loop(hint_parallel(4))       // JUST A TEST EXECUTION, NOT ANY PARALLELISATION BENEFIT FOR A PROCESS-PER-SE PERFORMANCE
    for ( int i = 0; i < 1000; i++ )
        M->prodScal( 567.3 );

    high_resolution_clock::time_point t2 = high_resolution_clock::now();
    auto duration = duration_cast<milliseconds>( t2 - t1 ).count();
    cout << "execution time [ms]: " << duration << endl;
  /* 
   * execution time [ms]: 21601
     ------------------
    (program exited with code: 0)
   * */
    return 0;
 }

一旦有了工作代码,性能调整,以获得最大,是下一个障碍 .

更好地通过 for(){...}可以显着提高所有 MEM 提取的成本总和(为每个非缓存引用支付 ~ +100 [ns])v/s 缓存重用(为任何缓存重用支付 ~ +1.5 [ns])。

它取决于矩阵的全局大小、L3、L2 和 L1 高速缓存大小以及高速缓存行长度/关联性,更不用说如果代码要在虚拟机上运行的额外性能偏差设备。
Non-Uniform-Memory-Architecture topology with static sizes and hardware ID#-s
可以使用 lstopo 描述静态大小和近似的 NUMA 拓扑。 (lscpu 在没有智能 hwloc 服务的情况下)。

在这里,您可以读取缓存容量,它可以保存矩阵单元,以实现智能重用的任何潜在加速(遵循 for(){...} 索引的缓存行跨步)。

调整 for() 可以获得最佳性能。 -循环步进,最好接近可用的 CPU 硬件 ILP 级别(使用 CPU 指令级并行可能的另一个并行度,允许共同执行的微指令链(引用 Intel CPU 关于这些细节的出版物)和最佳在目标平台上进行了测试(如果没有 objective-c PU 架构上的性能基准测试,交叉编译将无法进行此类优化,最好在目标平台上进行体内测试)。

此处的详细信息远远超出了此媒体格式的有限范围,在 StackOverflow 上,但如果对性能调整感兴趣,您肯定会发现来源和您自己的实验实践经验将指导您进一步的步骤。为了以某种方式感知权力,'已经做了一个大型矩阵线性代数项目来完成一些 [TB]矩阵处理从 ~ 126 小时减少到几分钟(不包括加载阶段,将矩阵数据放入 RAM ),通过非常仔细的并行代码设计,因此确实值得“正确”进行设计。

为了获得更高的性能,还必须避免 O/S 驱逐昂贵的预取数据,因此需要更多的努力来获得最终性能,而不仅仅是依靠自动化的“自动并行化”玩具。

结语 :
如果仍然存在疑问,如果这确实可能,那么如果“自动并行化”玩具会做得更好或至少与这些专家 Nerd 极客?他们不会,如果他们确实可以的话。

关于c++ - VS 自动并行化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48033769/

相关文章:

c++ - OpenCV - 使用 findHomography 的 RobustMatcher

c++ - 如何在 C++ 源代码、DLL 或 VC++ 编译器创建的任何文件中查找所有全局变量?

c++ - while 循环总是提前结束一个循环

c++ - 使用 nullptr 作为 std::unordered_map 的键有什么后果吗?

visual-studio - 不使用 Visual Studio 生成 .webtest 文件

c# - 从 Visual Studio 中运行 Specflow 标签?

r - R 并行扩展是否打破了 `apply` 的比喻?

r - listcolumns 和 multidplyr

oracle - 在 PARALLEL QUERY/DML/DDL 中使用 FORCE、ENABLE、DISABLE 关键字有什么区别

c++ - 两个数组,整数和字符串,如何显示带有相应整数的字符串?