title: Julia pmap speed - parallel processing - dynamic programming
body: <p>I am trying to speed up filling in a matrix for a dynamic programming problem in Julia (v0.6.0), and I can't seem to get much extra speed from using <code>pmap</code>. This is related to this question I posted almost a year ago: <a href="https://stackoverflow.com/questions/45178227/filling-a-matrix-using-parallel-processing-in-julia">Filling a matrix using parallel processing in Julia</a>. I was able to speed up serial processing with some great help then, and I'm now trying to get extra speed from parallel processing tools in Julia.</p>
  
  <p>For the serial processing case, I was using a 3-dimensional matrix (essentially a set of equally-sized matrices, indexed by the 1st-dimension) and iterating over the 1st-dimension. I wanted to give <code>pmap</code> a try, though, to more efficiently iterate over the set of matrices.</p>
  
  <p>Here is the code setup. To use <code>pmap</code> with the <code>v_iter</code> function below, I converted the three dimensional matrix into a dictionary object, with the dictionary keys equal to the index values in the 1st dimension (<code>v_dict</code> in the code below, with <code>gcc</code> equal to the 1st-dimension size). The <code>v_iter</code> function takes other dictionary objects (<code>E_opt_dict</code> and <code>gridpoint_m_dict</code> below) as additional inputs:</p>
  
  <pre><code>function v_iter(a,b,c)
     diff_v = 1
     while diff_v&gt;convcrit
       diff_v = -Inf
  
       #These lines efficiently multiply the value function by the Markov transition matrix, using the A_mul_B function
       exp_v       = zeros(Float64,gkpc,1)
       A_mul_B!(exp_v,a[1:gkpc,:],Zprob[1,:])
       for j=2:gz
         temp=Array{Float64}(gkpc,1)
         A_mul_B!(temp,a[(j-1)*gkpc+1:(j-1)*gkpc+gkpc,:],Zprob[j,:])
         exp_v=hcat(exp_v,temp)
       end    
  
       #This tries to find the optimal value of v
       for h=1:gm
         for j=1:gz
           oldv = a[h,j]
           newv = (1-tau)*b[h,j]+beta*exp_v[c[h,j],j]
           a[h,j] = newv
           diff_v = max(diff_v, oldv-newv, newv-oldv)
         end
       end
     end
  end
  
  gz =  9  
  gp =  13  
  gk =  17  
  gcc =  5  
  gm    = gk * gp * gcc * gz
  gkpc  = gk * gp * gcc
  gkp = gk*gp
  beta  = ((1+0.015)^(-1))
  tau        = 0.35
  Zprob = [0.43 0.38 0.15 0.03 0.00 0.00 0.00 0.00 0.00; 0.05 0.47 0.35 0.11 0.02 0.00 0.00 0.00 0.00; 0.01 0.10 0.50 0.30 0.08 0.01 0.00 0.00 0.00; 0.00 0.02 0.15 0.51 0.26 0.06 0.01  0.00 0.00; 0.00 0.00 0.03 0.21 0.52 0.21 0.03 0.00 0.00 ; 0.00 0.00  0.01  0.06 0.26 0.51 0.15 0.02 0.00 ; 0.00 0.00 0.00 0.01 0.08 0.30 0.50 0.10 0.01 ; 0.00 0.00 0.00 0.00 0.02 0.11 0.35 0.47 0.05; 0.00 0.00 0.00 0.00 0.00 0.03 0.15 0.38 0.43]
  convcrit = 0.001   # chosen convergence criterion
  
  E_opt                  = Array{Float64}(gcc,gm,gz)    
  fill!(E_opt,10.0)
  
  gridpoint_m   = Array{Int64}(gcc,gm,gz)
  fill!(gridpoint_m,fld(gkp,2)) 
  
  v_dict=Dict(i =&gt; zeros(Float64,gm,gz) for i=1:gcc)
  E_opt_dict=Dict(i =&gt; E_opt[i,:,:] for i=1:gcc)
  gridpoint_m_dict=Dict(i =&gt; gridpoint_m[i,:,:] for i=1:gcc) 
  </code></pre>
  
  <p>For parallel processing, I executed the following two commands:</p>
  
  <pre><code>wp = CachingPool(workers())
  addprocs(3)
  pmap(wp,v_iter,values(v_dict),values(E_opt_dict),values(gridpoint_m_dict))
  </code></pre>
  
  <p>...which produced this performance:</p>
  
  <p><code>135.626417 seconds (3.29 G allocations: 57.152 GiB, 3.74% gc time)</code></p>
  
  <p>I then tried to serial process instead:</p>
  
  <pre><code>for i=1:gcc
      v_iter(v_dict[i],E_opt_dict[i],gridpoint_m_dict[i])
  end
  </code></pre>
  
  <p>...and received better performance.</p>
  
  <pre><code>128.263852 seconds (3.29 G allocations: 57.101 GiB, 4.53% gc time)
  </code></pre>
  
  <p>This also gives me about the same performance as running <code>v_iter</code> on the original 3-dimensional objects:</p>
  
  <pre><code>v=zeros(Float64,gcc,gm,gz)
  for i=1:gcc
      v_iter(v[i,:,:],E_opt[i,:,:],gridpoint_m[i,:,:])
  end
  </code></pre>
  
  <p>I know that parallel processing involves setup time, but when I increase the value of <code>gcc</code>, I still get about equal processing time for serial and parallel. This seems like a good candidate for parallel processing, since there is no need for messaging between the workers! But I can't seem to make it work efficiently.</p>