% \VignetteIndexEntry{Debugging doRedis Programs} % \VignetteDepends{doRedis} % \VignettePackage{doRedis} \documentclass[10pt]{article} \usepackage[pdftex]{graphicx} \usepackage{Sweave} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document} \section*{Debugging foreach and doRedis programs} Debugging parallel programs is hard. R's foreach and doRedis packages include a few options outlined in this document to help. \section*{Error handling} The \verb+.errorhandling+ parameter of the \verb+foreach()+ function takes a character value among ``stop'', ``remove'', or ``pass'', defaulting to ``stop.'' That means that as soon as an error is detected in any loop iteration, the entire foreach loop stops with that error. Setting \verb`.errorhandling = "pass"` is very useful for debugging your programs since all errors encountered in the loop are returned verbatim in your solution. Start experimenting with this option without using the \verb`.combine` parameter to return all results in a list. Consider the following example program that is rigged to explicitly return an error in one of the loop iterations. We use the `doSEQ` back end below, but this example works exactly the same using any foreach back end. <>= cat(' library(foreach) registerDoSEQ() foreach(j=1:3, .errorhandling="pass") %dopar% { if(j==2) j + undefined_variable else j } # [[1]] # [1] 1 # # [[2]] # # # [[3]] # [1] 3 ') @ The example shows the error when \verb`j=2`. \section*{doRedis logging} Use the \verb`log` and \verb`loglevel` options in the doRedis \verb`redisWorker()` and\newline \verb`startLocalWorkers()` functions to direct output to a file. Use the \verb`logger()` function inside your foreach loop to write messages to the log. The logger function appends process ID and time stamps to your message. Alternatively use the plain old R \verb+message()+ function instead. These options together provide a kind of "printf"-style debug facility--crude but sometimes effective. Here is an example: <>= cat(' library(doRedis) registerDoRedis("cazart") startLocalWorkers(n=1, timeout=1, queue="cazart", log="/tmp/cazart.log", loglevel=1) x <- foreach(j=1:3) %dopar% { logger(paste("hello from loop iteration ", j)) j } # Remove the work queue (terminating the worker process) removeQueue("cazart") Sys.sleep(2) # wait for the worker to terminate # Display the log file file.show("/tmp/cazart.log") # Processing task(s) 1...1 from queue cazart ID 9ba32925bee... # @ 2016-04-23 20:17:26 hostname 3406 hello from loop iteration 1 # Processing task(s) 2...2 from queue cazart ID 9ba32925bee... # @ 2016-04-23 20:17:26 hostname 3406 hello from loop iteration 2 # Processing task(s) 3...3 from queue cazart ID 9ba32925bee... # @ 2016-04-23 20:17:26 hostname 3406 hello from loop iteration 3 # Normal worker exit. ') @ Note that log files from workers running on different hosts are stored on the corresponding host file systems. \section*{doRedis job and task accounting} The doRedis package includes \verb`setProgress()`, \verb`jobs()` and \verb`tasks()` functions that list detailed information about all processes working for doRedis. The function \begin{verbatim} setProgress(TRUE) \end{verbatim} enables an R progress meter during foreach execution. While a foreach loop is running, open a separate R terminal session and use the \verb`jobs()` and \verb`tasks()` functions to list details about running operations. See the help pages for those functions for complete details. \section*{Interactive debugging} A very low-level but effective debugging approach works as follows: \begin{enumerate} \item Start a single R worker process running in an R terminal using the\\ \verb`redisWorker()` function. \item Start, in a separate terminal, a master R process running a foreach job. \end{enumerate} You can monitor the worker R process as the work progresses in its terminal, even including interactive function debugging. With the \verb`loglevel=1` argument, loop task information is printed to standard output in the R worker process terminal window as it occurs, as well as any message output from the \verb`logger()` function. Here is an example split into two R sessions, one for the worker and one for the master (it's assumed that you run these in separate R terminal windows). All standard R debugging options are available in each R session, for example use \verb`option(error=recover)` to explore the call stack after encountering an error condition. <>= cat(' library(doRedis) registerDoRedis("cazart") x <- foreach(j=1:3) %dopar% { logger(paste(" log message from iteration", j)) j } removeQueue("cazart") # remove the work queue ') @ <>= cat(' library(doRedis) redisWorker(queue="cazart", loglevel=1, timeout=1) # Waiting for doRedis jobs. # Processing task(s) 1...1 from queue cazart ID 9ba77ba191c... # @ 2016-04-23 21:09:04 homer 3882 log message from iteration 1 # Processing task(s) 2...2 from queue cazart ID 9ba77ba191c... # @ 2016-04-23 21:09:04 homer 3882 log message from iteration 2 # Processing task(s) 3...3 from queue cazart ID 9ba77ba191c... # @ 2016-04-23 21:09:04 homer 3882 log message from iteration 3 # Normal worker exit. ') @ \end{document}