【问题标题】:Predicting runtime of parallel loop using a-priori estimate of effort per iterand (for given number of workers)使用每个迭代的工作量的先验估计来预测并行循环的运行时间(对于给定数量的工作人员)
【发布时间】:2013-11-19 14:07:58
【问题描述】:

我正在为来自 PDE 的特定离散化(具有已知的稀疏结构)的非常大的稀疏矩阵进行自适应矩阵向量乘法的 MATLAB 实现。

经过大量预处理后,我最终得到了许多不同的块(例如,大于 200),我想为其计算选定的条目。

其中一个预处理步骤是确定我要计算的每个块的(数量)条目,这让我几乎完美地衡量了每个块将花费的时间量(对于所有意图和目的,求积每个条目的努力都是相同的)。

感谢https://stackoverflow.com/a/9938666/2965879,我能够通过以相反的顺序对块进行排序来利用这一点,从而促使 MATLAB 先从最大的块开始。

但是,每个块的条目数差异很大,以至于直接运行 parfor 会受到条目数最多的块的严重限制,即使它们被反向输入循环。

我的解决方案是串行执行最大的块(但在条目级别上并行化!),这很好,只要每个迭代的开销无关紧要,分别。块不会变得太小。然后我用 parfor 完成其余的块。理想情况下,我会让 MATLAB 决定如何处理这个问题,但是由于嵌套的 parfor 循环失去了并行性,这不起作用。此外,将两个循环打包成一个(几乎)是不可能的。

我现在的问题是如何最好地确定串行和并行机制之间的界限,同时考虑到我所掌握的关于条目数量的信息(对于不同的问题,有序条目的曲线形状可能会有所不同),以及我可用的工人数量。

到目前为止,我一直在与标准 PCT 许可下可用的 12 名工作人员一起工作,但是自从我现在开始在集群上工作,确定这个截止值变得越来越重要(因为对于许多内核来说与并行循环相比,串行循环的开销变得越来越昂贵,但类似地,拥有支撑其余部分的块的成本更高)。

对于 12 个内核(分别是我正在使用的计算服务器的配置),我已经找到了一个合理的参数,即每个工作人员 100 个条目作为截止值,但是当内核数量时,这并不适用相对于块的数量不再小了(例如 64 对 200)。

我尝试减少具有不同功率(例如 1/2、3/4)的内核数量,但这也无法始终如一地工作。接下来,我尝试将块分组并确定当条目大于每批平均值时的截止值,resp。他们离结束的批次数:

logical_sml = true(1,num_core); i = 0;
while all(logical_sml)
    i = i+1;
    m = mean(num_entr_asc(1:min(i*num_core,end))); % "asc" ~ ascending order 
    logical_sml = num_entr_asc(i*num_core+(1:num_core)) < i^(3/4)*m;  
        % if the small blocks were parallelised perfectly, i.e. all  
        % cores take the same time, the time would be proportional to  
        % i*m. To try to discount the different sizes (and imperfect  
        % parallelisation), we only scale with a power of i less than  
        % one to not end up with a few blocks which hold up the rest  
end  
num_block_big = num_block - (i+1)*num_core + sum(~logical_sml);

(注意:此代码不适用于长度不是num_core 的倍数的向量num_entr_asc,但为了便于阅读,我决定省略min(...,end) 结构。)

我还省略了 &lt; max(...,...) 以结合这两个条件(即与每个工人的最低条目一起),这是必要的,这样就不会太早发现截止。我也考虑过以某种方式使用方差,但到目前为止,所有尝试都不尽如人意。

如果有人知道如何解决这个问题,我将不胜感激。
感谢您阅读这个很长的问题,
最好的问候,
阿克塞尔

附言。由于我的“亲爱的 stackoverflow”似乎被过滤了,让我感谢我已经在这里找到了我的问题的解决方案。

【问题讨论】:

  • 正如他们所说,最好的感谢就是支持答案(我相信你在那些场合已经这样做了):-)
  • 不是一个答案,但你的很多问题都可以归结为>我现在的问题是关于如何最好地确定串行和并行机制之间的截止[循环]。
  • @ijkilchenko:你说的完全正确,也许我把“具体”的建议看得太字面意思了...... ;-)

标签: matlab parallel-processing load-balancing parfor


【解决方案1】:

我想出了一个有点令人满意的解决方案,所以如果有人感兴趣,我想我会分享它。我仍然希望 cmets 了解如何改进/微调该方法。

基本上,我认为唯一明智的方法是为并行循环构建一个(非常)基本的调度器模型:

function c=est_cost_para(cost_blocks,cost_it,num_cores)
% Estimate cost of parallel computation

% Inputs:
%   cost_blocks: Estimate of cost per block in arbitrary units. For
%       consistency with the other code this must be in the reverse order
%       that the scheduler is fed, i.e. cost should be ascending!
%   cost_it:     Base cost of iteration (regardless of number of entries)
%       in the same units as cost_blocks.
%   num_cores:   Number of cores
%
% Output:
%   c: Estimated cost of parallel computation

num_blocks=numel(cost_blocks);
c=zeros(num_cores,1);

i=min(num_blocks,num_cores);
c(1:i)=cost_blocks(end-i+1:end)+cost_it;
while i<num_blocks
    i=i+1;
    [~,i_min]=min(c); % which core finished first; is fed with next block
    c(i_min)=c(i_min)+cost_blocks(end-i+1)+cost_it;
end

c=max(c);

end

空迭代的参数cost_it 是许多不同副作用的粗略混合,可以想象它们可以分开:for/parfor-loop 中空迭代的成本(也可能不同每个块),以及启动时间resp。 parfor-loop(可能更多)的数据传输。我将所有内容放在一起的主要原因是我不想估计/确定更精细的成本。

我使用上述例程通过以下方式确定截止:

% function i=cutoff_ser_para(cost_blocks,cost_it,num_cores)
% Determine cut-off between serial an parallel regime

% Inputs:
%   cost_blocks: Estimate of cost per block in arbitrary units. For
%       consistency with the other code this must be in the reverse order
%       that the scheduler is fed, i.e. cost should be ascending!
%   cost_it:     Base cost of iteration (regardless of number of entries)
%       in the same units as cost_blocks.
%   num_cores:   Number of cores
%
% Output:
%   i: Number of blocks to be calculated serially

num_blocks=numel(cost_blocks);
cost=zeros(num_blocks+1,2);

for i=0:num_blocks
    cost(i+1,1)=sum(cost_blocks(end-i+1:end))/num_cores + i*cost_it;
    cost(i+1,2)=est_cost_para(cost_blocks(1:end-i),cost_it,num_cores);
end

[~,i]=min(sum(cost,2));
i=i-1;

end

特别是,我不会夸大/更改est_cost_para 的值,它假定(除了cost_it)可能是最乐观的调度。我保持原样主要是因为我不知道什么会最有效。为了保守起见(即避免向并行循环提供太大的块),当然可以添加一些百分比作为缓冲区,甚至使用大于 1 的幂来增加并行成本。

另请注意,est_cost_para 的调用块会逐渐减少(尽管我对两个例程都使用变量名 cost_blocks,但其中一个是另一个的子集)。

与我冗长的问题中的方法相比,我看到了两个主要优点:

  1. 与使用单个公式相比,使用模拟调度程序可以更好地捕获数据(块数及其成本)与内核数之间相对复杂的相关性。
  2. 通过计算串行/并行分布的所有可能组合的成本,然后取最小值,在从一侧读取数据时不会过早“卡住”(例如,相对于数据而言较大的跳转)到目前为止,但与总数相比很小)。

当然,通过一直使用其 while 循环调用 est_cost_para,渐近复杂度会更高,但在我的情况下 (num_blocks&lt;500),这绝对可以忽略不计。

最后,如果cost_it 的一个像样的值不容易出现,可以尝试通过测量每个块的实际执行时间以及它的纯并行部分来计算它,然后尝试拟合将结果数据用于成本预测,并为下一次例程调用获取更新值cost_it(通过使用总成本和并行成本之间的差异或将零成本插入拟合公式)。对于所讨论的问题,这应该有望“收敛”到cost_it 的最有用值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-07
    • 1970-01-01
    相关资源
    最近更新 更多