
# the functions here serve to automate the process of debugging code
# using R's "parallel" library, in the portion derived from the old
# "snow" package, e.g. the function clusterApply() (this part of the
# library will be referred to as "snow" below)

# requires the Unix utility "screen"

# usage:

# we'll refer to the window in which clusterApply() or another
# "parallel" library function runs, as the manager window

# to debug, the user opens another R process in a separate window, and
# makes the call
#
#   cls <- dbs(nwrkrs)
#

# which enables debugging on nwrkrs workers

# the call does the following:

#   uses "screen" create new xterm windows in which the debuggees will run,
#      one window for each worker, to be referred to as worker windows
#   instructs the user to create a manual cluster in the manager window
#   starts up R processes in the worker windows, according to the output of
#      makeCluster()
#   writes the string "parallel:::.slaveRSOCK()" to each of the windows,
#      which means they loop around looking for commands from the manager,
#      generated by the "snow" code to be debugged

# you are then ready to run your "snow" code, and debug as usual by
# typing into the debuggee windows (usually either or via writescreens())

# the function writescreens() wsends a command to all worker windows;
# useful examples:

#   'debug(f)'  # debug a given function
#   'setBreakpoint("buggy.R",28)'  # set a breakpoint at a specific line
#   'c'  # resume execution of the debuggees
#   'xyz'  # print the value of the variable xyz' at all the debuggees
#   'Q'  # exit the debugger at the debuggees
#   'q()'  # exit R at the debuggees
#   'exit'  # close the debuggee windows

# for user convenience, the function dbsquitall() is provided to shut
# everything down; for each worker window, this function issues commands
# to exit the R browser (stepwise debugger), exit R, and then close the
# window (to make sure no "screen" processes remain); the function
# dbsquitrs() does part of this, if the debugger has already been quit

# globals:
#
#    debuggeename:  vector of screen window names, Debuggee1, Debuggee2,...

dbs <- function(nwrkrs) {
   print("run this in a different window from the manager")
   # set up debuggee windows
   dn <- vector(mode="character",length=nwrkrs)
   for (i in 1:nwrkrs) {
      dn[i] <- paste("Debuggee",i,sep="")
      cmd <- 'xterm -e "screen -S'
      cmd <- paste(cmd,dn[i])
      cmd <- paste(cmd,'" &')
      system(cmd)
   }
   debuggeename <<- dn
   print("run this command in the manager window, then hit enter port here:")
   cmd <- 
      paste("cls <- makeCluster(",nwrkrs,",manual=T)",sep="")
   print(cmd)
   port <- readline("enter port number: ")
   rcmd <- paste("R --args MASTER=localhost PORT=",port,
      " SNOWLIB=/usr/local/lib/R/library TIMEOUT=2592000 METHODS=TRUE",sep="")
   writescreens(rcmd)
   readline("hit Enter")  # seems to be needed for throttling
   writescreens("parallel:::.slaveRSOCK()")
}

# assuming all debuggees are currently in the R browser, it has them
# quit the browser, then quit R, then close the window
dbsquitall <- function() {
   writescreens("Q")
   dbsquitrs()
}

# quit R, then close the window
dbsquitrs <- function() {
   writescreens("q()")
   writescreens("n")
   writescreens("exit")
}

writescreens <- function(cmd) {
   cmd <- paste(cmd,'\n',sep="")
   for (dn in debuggeename) {
      tosend <- paste('screen -S ',dn,' -X stuff ', "'",cmd,"'", sep="")
      system(tosend)
   }
}

