2010-10-08 16:15:50 +02:00
function [nCPU, totCPU, nBlockPerCPU, totSLAVES] = distributeJobs ( Parallel, fBlock, nBlock)
2010-05-31 11:24:55 +02:00
% PARALLEL CONTEXT
% In parallel context this function is used to determine the total number of available CPUs,
% and the number of threads to run on each CPU.
%
% INPUTS
% o Parallel [struct vector] copy of options_.parallel
2010-09-06 16:59:57 +02:00
% o fBlock [int] index number of the first job (e.g. MC iteration or MH block)
2010-05-31 11:24:55 +02:00
% (between 1 and nBlock)
2010-09-06 16:59:57 +02:00
% o nBlock [int] index number of the last job.
2010-05-31 11:24:55 +02:00
%
% OUTPUT
% o nBlockPerCPU [int vector] for each CPU used, indicates the number of
% threads run on that CPU
% o totCPU [int] total number of CPU used (can be lower than
% the number of CPU declared in "Parallel", if
2010-10-22 11:27:26 +02:00
% the number of required threads is lower!)
% o nCPU the number of CPU in user format.
2011-05-10 10:06:16 +02:00
% o totSLAVES the number of cluster's node currently
% involved in parallel computing step.
% It is a number between 1 and length(Parallel).
2011-04-06 14:27:47 +02:00
2010-02-15 16:52:36 +01:00
2022-04-13 13:15:19 +02:00
% Copyright © 2010-2017 Dynare Team
2010-02-15 16:52:36 +01:00
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
2021-06-09 17:33:48 +02:00
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
2010-02-15 16:52:36 +01:00
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
% The Parallel vector has already been sorted
2017-05-16 15:10:20 +02:00
% (in accord with the CPUWeight values) in DESCENDING order in
2011-05-10 10:06:16 +02:00
% InitializeComputationalEnvironment!
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
totCPU = 0 ;
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
lP = length ( Parallel ) ;
CPUWeight = ones ( 1 , length ( Parallel ) ) * ( - 1 ) ;
2011-04-06 14:27:47 +02:00
2017-05-16 12:42:01 +02:00
for j = 1 : lP
2016-12-19 23:28:46 +01:00
if mod ( length ( Parallel ( j ) . CPUnbr ) , Parallel ( j ) . NumberOfThreadsPerJob )
skipline ( )
disp ( [ ' PARALLEL_ERROR:: NumberOfThreadsPerJob = ' , int2str ( Parallel ( j ) . NumberOfThreadsPerJob ) , ' is not an exact divisor of number of CPUs = ' , int2str ( length ( Parallel ( j ) . CPUnbr ) ) , ' !' ] )
disp ( [ ' You must re-set properly NumberOfThreadsPerJob of node ' int2str ( j ) ' ' Parallel ( j ) . ComputerName ] )
disp ( [ ' in your configuration file' ] )
error ( [ ' PARALLEL_ERROR:: NumberOfThreadsPerJob is not an exact divisor of CPUnbr' ] )
end
nCPU ( j ) = length ( Parallel ( j ) . CPUnbr ) / Parallel ( j ) . NumberOfThreadsPerJob ;
2017-05-16 15:10:20 +02:00
totCPU = totCPU + nCPU ( j ) ;
2011-05-10 10:06:16 +02:00
CPUWeight ( j ) = str2num ( Parallel ( j ) . NodeWeight ) ;
end
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
% Copy of original nCPU.
nCPUoriginal = nCPU ;
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
nCPU = cumsum ( nCPU ) ;
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
% Number of Nodes in Cluster.
nC = lP ;
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
% Numbers of Jobs.
NumbersOfJobs = nBlock - fBlock + 1 ;
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
SumOfJobs = 0 ;
JobsForNode = zeros ( 1 , nC ) ;
2011-04-06 14:27:47 +02:00
2017-05-16 12:42:01 +02:00
for j = 1 : lP
2011-05-10 10:06:16 +02:00
CPUWeight ( j ) = str2num ( Parallel ( j ) . NodeWeight ) * nCPUoriginal ( j ) ;
2011-04-06 14:27:47 +02:00
end
2011-05-10 10:06:16 +02:00
CPUWeight = CPUWeight ./ sum ( CPUWeight ) ;
2011-04-06 14:27:47 +02:00
2011-05-10 10:06:16 +02:00
% Redistributing the jobs among the cluster nodes according to the
% CPUWeight.
for i = 1 : nC
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
JobsForNode ( i ) = CPUWeight ( i ) * NumbersOfJobs ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% Many choices are possible:
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% JobsForNode(i)=round(JobsForNode(i));
% JobsForNode(i)=floor(JobsForNode(i));
2017-05-16 15:10:20 +02:00
JobsForNode ( i ) = ceil ( JobsForNode ( i ) ) ;
2011-05-10 10:06:16 +02:00
end
% Check if there are more (fewer) jobs.
% This can happen when we use ceil, round, ... functions.
SumOfJobs = sum ( JobsForNode ) ;
if SumOfJobs ~= NumbersOfJobs
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if SumOfJobs > NumbersOfJobs
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% Many choices are possible:
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% - Remove the excess works at the node that has the greatest
% number of jobs.
% - Remove the excess works at the node slower.
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
VerySlow = nC ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
while SumOfJobs > NumbersOfJobs
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if JobsForNode ( VerySlow ) == 0
VerySlow = VerySlow - 1 ;
continue
2011-04-06 14:27:47 +02:00
end
2011-05-10 10:06:16 +02:00
JobsForNode ( VerySlow ) = JobsForNode ( VerySlow ) - 1 ;
SumOfJobs = SumOfJobs - 1 ;
2011-04-06 14:27:47 +02:00
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if SumOfJobs < NumbersOfJobs
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% Many choices are possible:
% - ... (see above).
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
[ NonServe VeryFast ] = min ( CPUWeight ) ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
while SumOfJobs < NumbersOfJobs
JobsForNode ( VeryFast ) = JobsForNode ( VeryFast ) + 1 ;
SumOfJobs = SumOfJobs + 1 ;
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
end
end
% Redistributing the jobs among the cpu/core nodes.
JobsForCpu = zeros ( 1 , nCPU ( nC ) ) ;
JobAssignedCpu = 0 ;
RelativePosition = 1 ;
for i = 1 : nC
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% Many choices are possible:
% - ... (see above).
2017-05-16 15:10:20 +02:00
2011-12-02 16:11:10 +01:00
JobAssignedCpu = max ( 1 , floor ( JobsForNode ( i ) / nCPUoriginal ( i ) ) ) ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
ChekOverFlow = 0 ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
for j = RelativePosition : nCPU ( i )
JobsForCpu ( j ) = JobAssignedCpu ;
ChekOverFlow = ChekOverFlow + JobAssignedCpu ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if ChekOverFlow > = JobsForNode ( i )
2017-05-16 12:42:01 +02:00
break
2011-04-06 14:27:47 +02:00
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
% Check if there are more (fewer) jobs.
% This can happen when we use ceil, round, ... functions.
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if ChekOverFlow ~= ( JobsForNode ( i ) )
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if ChekOverFlow > ( JobsForNode ( i ) )
while ChekOverFlow > JobsForNode ( i )
JobsForCpu ( nCPU ( i ) ) = JobsForCpu ( nCPU ( i ) ) - 1 ;
ChekOverFlow = ChekOverFlow - 1 ;
2011-04-06 14:27:47 +02:00
end
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
if ChekOverFlow < ( JobsForNode ( i ) )
while ChekOverFlow < JobsForNode ( i )
JobsForCpu ( nCPU ( i ) ) = JobsForCpu ( nCPU ( i ) ) + 1 ;
ChekOverFlow = ChekOverFlow + 1 ;
end
end
2011-04-06 14:27:47 +02:00
end
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
RelativePosition = nCPU ( i ) + 1 ;
2017-05-16 15:10:20 +02:00
2011-05-10 10:06:16 +02:00
end
% Reshape the variables totCPU,totSLAVES and nBlockPerCPU in accord with
% the syntax rquired by a previous version of parallel package ...
totCPU = 0 ;
totSLAVES = 0 ;
nBlockPerCPU = [ ] ;
for i = 1 : nCPU ( nC )
if JobsForCpu ( i ) ~= 0
totCPU = totCPU + 1 ;
end
end
for i = 1 : nC
2017-05-16 12:42:01 +02:00
if JobsForNode ( i ) ~= 0
2011-05-10 10:06:16 +02:00
totSLAVES = totSLAVES + 1 ;
end
end
RelativeCounter = 1 ;
for i = 1 : nCPU ( nC )
if JobsForCpu ( i ) ~= 0
nBlockPerCPU ( RelativeCounter ) = JobsForCpu ( i ) ;
RelativeCounter = RelativeCounter + 1 ;
end
2011-04-06 14:27:47 +02:00
end