R: How make dump.frames() include all variables for later post-mortem debugging with debugger()
Asked Answered
I

2

5

I have the following code which provokes an error and writes a dump of all frames using dump.frames() as proposed e. g. by Hadley Wickham:

a <- -1
b <- "Hello world!"
bad.function <- function(value)
{
  log(value)                  # the log function may cause an error or warning depending on the value
}

tryCatch( {
             a.local.value <- 42
             bad.function(a)
             bad.function(b)
          },
          error = function(e)
          {
            dump.frames(to.file = TRUE)
          })

When I restart the R session and load the dump to debug the problem via

load(file = "last.dump.rda")
debugger(last.dump)

I cannot find my variables (a, b, a.local.value) nor my function "bad.function" anywhere in the frames.

This makes the dump nearly worthless to me.

What do I have to do to see all my variables and functions for a decent post-mortem analysis?

The output of debugger is:

> load(file = "last.dump.rda")
> debugger(last.dump)
Message:  non-numeric argument to mathematical functionAvailable environments had calls:
1: tryCatch({
    a.local.value <- 42
    bad.function(a)
    bad.function(b)
2: tryCatchList(expr, classes, parentenv, handlers)
3: tryCatchOne(expr, names, parentenv, handlers[[1]])
4: value[[3]](cond)

Enter an environment number, or 0 to exit  
Selection: 

PS: I am using R3.3.2 with RStudio for debugging.

Illboding answered 4/11, 2016 at 11:30 Comment(4)
Select 1 and then do ls(parentenv) or get("a.local.value", env = parentenv).Lonne
Strike, getting the local variable works that way, thx! What I still cannot find when I browse through all the environments contained in the different frames of the dump are the global variables and function(s). Strange... It looks like the .GlobalEnv is not contained in dump.frames.Illboding
Perhaps one could append extra variables to the dumped .rda file?Lonne
After some experiments I guess the visibility of a.local.value is caused by lazy evaluation ("promises") because you can see the variable in your own .GlobalEnv after looking into the parentenv which is .GlobalEnv (try environmentName(parentenv)). You can recognize this at the warning issued: "Warning message: In get(.obj, envir = dump[[.selection]]) : restarting interrupted promise evaluation". I think dump.frames with the parameter to.file = TRUE is a big anti pattern (I will explain this in an answer later - discussions are welcome)Illboding
P
3

Note that it is often more productive to work with the R Core team rather than just telling that R has a bug. It clearly has no bug, here, as it behaves exactly as documented.

Also there is no problem if you work interactively, as you have full access to your workspace (which may be LARGE) there, so the problem applies only to batch jobs (as you've mentioned).

What we rather have here is a missing feature and feature requests (and bug reports!) should happen on the R bug site (aka _'R bugzilla'), https://bugs.r-project.org/ ... typically however after having read the corresponding page on the R website: https://www.r-project.org/bugs.html.

Note that R bugzilla is searchable, and in the present case, you'd pretty quickly find that Andreas Kersting made a nice proposal (namely as a wish, rather than claiming a bug), https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17116 and consequently I had added the missing feature to R, on Aug.16, already. Yes, of course, the development version of R, aka R-devel. See also today's thread on the R-devel mailing list, https://stat.ethz.ch/pipermail/r-devel/2016-November/073378.html

Paschasia answered 14/11, 2016 at 10:51 Comment(1)
Martin, thanks for your patience to help me learning how to search for and propose missing feature (which I acutally didn't know or better have not yet cared about). I have marked the answer as accepted and I am happy that a solution is already on the way in a future release. Please rest assured that I didn't want to blame R or some of the developers by shouting out "bug" loudly!Illboding
I
6

Update Nov. 20, 2016: Note that it is not an R bug (see answer of Martin Maechler). I did not change my answer for reproducibility. The described work around still applies.

Summary

I think dump.frames(to.file = TRUE) is currently an anti pattern (or probably a bug) in R if you want to debug errors of batch jobs in a new R session.

You should better replace it with

  dump.frames()
  save.image(file = "last.dump.rda")

or

options(error = quote({dump.frames(); save.image(file = "last.dump.rda")}))

instead of

options(error = dump.frames)

because the global environment (.GlobalEnv = the user workspace you normally create your objects) is included then in the dump while it is missing when you save the dump directly via dump.frames(to.file = TRUE).

Impact analysis

Without the .GlobalEnv you loose important top level objects (and their current values ;-) to understand the behaviour of your code that led to an error!

Especially in case of errors in "non-interactive" R batch jobs you are lost without .GlobalEnv since you can debug only in a newly started (empty) interactive workspace where you then can only access the objects in the call stack frames.

Using the code snippet above you can examine the object values that led to the error in a new R workspace as usual via:

load(file = "last.dump.rda")
debugger(last.dump)

Background

The implementation of dump.frames creates a variable last.dump in the workspace and fills it with the environments of the call stack (sys.frames(). Each environment contains the "local variables" of the called function). Then it saves this variable into a file using save().

The frame stack (call stack) grows with each call of a function, see ?sys.frames:

.GlobalEnv is given number 0 in the list of frames. Each subsequent function evaluation increases the frame stack by 1 and the [...] environment for evaluation of that function are returned by [...] sys.frame with the appropriate index.

Observe that the .GlobalEnv has the index number 0.

If I now start debugging the dump produced by the code in the question and select the frame 1 (not 0!) I can see a variable parentenv which points (references) the .GlobalEnv:

Browse[1]> environmentName(parentenv)
[1] "R_GlobalEnv"

Hence I believe that sys.frames does not contain the .GlobalEnv and therefore dump.frames(to.file = TRUE) neither since it only stores the sys.frames without all other objects of the .GlobalEnv.

Maybe I am wrong, but this looks like an unwanted effect or even a bug. Discussions welcome!

References

https://cran.r-project.org/doc/manuals/R-exts.pdf

Excerpt from section 4.2 Debugging R code (page 96):

Because last.dump can be looked at later or even in another R session, post-mortem debug- ging is possible even for batch usage of R. We do need to arrange for the dump to be saved: this can be done either using the command-line flag --save to save the workspace at the end of the run, or via a setting such as

options(error = quote({dump.frames(to.file=TRUE); q()}))

Illboding answered 4/11, 2016 at 21:6 Comment(2)
Not sure if the situation has changed since you posted this answer, but when I look up the debugger, I see the option include.GlobalEnv in dump.frames. Would this be the same as your proposed solution?Kerge
@rensa The parameter include.GlobalEnv was created via a FR (bugs.r-project.org/bugzilla/show_bug.cgi?id=17116) before I posted here (I've overlooked this FR). The semantics of this parameter is different from my proposed solution: To get a variable from the GlobalEnv you use get("variable.name", last.dump$.GlobalEnv) if you create the dump using this parameter, but just entering the variable name into the debugger does not find the variable by "climbing up" the call stack - this was my last known info. My workaround actually causes the variable to be found in the GlobalEnv.Illboding
P
3

Note that it is often more productive to work with the R Core team rather than just telling that R has a bug. It clearly has no bug, here, as it behaves exactly as documented.

Also there is no problem if you work interactively, as you have full access to your workspace (which may be LARGE) there, so the problem applies only to batch jobs (as you've mentioned).

What we rather have here is a missing feature and feature requests (and bug reports!) should happen on the R bug site (aka _'R bugzilla'), https://bugs.r-project.org/ ... typically however after having read the corresponding page on the R website: https://www.r-project.org/bugs.html.

Note that R bugzilla is searchable, and in the present case, you'd pretty quickly find that Andreas Kersting made a nice proposal (namely as a wish, rather than claiming a bug), https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17116 and consequently I had added the missing feature to R, on Aug.16, already. Yes, of course, the development version of R, aka R-devel. See also today's thread on the R-devel mailing list, https://stat.ethz.ch/pipermail/r-devel/2016-November/073378.html

Paschasia answered 14/11, 2016 at 10:51 Comment(1)
Martin, thanks for your patience to help me learning how to search for and propose missing feature (which I acutally didn't know or better have not yet cared about). I have marked the answer as accepted and I am happy that a solution is already on the way in a future release. Please rest assured that I didn't want to blame R or some of the developers by shouting out "bug" loudly!Illboding

© 2022 - 2024 — McMap. All rights reserved.