From a55cbdd5fef2ee157b9b6b7d1ec6f58f41655ec1 Mon Sep 17 00:00:00 2001
From: Marco Ratto <marco.ratto@jrc.ec.europa.eu>
Date: Mon, 19 Dec 2016 23:28:46 +0100
Subject: [PATCH] Provisions for new node option NumberOfThreadsPerJob.
 Document option

---
 doc/dynare.texi                               |  4 +++
 .../AnalyseComputationalEnvironment.m         | 10 ++++++
 matlab/parallel/distributeJobs.m              |  9 +++++-
 matlab/parallel/masterParallel.m              | 32 ++++++++++++-------
 4 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/doc/dynare.texi b/doc/dynare.texi
index aee146dd2..c20b97e06 100644
--- a/doc/dynare.texi
+++ b/doc/dynare.texi
@@ -10815,6 +10815,10 @@ installation directory. The default is the empty string.
 The path to the MATLAB or Octave executable. The default value is
 @code{matlab}.
 
+@item NumberOfThreadsPerJob = @var{INTEGER}
+For Windows nodes, sets the number of threads assigned to each remote MATLAB/Octave run. The default
+value is @code{1}. 
+
 @item SingleCompThread = @var{BOOLEAN}
 Whether or not to disable MATLAB's native multithreading. The default
 value is @code{false}. Option meaningless under Octave.
diff --git a/matlab/parallel/AnalyseComputationalEnvironment.m b/matlab/parallel/AnalyseComputationalEnvironment.m
index 8ca504288..9ac207e5c 100644
--- a/matlab/parallel/AnalyseComputationalEnvironment.m
+++ b/matlab/parallel/AnalyseComputationalEnvironment.m
@@ -58,6 +58,7 @@ dynareParallelMkDir(RemoteTmpFolder,DataInput);
 %               see http://www.dynare.org/DynareWiki/ParallelDynare.
 %         2.1   [warning] The user asks to use more CPU's than those available.
 %         2.2   [warning] There are unused CPU's!
+%         2.3   [error] NumberOfThreadsPerJob is not a divisor of CPUnbr
 %
 %
 %   Value 3:    The remote computer is unreachable!!!
@@ -621,6 +622,15 @@ for Node=1:length(DataInput) % To obtain a recoursive function remove the 'for'
         ErrorCode=2.2;
     end
     
+    if mod(length(DataInput(Node).CPUnbr),DataInput(Node).NumberOfThreadsPerJob)
+        skipline()
+        disp(['NumberOfThreadsPerJob = ',int2str(DataInput(Node).NumberOfThreadsPerJob),' is not an exact divisor of number of CPUs = ',int2str(DataInput(Node).CPUnbr)),'!'])
+        disp(['    You must re-set properly NumberOfThreadsPerJob of node ' int2str(Node) ' ' DataInput(Node).ComputerName])
+        disp(['    in your configuration file'])
+        skipline()
+        ErrorCode=2.3;
+    end
+    
     disp(['Test for Cluster computation, computer ',DataInput(Node).ComputerName, ' ..... Passed!'])
     skipline(2)    
 end
\ No newline at end of file
diff --git a/matlab/parallel/distributeJobs.m b/matlab/parallel/distributeJobs.m
index 3f6b60356..0667d902f 100644
--- a/matlab/parallel/distributeJobs.m
+++ b/matlab/parallel/distributeJobs.m
@@ -49,7 +49,14 @@ lP=length(Parallel);
 CPUWeight=ones(1,length(Parallel))*(-1);
 
 for j=1:lP,    
-    nCPU(j)=length(Parallel(j).CPUnbr);
+    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;
     totCPU=totCPU+nCPU(j);    
     CPUWeight(j)=str2num(Parallel(j).NodeWeight);
 end
diff --git a/matlab/parallel/masterParallel.m b/matlab/parallel/masterParallel.m
index 948238afc..902b237dc 100644
--- a/matlab/parallel/masterParallel.m
+++ b/matlab/parallel/masterParallel.m
@@ -259,6 +259,7 @@ for j=1:totCPU,
         compThread = '';
     end
     
+    nthreads=Parallel(indPC).NumberOfThreadsPerJob;
     if indPC>1
         nCPU0 = nCPU(indPC-1);
     else
@@ -322,6 +323,13 @@ for j=1:totCPU,
         
     end
     
+    % set affinity range on win CPU's
+    affinity_range = [1:nthreads]+(j-1-nCPU0)*nthreads;
+    my_affinity = int2str(Parallel(indPC).CPUnbr(affinity_range(1)));
+    for jaff=2:length(affinity_range),
+        my_affinity = [my_affinity ',' int2str(Parallel(indPC).CPUnbr(affinity_range(jaff)))];
+    end
+% % %                   int2str(Parallel(indPC).CPUnbr(j-nCPU0))
     % DA SINTETIZZARE:
     
     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -339,9 +347,9 @@ for j=1:totCPU,
                     end
                 else    % Hybrid computing Matlab(Master)->Octave(Slaves) and Vice Versa!
                     if  regexpi([Parallel(indPC).MatlabOctavePath], 'octave')
-                        command1=['psexec -d -W "',DyMo, '" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)),' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7''); addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
+                        command1=['psexec -d -W "',DyMo, '" -a ',my_affinity,' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7''); addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
                     else
-                        command1=['psexec -d -W "',DyMo, '" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)),' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
+                        command1=['psexec -d -W "',DyMo, '" -a ',my_affinity,' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
                     end
                 end
             else                                                            % 0.2 Parallel(indPC).Local==0: Run using network on remote machine or also on local machine.
@@ -377,20 +385,20 @@ for j=1:totCPU,
                     if ~strcmpi(Parallel(indPC).ComputerName,MasterName),  % 0.3 Run on a remote machine!
                         % Hybrid computing Matlab(Master)-> Octave(Slaves) and Vice Versa!
                         if  regexpi([Parallel(indPC).MatlabOctavePath], 'octave')
-                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                 ' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7''); addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
                         else
              
-                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                 ' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
                         end
                     else                                                  % 0.4 Run on the local machine via the network
                         % Hybrid computing Matlab(Master)->Octave(Slaves) and Vice Versa!
                         if  regexpi([Parallel(indPC).MatlabOctavePath], 'octave')
-                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                 ' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7''); addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
                         else
-                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                            command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                 ' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); fParallel(',int2str(offset+1),',',int2str(sum(nBlockPerCPU(1:j))),',',int2str(j),',',int2str(indPC),',''',fname,''')"'];
                         end
                     end
@@ -408,9 +416,9 @@ for j=1:totCPU,
                     end
                 else    % Hybrid computing Matlab(Master)->Octave(Slaves) and Vice Versa!
                     if  regexpi([Parallel(indPC).MatlabOctavePath], 'octave')
-                        command1=['psexec -d -W "',DyMo, '" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)),' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7'');addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
+                        command1=['psexec -d -W "',DyMo, '" -a ',my_affinity,' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7'');addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
                     else
-                        command1=['psexec -d -W "',DyMo, '" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)),' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
+                        command1=['psexec -d -W "',DyMo, '" -a ',my_affinity,' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
                     end
                 end
             elseif Parallel(indPC).Local==0,                                % 1.2 Run using network on remote machine or also on local machine.
@@ -450,19 +458,19 @@ for j=1:totCPU,
                         if ~strcmpi(Parallel(indPC).ComputerName,MasterName), % 1.3 Run on a remote machine.
                             % Hybrid computing Matlab(Master)->Octave(Slaves) and Vice Versa!
                             if  regexpi([Parallel(indPC).MatlabOctavePath], 'octave')
-                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                     ' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7'');addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
                             else
-                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -u ',Parallel(indPC).UserName,' -p ',Parallel(indPC).Password,' -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                     ' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
                             end
                         else                                                % 1.4 Run on the local machine via the network.
                             % Hybrid computing Matlab(Master)->Octave(Slaves) and Vice Versa!
                             if  regexpi([Parallel(indPC).MatlabOctavePath], 'octave')
-                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                     ' -low  ',Parallel(indPC).MatlabOctavePath,' -f --eval "default_save_options(''-v7''); addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
                             else
-                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',int2str(Parallel(indPC).CPUnbr(j-nCPU0)), ...
+                                command1=['psexec \\',Parallel(indPC).ComputerName,' -d -e -W "',Parallel(indPC).RemoteDrive,':\',Parallel(indPC).RemoteDirectory,'\',PRCDir,'\" -a ',my_affinity, ...
                                     ' -low  ',Parallel(indPC).MatlabOctavePath,' -nosplash -nodesktop -minimize ',compThread,' -r "addpath(''',Parallel(indPC).DynarePath,'''), dynareroot = dynare_config(); slaveParallel(',int2str(j),',',int2str(indPC),')"'];
                             end
                         end
-- 
GitLab