主要内容

任务并行问题中的资源争用

这个例子说明了为什么很难对“我的并行代码在多核机器或集群上的表现如何?”这个问题给出具体的答案。

最常见的答案是“这取决于你的代码和硬件”,这个例子将试图解释为什么在没有更多信息的情况下可以这么说。

这个例子使用在同一个多核CPU上的worker上运行的并行代码,突出了内存访问争用的问题。为了简化问题,本示例测试计算机执行不涉及磁盘IO的任务并行问题的能力。这允许你忽略一些可能影响并行代码执行的因素,例如:

  • 进程间通信的数量

  • 进程间通信的网络带宽和延迟

  • 处理启动和关闭时间

  • 将请求分派到流程的时间

  • 磁盘IO性能

这就只剩下:

  • 执行任务并行代码所花费的时间

该图显示了在多个并发进程上并行执行操作时实现的加速。

并行资源争用

资源竞争与效率的类比

要理解为什么执行这样一个简单的基准测试是值得的,请考虑下面的例子:如果一个人可以装满一桶水,带着它走一段距离,倒空它,并在一分钟内把它带回来补充,那么两个人每人带着一桶水走相同的往返需要多长时间?这个简单的类比很好地反映了本例中的任务并行基准测试。乍一看,两个人同时做同一件事比一个人做会降低效率,这似乎很荒谬。

争夺一个管道:资源争用

如果在前面的例子中一切都很完美,那么两个人在一分钟内每人用一桶水完成一个循环。每个人迅速装满一个桶,提着桶到目的地,倒空桶,然后走回来,他们确保不会相互干扰或打断。

然而,想象一下,他们必须用一根小水管来装满水桶。如果他们同时到达水管,人们就不得不等待。这是一个例子共享资源的争用.也许这两个人不需要同时使用软管,因此软管满足了他们的需求;但如果每个人有10个人运输一个桶,有些人可能要一直等待。

在类比中,水管对应于计算机硬件,特别是内存。如果多个程序同时在一个CPU核心上运行,并且它们都需要访问存储在计算机内存中的数据,那么由于内存带宽有限,其中一些程序可能不得不等待。

相同的软管,不同的距离,不同的结果

想象一下,当两个人每人提着一个水桶时,在水管上发生了争执,但随后任务改变了,两个人必须把水提到离水管很远的地方。在执行这个修改后的任务时,两个人花了更大比例的时间在工作上,即拿着水桶走路,而花了更小比例的时间在争夺共享资源(软管)上。因此,他们不太可能同时需要软管,所以这个修改后的任务有更高的并行效率而不是原来的那个。

在本例中的基准测试中,这一方面对应于运行需要大量访问计算机内存的程序,但它们对获取的数据执行的工作很少。另一方面,如果程序对数据执行了大量的计算,那么获取数据所需的时间就变得无关紧要了,计算时间将盖过等待访问内存的时间。

算法的内存访问的可预测性也会影响内存访问的竞争程度。如果以一种规则的、可预测的方式访问内存,将比以一种不规则的方式访问内存减少争用。这可以在下面进一步看到,例如,奇异值分解计算比矩阵乘法导致更多的争用。

启动并行池

关闭任何现有的并行池,并使用parpool.使用默认首选项,parpool在本地机器上启动一个池,每个物理CPU核心有一个worker,直到首选的worker数量。

删除(gcp (“nocreate”));关闭任何现有的并行池P = parpool(“进程”);
使用'Processes'配置文件启动并行池(parpool)…连接到并行池(工人数:6)。
poolSize = p.NumWorkers;

定时功能

一个定时函数,timingFcn,在本例的末尾提供。定时函数在周期内执行一个函数五次spmd语句,并保留给定并发级别所观察到的最小执行时间。

如上所述,这个示例对任务并行问题进行基准测试,仅测量实际运行时。这意味着该示例没有对MATLAB®、并行计算工具箱™或spmd语言构造。相反,这个示例测试了操作系统和硬件同时运行一个程序的多个副本的能力。

设置基准测试问题

创建一个足够大的输入矩阵,以便每次处理时都需要将它从计算机的内存带到CPU上。也就是说,让它大到足以引起资源争用。

Sz = 2048;M = rand(sz*sz,1);

求和操作

一个对单个数组执行重复求和的函数,sumOp,在本例的末尾提供。由于求和操作在计算上是轻量级的,因此在使用大型输入数组同时运行该函数的多个副本时,可以预期会出现资源争用。因此,在并发执行多个这样的计算时,计算求和函数的时间要比在空闲的CPU上执行一个这样的计算所需的时间长。

快速傅里叶变换运算

一个对向量进行重复快速傅里叶变换的函数,fftOp,在本例的末尾提供。FFT操作比求和操作的计算量更大,因此,当同时计算对FFT函数的多个调用时,您应该不会看到与对求和函数的调用相同的性能下降。

矩阵乘法运算

执行矩阵乘法的函数,multOp,在本例的末尾提供。矩阵乘法中的内存访问是非常有规律的,因此这个操作有可能在多核机器上并行地非常有效地执行。

调查资源争用

度量同时计算N个工人上的N个求和函数所需的时间,以获得从1到并行池大小的N个值。

tsum = timingFcn(@() sumOp(m), 1:poolSize);
执行次数:0.279930,0.292188,0.311675,0.339938,0.370064,0.425983

度量在N个worker上同时计算N个FFT函数所需的时间,以获得N从1到并行池大小的值。

tfft = timingFcn(@() fftOp(m),1:poolSize);
执行次数:0.818498,0.915932,0.987967,1.083160,1.205024,1.280371

测量在N个worker上同时计算N个矩阵乘法函数所需的时间,以获得从1到并行池大小的N的值。

M =重塑(M,sz,sz);tmtimes = timingFcn(@() multOp(m),1:poolSize);
执行次数:0.219166,0.225956,0.237215,0.264970,0.289410,0.346732
清晰的

将计时结果合并到一个数组中,并计算通过并发运行多个函数调用实现的加速。

allTimes = [tsum(:), tfft(:), tmtimes(:)];:加速=(任何时候(1)。/任何时候)。* ((1:poolSize) ');

在条形图中绘制结果。这个图表显示了加速与所谓的弱扩展.弱伸缩性是指进程/处理器的数量变化,而每个进程/处理器上的问题大小是固定的。这会随着进程/处理器数量的增加而增加总问题大小。另一方面,强大的扩展是指问题的大小是固定的,而进程/处理器的数量是变化的。这样做的结果是,随着进程/处理器数量的增加,每个进程/处理器所做的功就会减少。

酒吧(加速)传说(的矢量和“向量FFT”矩阵相乘。...“位置”“西北”)包含('并发进程数');ylabel (“加速”)标题(“No的影响。并发进程...“资源争用和加速”]);

对实际应用的影响

查看上面的图表,您可以看到在同一台计算机上,问题的规模可能不同。考虑到其他问题和计算机可能会显示非常不同的行为,应该很清楚为什么不可能对“我的(并行)应用程序在多核机器或集群上的表现如何?”这个问题给出一个一般的答案。这个问题的答案实际上取决于所讨论的应用程序和硬件。

数据大小对资源竞争的度量效应

资源争用不仅取决于正在执行的函数,还取决于正在处理的数据的大小。为了说明这一点,您将测量输入数据大小不同的各种函数的执行时间。与前面一样,您正在对我们的硬件并发执行这些计算的能力进行基准测试,而不是MATLAB或其算法。本文将考虑比以前更多的函数,以便您可以研究不同内存访问模式的影响以及不同数据大小的影响。除了上面描述的函数,您还将使用基准测试

定义数据大小,指定在测试中使用的操作。

SZS = [128, 256, 512, 1024, 2048];操作= {的矢量和“向量FFT”矩阵相乘。“矩阵LU”...矩阵奇异值分解的“矩阵EIG”};

遍历不同的数据大小和函数,并测量顺序执行时间以及并行池中所有工作线程上并发执行所需的时间。

加速= 0(长度(szs),长度(操作));遍历数据大小I = 1:长度(szs) sz = szs(I);流('使用大小为%d- %d.\n的矩阵', sz, sz);J = 1;遍历不同的操作f = [{@sumOp;深圳^ 2;1}、{@fftOp;深圳^ 2;1}、{@multOp;深圳;深圳},...{@lu;深圳;深圳},{@svd;深圳;深圳},{@eig;深圳;Sz}] op = f{1};Nrows = f{2};Ncols = f{3};M = rand(nrows, ncols);比较所有worker上的顺序执行和执行。tcurr = timingFcn(@() op(m), [1, poolSize]);加速(i, j) = tcurr(1)/tcurr(2)*poolSize;J = J + 1;结束结束
使用128 * 128的矩阵。
执行次数:0.000496、0.000681执行次数:0.001933、0.003149执行次数:0.000057、0.000129执行次数:0.000125、0.000315执行次数:0.000885、0.001373执行次数:0.004683、0.007004
使用256 * 256大小的矩阵。
执行次数:0.001754、0.002374执行次数:0.012112、0.022556执行次数:0.000406、0.001121执行次数:0.000483、0.001011执行次数:0.004097、0.005329执行次数:0.023690、0.033705
使用512 * 512大小的矩阵。
执行次数:0.008338、0.018826执行次数:0.046627、0.089895执行次数:0.003986、0.007924执行次数:0.003566、0.007190执行次数:0.040086、0.081230执行次数:0.185437、0.261263
使用1024 * 1024的矩阵。
执行次数:0.052518、0.096353执行次数:0.235325、0.339011执行次数:0.030236、0.039486执行次数:0.022886、0.048219执行次数:0.341354、0.792010执行次数:0.714309、1.146659
使用2048 × 2048的矩阵。
执行次数:0.290942、0.407355执行次数:0.855275、1.266367执行次数:0.213512、0.354477执行次数:0.149325、0.223728执行次数:3.922412、7.140040执行次数:4.684580、7.150495

在每个数据大小的池中的所有worker上并发运行时,绘制每个操作的加速图,显示理想的加速。

图ax =坐标轴;(加速)组(ax的阴谋。孩子,{“标记”}, {“+”“o”‘*’“x”“年代”' d '}”)持有plot([1长度(szs)],[poolSize poolSize],“——”) xticks(1:长度(深圳));xticklabels(深圳+“^ 2”)包含(“每个进程的元素数量”ylim([0 poolSize+0.5])“加速”) legend([操作,{“理想的加速”}),“位置”“西南”)标题(“数据大小对资源竞争和加速的影响”)举行

在查看结果时,请记住函数如何与CPU上的缓存交互。对于较小的数据量,所有这些功能都需要使用CPU缓存。在这种情况下,您可以期望看到良好的加速。当输入数据太大而无法放入CPU缓存时,您将开始看到由于内存访问争用而导致的性能下降。

金宝app支持功能

定时功能

timingFcnFunction接受一个函数句柄和若干并发进程。对于多个并发进程N,当函数句柄在一个周期内执行N次时,该函数测量函数句柄所表示的函数的执行时间spmd块使用N个并行工人。

函数time = timingFcn(fcn, numConcurrent) time = 0 (1,length(numConcurrent));numTests = 5;记录1到numConcurrent workers上的执行时间ind = 1:length(numConcurrent) n = numConcurrent(ind);spmd(n) tconcurrent = inf;%时间函数numTests次,并记录最小时间itr = 1:numTests仅测量任务并行运行时spmdBarrier;抽搐;fcn ();记录所有完成的时间tAllDone = spmdReduce(@max, toc);tconcurrent = min(tconcurrent, tAllDone);结束结束Time (ind) = tconcurrent{1};清晰的tconcurrentitrtAllDone如果1 fprintf('执行次数:%f'、时间(印第安纳州));其他的流(”,% f '、时间(印第安纳州));结束结束流(' \ n ');结束

求和函数

这个函数sumOp对输入矩阵执行100次求和运算,并对结果进行累加。为了得到准确的计时,进行了100次求和运算。

函数sumOp(m) s = 0;Itr = 1:100 s = s + sum(m);结束结束

FFT函数

这个函数fftOp对输入数组执行10次FFT操作。执行FFT操作以获得准确的定时。

函数fftOp (m)Itr = 1:10 fft(m);结束结束

矩阵乘法函数

这个函数multOp将输入矩阵自身相乘。

函数multOp (m) m * m;结束

另请参阅

|||

相关的例子

更多关于