1

我正在尝试对计算进行基准测试,f(x)同时在每次迭代中改变线程数。

f(x) = c * ln(x) * cos(x)

n=10000000


for (int pp = 2; pp<17; pp++)
{
    p = pp;
    int chunk = n/p; //acts like floor
    omp_set_num_threads(p);
    double start_parallel = omp_get_wtime();
    //start parallel
    #pragma omp parallel shared(tt,chunk) private (i)
    {
        //printf("thread number %d\n",omp_get_thread_num());
        #pragma omp for schedule(dynamic,chunk) nowait
        for(i=0; i<n; i++)
        {
            //tt[i] = f(tt[i]);
            tt[i] = f1(tt[i]); //the speed up is much higher with f1 since log and cos 
                               //computations are polynomial; see function.
        }
    } //end parallel
    double end_parallel = omp_get_wtime();
    double cpu_time_used_parallel = (double) (end_parallel - start_parallel);
    printf("parallel: for n=%d, p=%d, time taken=%f, speedup=%f\n",
            n,p,cpu_time_used_parallel,
            cpu_time_used_seq/cpu_time_used_parallel);
}

结果:

开始了不同的线程:

并行:对于 n=10000000,p=2,所用时间=0.153774,加速=3.503831

并行:对于 n=10000000,p=3,耗时=0.064447,加速比=8.360370

并行:对于 n=10000000,p=4,耗时=0.044694,加速=12.055239

并行:对于 n=10000000,p=5,耗时=0.048700,加速=11.063550

并行:对于 n=10000000,p=6,所用时间=0.039009,加速比=13.811989

并行:对于 n=10000000,p=7,所用时间=0.041735,加速=12.910017

并行:对于 n=10000000,p=8,耗时=0.041268,加速=13.055919

并行:对于 n=10000000,p=9,所用时间=0.039032,加速=13.804157

并行:对于 n=10000000,p=10,耗时=0.038970,加速=13.825767

并行:对于 n=10000000,p=11,耗时=0.039843,加速=13.522884

并行:对于 n=10000000,p=12,耗时=0.041356,加速=13.028237

并行:对于 n=10000000,p=13,所用时间=0.041039,加速=13.128763

并行:对于 n=10000000,p=14,耗时=0.047433,加速=11.359218

并行:对于 n=10000000,p=15,耗时=0.048430,加速=11.125202

并行:对于 n=10000000,p=16,耗时=0.051950,加速=10.371477


注意:此处的加速比是根据顺序算法计算的(线程 = 1)

加速似乎并没有真正受到p(线程数)变化的影响。

我这样做是否正确,或者原因来自线程数的非有效增量(即理论上讲更改p不会严重影响O(myprogram))?

4

2 回答 2

3

我这样做对吗……?
A :不,对不起,你没有碰巧做这件事。让我们分析一下原因,一起勾勒出一些HPC级性能基准测试的提示:

好吧,您已经知道最初的基准设计不是精心设计的。附加成本的影响,在当代原始的、开销天真的阿姆达尔定律的批评中得到了证明,对此有更多的细节,而时序细节很好地表明了这一点,因为实例化成本对其他类型的处理越来越小,而且我/O相关费用,如下图。

在此处输入图像描述

原因?

与“计算”部分相比,该代码具有巨大的附加开销成本。这是对原本合法的语法构造函数(此处为 OpenMP,其他地方的 map-reduce,其他情况下的列表理解或其他其他地方的一些其他语法糖技巧)的技术能力使用有缺陷的最强标志

最终的表现是一种平衡的艺术(正确 - 平衡成本和收益 - 任何类型的不平衡都意味着失去性能优势)。


费用?这里?看看结果的风景::

第二个罪是忽略域缩放的“幕后”[TIME]域惩罚。[SPACE]越大n,分配的内存就越大,(可怕的)缓存行效率低下带来的惩罚也就越多,所有这些都具有零保护,不会陷入内存交换的地狱:

n=1E3        1E4        1E5        1E6        1E7        1E8        1E9       :
______________________________________________________________________________:_____
1.000      1.000      1.000      1.000      1.000      1.000      1.000       : p= 1
0.930      1.403      0.902      1.536      1.492      1.517      0.356       : p= 2
1.075      2.319      2.207      1.937      2.001      1.991      1.489++     : p= 3
1.497+++++ 2.636++++  1.563      1.657      2.571      2.144      0.687       : p= 4
1.226++    2.548+++   0.957      2.025      2.357      1.731      1.569++++   : p= 5
1.255+++   1.805      2.704      2.020      2.348      1.502      0.989       : p= 6
0.957      0.581      3.104++    2.124      2.486      2.002      0.838       : p= 7
1.151      1.376      2.449      2.154      2.573      1.536      0.776       : p= 8
1.135      1.685      2.388      2.506+++   2.852++++  2.311      1.676+++++  : p= 9
1.285++++  2.492++    2.497      2.568++++  2.647+     2.467      1.413+      : p=10
1.177      2.314+     2.709+     2.174      2.688+++   2.634++++  0.606       : p=11
1.216+     2.293      2.442      2.287      2.550      2.551++    1.256       : p=12
1.034      2.148      1.802      2.361++    2.635      2.554+++   1.181       : p=13
0.999      0.440      3.672+++++ 2.774+++++ 2.927+++++ 2.839+++++ 1.496+++    : p=14
1.091      1.217      3.285++++  2.284      2.525      2.356      1.005       : p=15
0.937      2.850+++++ 3.185+++   2.334+     2.655++    2.508+     0.889       : p=16

提高性能的技巧 ?

  • 如果对计算进行基准测试,请对计算进行基准测试并避免MEM-I/O

  • 如果进行基准测试,请始终检查整个环境,以感受(更好地了解如何避免/消除任何此类情况,以免测量结果出现偏差)缓存中的副作用

  • 始终避免任何形式的共享(可以避免 - 将处理映射到缓存行连贯块中的分离区域tt[],但覆盖“整个” tt[],以避免错误共享和“至少”重用任何数据从已经获取的数据块中,您已经支付了 MEM-I/O 获取的成本(如果基于向量的 LOAD/STORE 确实是必须的 - 见上文)

  • 允许并积极利用 FMA4 / SIMD / AVX512 可用的任何 HPC 矢量化技巧

于 2019-10-06T16:45:02.780 回答
0

nowait由于omp pragma中的子句,您的结果不正确。通常,a 的结尾parallel代表一个同步点,但没有等待,第一个完成的线程不会等待其他线程,因此您将 double end_parallel = omp_get_wtime();在其他线程仍在进行一些计算时执行。如果你取出nowait,你应该观察到完全不同的结果。

于 2019-10-04T14:14:07.960 回答