What is the cost of a progress bar in R?

[This article was first published on Peter Solymos - R related posts, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

The pbapply R package adds progress bar to vectorized functions, like lapply. A feature request regarding progress bar for parallel functions has been sitting at the development GitHub repository for a few months. More recently, the author of the pbmcapply package dropped a note about his implementation of forking functionality with progress bar for Unix/Linux computers, which got me thinking. How should we add progress bar to snow type clusters? Which led to more important questions: what is the real cost of the progress bar and how can we reduce overhead on process times?

Parallel workflow

Fist off, let’s review how a snow type cluster works. (This is actually implemented in the parallel package, but I tend to refer to snow as that was the original package where the parallel code was taken from, see here.)

<span class="n">library</span><span class="p">(</span><span class="n">parallel</span><span class="p">)</span><span class="w">
</span><span class="n">parLapply</span><span class="w">
</span>
## function (cl = NULL, X, fun, ...)
## {
##     cl <- defaultCluster(cl)
##     do.call(c, clusterApply(cl, x = splitList(X, length(cl)),
##         fun = lapply, fun, ...), quote = TRUE)
## }
## <bytecode: 0x7fa43b326fc0>
## <environment: namespace:parallel>

The cl argument refers to a cluster object that can be conveniently set up via the makeCluster function. X is the ‘problem’ to be split among the workers defined by the cluster object. fun is the function that needs to be applied on elements of X. Pretty much the same as the lapply function except for the cluster argument.

Within the function, we see a nested expression that can be unpacked like this:

<span class="n">x</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">splitList</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">cl</span><span class="p">))</span><span class="w">
</span><span class="n">z</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clusterApply</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lapply</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="p">)</span><span class="w">
</span><span class="n">do.call</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">quote</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span>

The first line splits X so that it is now a list of lists. The list x is of length equal to the number of workers (i.e. length(cl)). Each element in the list x is a part of the original X vector. Let’s see how splitList works. It is an un-exported function from the parallel package that calls splitIndices. Suppose we have 10 ‘jobs’ we want to submit to 2 workers (note that these are just indices, not real values from X):

<span class="n">splitIndices</span><span class="p">(</span><span class="n">nx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="n">ncl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span>
## [[1]]
## [1] 1 2 3 4 5
##
## [[2]]
## [1]  6  7  8  9 10

The first worker gets one half of the job, while the second gets the rest. In other words, the full problem is split into ncl subsets, and those are pushed to the workers in one batch. That is what the next line with clusterApply does (it uses lapply on each worker passing the function etc.). The output object z has all the results in the form of list of lists. So the final do.call expression puts together the pieces in a single list/vector that can be mapped to the input object X.

Here is example taking squares of the numbers 11:20 (note: it is good practice to stop the child processes with stopCluster when all done):

<span class="n">ncl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">2</span><span class="w">
</span><span class="p">(</span><span class="n">cl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">makeCluster</span><span class="p">(</span><span class="n">ncl</span><span class="p">))</span><span class="w">
</span>
## socket cluster with 2 nodes on host 'localhost'
<span class="p">(</span><span class="n">X</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">11</span><span class="o">:</span><span class="m">20</span><span class="p">)</span><span class="w">
</span>
##  [1] 11 12 13 14 15 16 17 18 19 20
<span class="n">fun</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="o">^</span><span class="m">2</span><span class="w">
</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">parallel</span><span class="o">:::</span><span class="n">splitList</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">cl</span><span class="p">)))</span><span class="w"> </span><span class="c1"># these are the real values
</span>
## [[1]]
## [1] 11 12 13 14 15
##
## [[2]]
## [1] 16 17 18 19 20
<span class="n">str</span><span class="p">(</span><span class="n">z</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">clusterApply</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lapply</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="p">))</span><span class="w">
</span>
## List of 2
##  $ :List of 5
##   ..$ : num 121
##   ..$ : num 144
##   ..$ : num 169
##   ..$ : num 196
##   ..$ : num 225
##  $ :List of 5
##   ..$ : num 256
##   ..$ : num 289
##   ..$ : num 324
##   ..$ : num 361
##   ..$ : num 400
<span class="n">str</span><span class="p">(</span><span class="n">do.call</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">quote</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">))</span><span class="w">
</span>
## List of 10
##  $ : num 121
##  $ : num 144
##  $ : num 169
##  $ : num 196
##  $ : num 225
##  $ : num 256
##  $ : num 289
##  $ : num 324
##  $ : num 361
##  $ : num 400
<span class="n">stopCluster</span><span class="p">(</span><span class="n">cl</span><span class="p">)</span><span class="w">
</span>

Progress bar for sequential jobs

Here is a function that shows the basic principle behind the functions in the pbapply package:

<span class="n">library</span><span class="p">(</span><span class="n">pbapply</span><span class="p">)</span><span class="w">

</span><span class="n">pb_fun</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="p">,</span><span class="w"> </span><span class="n">...</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">X</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">as.list</span><span class="p">(</span><span class="n">X</span><span class="p">)</span><span class="w"> </span><span class="c1"># X as list
</span><span class="w">    </span><span class="n">B</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">X</span><span class="p">)</span><span class="w"> </span><span class="c1"># length of X
</span><span class="w">    </span><span class="n">fun</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">match.fun</span><span class="p">(</span><span class="n">fun</span><span class="p">)</span><span class="w"> </span><span class="c1"># recognize the function
</span><span class="w">    </span><span class="n">out</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">vector</span><span class="p">(</span><span class="s2">"list"</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w"> </span><span class="c1"># output list
</span><span class="w">    </span><span class="n">pb</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">startpb</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w"> </span><span class="c1"># set up progress bar
</span><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">seq_len</span><span class="p">(</span><span class="n">B</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1"># start loop
</span><span class="w">        </span><span class="n">out</span><span class="p">[[</span><span class="n">i</span><span class="p">]]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">fun</span><span class="p">(</span><span class="n">X</span><span class="p">[[</span><span class="n">i</span><span class="p">]],</span><span class="w"> </span><span class="n">...</span><span class="p">)</span><span class="w"> </span><span class="c1"># apply function on X
</span><span class="w">        </span><span class="n">setpb</span><span class="p">(</span><span class="n">pb</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="c1"># update progress bar
</span><span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="c1"># end loop
</span><span class="w">    </span><span class="n">closepb</span><span class="p">(</span><span class="n">pb</span><span class="p">)</span><span class="w"> </span><span class="c1"># close progress bar on exit
</span><span class="w">    </span><span class="n">out</span><span class="w"> </span><span class="c1"># return output
</span><span class="p">}</span><span class="w">
</span>

The example demonstrates that the progress bar is updated at each iteration in the for loop, in this case it means 100 updates:

<span class="n">B</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">100</span><span class="w">
</span><span class="n">fun</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">Sys.sleep</span><span class="p">(</span><span class="m">0.01</span><span class="p">)</span><span class="w">
</span><span class="n">pbo</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">pboptions</span><span class="p">(</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"timer"</span><span class="p">)</span><span class="w">
</span><span class="n">tmp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">pb_fun</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">B</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="p">)</span><span class="w">
</span><span class="c1">##   |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed = 01s
</span><span class="n">pboptions</span><span class="p">(</span><span class="n">pbo</span><span class="p">)</span><span class="w">
</span>

If we want to put this updating process together with the parallel evaluation, we need to split the problem in a different way. Suppose we only send one job to each worker at a time. We can do that exactly ceiling(B / ncl) times. The splitpb function takes care of the indices. Using the previous example of 10 jobs and 2 workers, we get:

<span class="n">splitpb</span><span class="p">(</span><span class="n">nx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="n">ncl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span>
## [[1]]
## [1] 1 2
##
## [[2]]
## [1] 3 4
##
## [[3]]
## [1] 5 6
##
## [[4]]
## [1] 7 8
##
## [[5]]
## [1]  9 10

This gives us 10/2 = 5 occasions for updating the progress bar. And it also means that we will increase communication overhead for our parallel jobs 5-fold (from 1 to 5 batches). The overhead increases linearly with problem size B as opposed to being constant.

The cost of the progress bar

To get a sense of the overhead cost associated with the progress bar, here is a prototype function that I used for the developmental version of the pbapply package. The pbapply_test function takes some of the arguments we have covered before (X, FUN, cl). The only new argument is nout which is the maximum number of splits we allow in splitpb. nout = NULL is the default which gives exactly ceiling(nx / ncl) splits. See what happens when we cap that at 4:

<span class="n">splitpb</span><span class="p">(</span><span class="n">nx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="n">ncl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">4</span><span class="p">)</span><span class="w">
</span>
## [[1]]
## [1] 1 2 3 4
##
## [[2]]
## [1] 5 6 7 8
##
## [[3]]
## [1]  9 10

pbapply_test exposes the nout argument so that we can see what happens when we cap the number of progress bar updates (use 100 and 1) vs. we keep the updates increasing with B (NULL).

<span class="n">pblapply_test</span><span class="w"> </span><span class="o"><-</span><span class="w">
</span><span class="k">function</span><span class="w"> </span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">...</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">NULL</span><span class="p">)</span><span class="w">
</span><span class="p">{</span><span class="w">
    </span><span class="n">FUN</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">match.fun</span><span class="p">(</span><span class="n">FUN</span><span class="p">)</span><span class="w">
    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">is.vector</span><span class="p">(</span><span class="n">X</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nf">is.object</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="w">
        </span><span class="n">X</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">as.list</span><span class="p">(</span><span class="n">X</span><span class="p">)</span><span class="w">
    </span><span class="c1">## catch single node requests and forking on Windows
</span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nf">is.null</span><span class="p">(</span><span class="n">cl</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">inherits</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="s2">"cluster"</span><span class="p">)</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">cl</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="m">2L</span><span class="p">)</span><span class="w">
            </span><span class="n">cl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">inherits</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="s2">"cluster"</span><span class="p">)</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
            </span><span class="n">cl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">inherits</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="s2">"cluster"</span><span class="p">)</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">.Platform</span><span class="o">$</span><span class="n">OS.type</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s2">"windows"</span><span class="p">)</span><span class="w">
            </span><span class="n">cl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
    </span><span class="p">}</span><span class="w">
    </span><span class="n">do_pb</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dopb</span><span class="p">()</span><span class="w">
    </span><span class="c1">## sequential evaluation
</span><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">cl</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="n">Split</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">splitpb</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">X</span><span class="p">),</span><span class="w"> </span><span class="m">1L</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nout</span><span class="p">)</span><span class="w">
        </span><span class="n">B</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">Split</span><span class="p">)</span><span class="w">
        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">do_pb</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="n">pb</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">startpb</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w">
            </span><span class="nf">on.exit</span><span class="p">(</span><span class="n">closepb</span><span class="p">(</span><span class="n">pb</span><span class="p">),</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
        </span><span class="p">}</span><span class="w">
        </span><span class="n">rval</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">vector</span><span class="p">(</span><span class="s2">"list"</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w">
        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">seq_len</span><span class="p">(</span><span class="n">B</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="n">rval</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">lapply</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">Split</span><span class="p">[[</span><span class="n">i</span><span class="p">]]],</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">...</span><span class="p">))</span><span class="w">
            </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">do_pb</span><span class="p">)</span><span class="w">
                </span><span class="n">setpb</span><span class="p">(</span><span class="n">pb</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="c1">## parallel evaluation
</span><span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="c1">## snow type cluster
</span><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">inherits</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="s2">"cluster"</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="n">Split</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">splitpb</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">X</span><span class="p">),</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">cl</span><span class="p">),</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nout</span><span class="p">)</span><span class="w">
            </span><span class="n">B</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">Split</span><span class="p">)</span><span class="w">
            </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">do_pb</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="n">pb</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">startpb</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w">
                </span><span class="nf">on.exit</span><span class="p">(</span><span class="n">closepb</span><span class="p">(</span><span class="n">pb</span><span class="p">),</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
            </span><span class="p">}</span><span class="w">
            </span><span class="n">rval</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">vector</span><span class="p">(</span><span class="s2">"list"</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w">
            </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">seq_len</span><span class="p">(</span><span class="n">B</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="n">rval</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">parallel</span><span class="o">::</span><span class="n">parLapply</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="n">X</span><span class="p">[</span><span class="n">Split</span><span class="p">[[</span><span class="n">i</span><span class="p">]]],</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">...</span><span class="p">))</span><span class="w">
                </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">do_pb</span><span class="p">)</span><span class="w">
                    </span><span class="n">setpb</span><span class="p">(</span><span class="n">pb</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="c1">## multicore type forking
</span><span class="w">        </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
            </span><span class="n">Split</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">splitpb</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">X</span><span class="p">),</span><span class="w"> </span><span class="nf">as.integer</span><span class="p">(</span><span class="n">cl</span><span class="p">),</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nout</span><span class="p">)</span><span class="w">
            </span><span class="n">B</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">Split</span><span class="p">)</span><span class="w">
            </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">do_pb</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="n">pb</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">startpb</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w">
                </span><span class="nf">on.exit</span><span class="p">(</span><span class="n">closepb</span><span class="p">(</span><span class="n">pb</span><span class="p">),</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
            </span><span class="p">}</span><span class="w">
            </span><span class="n">rval</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">vector</span><span class="p">(</span><span class="s2">"list"</span><span class="p">,</span><span class="w"> </span><span class="n">B</span><span class="p">)</span><span class="w">
            </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">seq_len</span><span class="p">(</span><span class="n">B</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="n">rval</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">parallel</span><span class="o">::</span><span class="n">mclapply</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">Split</span><span class="p">[[</span><span class="n">i</span><span class="p">]]],</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">...</span><span class="p">,</span><span class="w">
                    </span><span class="n">mc.cores</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">as.integer</span><span class="p">(</span><span class="n">cl</span><span class="p">)))</span><span class="w">
                </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">do_pb</span><span class="p">)</span><span class="w">
                    </span><span class="n">setpb</span><span class="p">(</span><span class="n">pb</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w">
            </span><span class="p">}</span><span class="w">
        </span><span class="p">}</span><span class="w">
    </span><span class="p">}</span><span class="w">
    </span><span class="c1">## assemble output list
</span><span class="w">    </span><span class="n">rval</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">do.call</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">rval</span><span class="p">,</span><span class="w"> </span><span class="n">quote</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
    </span><span class="nf">names</span><span class="p">(</span><span class="n">rval</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">names</span><span class="p">(</span><span class="n">X</span><span class="p">)</span><span class="w">
    </span><span class="n">rval</span><span class="w">
</span><span class="p">}</span><span class="w">
</span>

The next function is test_fun which has a type argument that affects the type of progress bar. We will compare the following three types:

  • "none": no progress bar updates, but the function does everything else the same way including splitting;
  • "txt": text progress bar showing percent of jobs completed;
  • "timer": timer progress bar showing percent of jobs completed with time estimates and final elapsed time.

The no-progress bar case ("none") with nout = 1 will serve as baseline as in this case the function falls back to lapply and its parallel equivalents (parLapply and mclapply).

<span class="n">timer_fun</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"timer"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">pbo</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">pboptions</span><span class="p">(</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">type</span><span class="p">)</span><span class="w">
    </span><span class="nf">on.exit</span><span class="p">(</span><span class="n">pboptions</span><span class="p">(</span><span class="n">pbo</span><span class="p">))</span><span class="w">
    </span><span class="n">rbind</span><span class="p">(</span><span class="w">
        </span><span class="n">pb_NULL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">NULL</span><span class="p">)),</span><span class="w">
        </span><span class="n">pb_100</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">100</span><span class="p">)),</span><span class="w">
        </span><span class="n">pb_1</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">)),</span><span class="w">

        </span><span class="n">pb_cl_NULL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">NULL</span><span class="p">)),</span><span class="w">
        </span><span class="n">pb_cl_100</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">100</span><span class="p">)),</span><span class="w">
        </span><span class="n">pb_cl_1</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">cl</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">)),</span><span class="w">

        </span><span class="n">pb_mc_NULL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ncl</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">NULL</span><span class="p">)),</span><span class="w">
        </span><span class="n">pb_mc_100</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ncl</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">100</span><span class="p">)),</span><span class="w">
        </span><span class="n">pb_mc_1</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pblapply_test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">FUN</span><span class="p">,</span><span class="w"> </span><span class="n">cl</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ncl</span><span class="p">,</span><span class="w"> </span><span class="n">nout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">))</span><span class="w">
    </span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span>

Here is the setup: 1000 iterations, 2 workers, and the function fun2. This function calls Sys.sleep and returns the squared value of the input. Once we open the cluster connection, run timer_fun with different settings and stop the cluster, we also call the pbmclapply function from the pbmcapply package for comparison and calculate a minimum expected time based on the fact that 0.01 * B = 10 sec.

<span class="n">ncl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">2</span><span class="w">
</span><span class="n">B</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">1000</span><span class="w">
</span><span class="n">fun2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">Sys.sleep</span><span class="p">(</span><span class="m">0.01</span><span class="p">)</span><span class="w">
    </span><span class="n">x</span><span class="o">^</span><span class="m">2</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="n">cl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">makeCluster</span><span class="p">(</span><span class="n">ncl</span><span class="p">)</span><span class="w">
</span><span class="n">timer_out</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="w">
    </span><span class="n">none</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="n">timer_fun</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">B</span><span class="p">,</span><span class="w"> </span><span class="n">fun2</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"none"</span><span class="p">),</span><span class="w">
    </span><span class="n">txt</span><span class="w">   </span><span class="o">=</span><span class="w"> </span><span class="n">timer_fun</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">B</span><span class="p">,</span><span class="w"> </span><span class="n">fun2</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"txt"</span><span class="p">),</span><span class="w">
    </span><span class="n">timer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">timer_fun</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">B</span><span class="p">,</span><span class="w"> </span><span class="n">fun2</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"timer"</span><span class="p">))</span><span class="w">
</span><span class="n">stopCluster</span><span class="p">(</span><span class="n">cl</span><span class="p">)</span><span class="w">

</span><span class="n">library</span><span class="p">(</span><span class="n">pbmcapply</span><span class="p">)</span><span class="w">
</span><span class="n">tpbmc</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">system.time</span><span class="p">(</span><span class="n">pbmclapply</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">B</span><span class="p">,</span><span class="w"> </span><span class="n">fun</span><span class="p">,</span><span class="w"> </span><span class="n">mc.cores</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ncl</span><span class="p">))</span><span class="w">

</span><span class="n">tex</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">0.01</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">B</span><span class="w">
</span><span class="n">tpb</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">cbind</span><span class="p">(</span><span class="n">timer_out</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">],</span><span class="w">
    </span><span class="n">timer_out</span><span class="p">[[</span><span class="m">2</span><span class="p">]][</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">],</span><span class="w">
    </span><span class="n">timer_out</span><span class="p">[[</span><span class="m">3</span><span class="p">]][</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">])</span><span class="w">
</span><span class="n">tcl</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">cbind</span><span class="p">(</span><span class="n">timer_out</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="m">4</span><span class="o">:</span><span class="m">6</span><span class="p">,</span><span class="m">3</span><span class="p">],</span><span class="w">
    </span><span class="n">timer_out</span><span class="p">[[</span><span class="m">2</span><span class="p">]][</span><span class="m">4</span><span class="o">:</span><span class="m">6</span><span class="p">,</span><span class="m">3</span><span class="p">],</span><span class="w">
    </span><span class="n">timer_out</span><span class="p">[[</span><span class="m">3</span><span class="p">]][</span><span class="m">4</span><span class="o">:</span><span class="m">6</span><span class="p">,</span><span class="m">3</span><span class="p">])</span><span class="w">
</span><span class="n">tmc</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">cbind</span><span class="p">(</span><span class="n">timer_out</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="m">7</span><span class="o">:</span><span class="m">9</span><span class="p">,</span><span class="m">3</span><span class="p">],</span><span class="w">
    </span><span class="n">timer_out</span><span class="p">[[</span><span class="m">2</span><span class="p">]][</span><span class="m">7</span><span class="o">:</span><span class="m">9</span><span class="p">,</span><span class="m">3</span><span class="p">],</span><span class="w">
    </span><span class="n">timer_out</span><span class="p">[[</span><span class="m">3</span><span class="p">]][</span><span class="m">7</span><span class="o">:</span><span class="m">9</span><span class="p">,</span><span class="m">3</span><span class="p">])</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">tpb</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colnames</span><span class="p">(</span><span class="n">tcl</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colnames</span><span class="p">(</span><span class="n">tmc</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">names</span><span class="p">(</span><span class="n">timer_out</span><span class="p">)</span><span class="w">

</span><span class="n">op</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">par</span><span class="p">(</span><span class="n">mfrow</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">3</span><span class="p">),</span><span class="w"> </span><span class="n">las</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">mar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">))</span><span class="w">
</span><span class="n">matplot</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">B</span><span class="p">,</span><span class="w"> </span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">),</span><span class="w"> </span><span class="n">tpb</span><span class="p">,</span><span class="w">
    </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"l"</span><span class="p">,</span><span class="w"> </span><span class="n">lty</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">ylim</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">tpb</span><span class="p">,</span><span class="w"> </span><span class="n">tcl</span><span class="p">,</span><span class="w"> </span><span class="n">tmc</span><span class="p">)),</span><span class="w">
    </span><span class="n">xlab</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"# pb updates"</span><span class="p">,</span><span class="w"> </span><span class="n">ylab</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"proc time (sec)"</span><span class="p">,</span><span class="w"> </span><span class="n">main</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"sequential"</span><span class="p">)</span><span class="w">
</span><span class="n">abline</span><span class="p">(</span><span class="n">h</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tex</span><span class="p">,</span><span class="w"> </span><span class="n">lty</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w">
</span><span class="n">matplot</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">B</span><span class="o">/</span><span class="n">ncl</span><span class="p">,</span><span class="w"> </span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">),</span><span class="w"> </span><span class="n">tcl</span><span class="p">,</span><span class="w">
    </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"l"</span><span class="p">,</span><span class="w"> </span><span class="n">lty</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">ylim</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">tpb</span><span class="p">,</span><span class="w"> </span><span class="n">tcl</span><span class="p">,</span><span class="w"> </span><span class="n">tmc</span><span class="p">)),</span><span class="w">
    </span><span class="n">xlab</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"# pb updates"</span><span class="p">,</span><span class="w"> </span><span class="n">ylab</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"proc time (sec)"</span><span class="p">,</span><span class="w"> </span><span class="n">main</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"cluster"</span><span class="p">)</span><span class="w">
</span><span class="n">abline</span><span class="p">(</span><span class="n">h</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tex</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">ncl</span><span class="p">,</span><span class="w"> </span><span class="n">lty</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w">
</span><span class="n">matplot</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">B</span><span class="o">/</span><span class="n">ncl</span><span class="p">,</span><span class="w"> </span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">),</span><span class="w"> </span><span class="n">tmc</span><span class="p">,</span><span class="w">
    </span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"l"</span><span class="p">,</span><span class="w"> </span><span class="n">lty</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">ylim</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">tpb</span><span class="p">,</span><span class="w"> </span><span class="n">tcl</span><span class="p">,</span><span class="w"> </span><span class="n">tmc</span><span class="p">)),</span><span class="w">
    </span><span class="n">xlab</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"# pb upda...

To leave a comment for the author, please follow the link and comment on their blog: Peter Solymos - R related posts.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)