ITERAND 당 선고적인 노력 추정치를 사용하여 병렬 루프의 런타임 예측 (주어진 수의 근로자)

StackOverflow https://stackoverflow.com/questions/19844249

문제

PDE의 특정 이산화 (알려진 희소성 구조)에서 나오는 매우 큰 희소 행렬에 대한 적응 형 매트릭스 벡터 곱셈의 MATLAB 구현 작업을 수행하고 있습니다.

많은 사전 프로세싱 후, 나는 선택한 항목을 계산하려는 여러 가지 다른 블록 (예 : 200보다 큰)으로 끝납니다.

사전 처리 단계 중 하나는 내가 계산하려는 블록 당 (수) 항목을 결정하는 것입니다. 이는 각 블록이 취할 시간의 양을 거의 완벽하게 측정합니다 (모든 의도와 목적에 따라 직교 노력은 다음과 같습니다. 각 항목에 대해 동일).

감사합니다 https://stackoverflow.com/a/9938666/2965879, 나는 블록을 역 순서로 주문함으로써 이것을 사용할 수 있었기 때문에 Matlab을 가장 큰 것들로 시작으로 시작했습니다.

그러나 항목의 수는 블록마다 크게 다르기 때문에 파워를 직접 실행하는 것은 반전 루프에 공급 되더라도 가장 많은 항목으로 블록에 의해 직접 실행됩니다.

내 해결책은 가장 큰 블록을 연속적으로 수행하는 것입니다 (그러나 항목 수준에서 평행을 이루는 것)은 이르 랜드 당 오버 헤드가 너무 중요하지 않은 한 괜찮습니다. 블록이 너무 작아지지 않습니다. 나머지 블록은 파워로 수행합니다. 이상적으로는 Matlab이이를 처리하는 방법을 결정하게했지만 중첩 된 파우프 루프가 병렬 처리를 잃어 버리기 때문에 작동하지 않습니다. 또한 두 루프를 하나로 포장하는 것은 불가능합니다.

내 질문은 이제 직렬 정권과 병렬 체제 사이의 이러한 컷오프를 가장 잘 결정하는 방법에 관한 것입니다. 내가 이용할 수있는 근로자의 수.

지금까지 표준 PCT 라이센스로 이용 가능한 12 명의 근로자와 협력 해 왔지만 이제 클러스터 작업을 시작한 이래로이 컷오프를 결정하는 것이 점점 더 중요해집니다 (많은 코어의 경우 오버 헤드가 있기 때문입니다. 일련의 루프는 병렬 루프와 비교하여 점점 더 많은 비용이 들지만, 마찬가지로 나머지를 유지하는 블록이 훨씬 더 비싸다).

12 개의 코어의 경우 (내가 작업 한 컴퓨팅 서버의 구성), 나는 컷오프로 작업자 당 100 개의 항목의 합리적인 매개 변수를 알아 냈지만, 코어 수가 아닌 경우에는 잘 작동하지 않습니다. 블록 수와 관련하여 더 이상 작습니다 (예 : 64 vs 200).

나는 다른 힘 (예 : 1/2, 3/4)을 가진 코어의 수를 디플레이션하려고 노력했지만 이것은 일관되게 작동하지 않습니다. 다음으로 블록을 배치로 그룹화하고 항목이 배치 당 평균보다 클 때 컷오프를 결정하려고 시도했습니다. 그들이 끝나는 배치의 수 :

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_entr_asc 그 길이는 여러 가지가 아닙니다 num_core, 그러나 나는 생략하기로 결정했다 min(...,end) 가독성을위한 구조.)

나는 또한 생략했다 < max(...,...) 두 조건을 결합하는 경우 (예 : 컷오프가 너무 일찍 발견되지 않도록 필요합니다. 나는 어떻게 든 분산을 사용하는 것에 대해 조금 생각했지만 지금까지 모든 시도는 불만족 스러웠습니다.

누군가가 이것을 해결하는 방법에 대해 좋은 아이디어가 있다면 매우 감사 할 것입니다.

도움이 되었습니까?

해결책

나는 다소 만족스러운 솔루션을 생각해 냈기 때문에 누구나 관심이있는 경우 공유 할 것이라고 생각했습니다. 접근 방식을 개선/미세 조정하는 방법에 대한 의견에 여전히 감사 할 것입니다.

기본적으로, 나는 유일한 현명한 방법은 병렬 루프에 대한 스케줄러의 (매우) 초보 모델을 구축하는 것이라고 결정했습니다.

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-루프 (아마도 더). 모든 것을 함께 버리는 주된 이유는 더 세분화 된 비용을 추정/결정하고 싶지 않기 때문입니다.

위의 루틴을 사용하여 다음과 같은 방식으로 컷오프를 결정합니다.

% 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. 일련/병렬 분포의 가능한 모든 조합에 대한 비용을 계산 한 다음 최소한을 취함으로써 한쪽에서 데이터를 읽는 동안 너무 일찍 "고착"할 수 없습니다 (예 : 지금까지 데이터에 비해 큰 점프가 있습니다. 그러나 총계에 비해 작습니다).

물론, 무증상 복잡성은 est_cost_para 항상 루프를 가지고 있지만 내 경우에는 (num_blocks<500) 이것은 절대적으로 무시할 수 있습니다.

마지막으로, 괜찮은 값의 경우 cost_it 쉽게 제시하지 않으며, 각 블록의 실제 실행 시간을 측정하고 순전히 평행 한 부분을 측정 한 다음 결과 데이터를 비용 예측에 맞추고 업데이트 된 값을 얻으려고 시도 할 수 있습니다. cost_it 일상의 다음 호출을 위해 (총 비용과 병렬 비용의 차이를 사용하거나, 제로 비용을 적합한 공식에 삽입함으로써). 이것은 가장 유용한 가치로 "수렴"해야합니다. cost_it 문제의 문제.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top