future icon indicating copy to clipboard operation
future copied to clipboard

Plan for debugging (and traceback)

Open mllg opened this issue 7 years ago • 3 comments

I know there is the "transparent" plan, but I'm still not very helpful tracebacks:

library(future)
plan("transparent")
f = function(x) if (x > 5) stop("whoops") else x
g = function(x) f(x)
result %<-% g(10)
> Error in f(x) : whoops
> traceback()
17: stop(condition)
16: resignalCondition(future)
15: signalEarly(x, ...)
14: resolved.Future(future)
13: NextMethod()
12: resolved.UniprocessFuture(future)
11: resolved(future)
10: signalEarly(future, collect = FALSE)
9: run.UniprocessFuture(future)
8: run(future)
7: sequential(expr, envir = envir, substitute = FALSE, lazy = lazy,
       seed = seed, globals = globals, local = local, earlySignal = earlySig
nal,
       label = label, ...)
6: evaluator(expr, envir = envir, substitute = FALSE, lazy = lazy,
       seed = seed, globals = globals, packages = packages, ...)
5: (function (expr, envir = parent.frame(), substitute = TRUE, globals = TRU
E,
       packages = NULL, lazy = FALSE, seed = NULL, evaluator = plan("next"),

       ...)
   {
       if (substitute)
           expr <- substitute(expr)
       if (!is.function(evaluator)) {
           stop("Argument 'evaluator' must be a function: ", typeof(evaluato
r))
       }
       future <- evaluator(expr, envir = envir, substitute = FALSE,
           lazy = lazy, seed = seed, globals = globals, packages = packages,

           ...)
       if (!inherits(future, "Future")) {
           stop("Argument 'evaluator' specifies a function that does not ret
urn a Future object: ",
               paste(sQuote(class(future)), collapse = ", "))
       }
       future
   })(g(10), envir = <environment>, lazy = FALSE, seed = NULL, globals = TRU
E)
4: do.call(future::future, args = future.args, envir = assign.env)
3: futureAssign(name, expr, envir = envir, assign.env = assign.env,
       substitute = FALSE)
2: futureAssignInternal(target, expr, envir = envir, substitute = FALSE)
1: result %<-% g(10)

-> I just get the top level call, nothing about f().

  1. Would it be possible to create a plan which just calls base R functions? E.g., futureCall calls do.call, futureAssign calls assign, future_lapply calls lapply ...?
  2. Alternatively, would it be possible to store and query the traceback?
  3. Maybe there could also be a plan for the evaluate package?

mllg avatar Sep 21 '18 07:09 mllg

Sorry for the delay. Yes, the idea of the transparent backend is to simplify troubleshooting. It would be nice to have a barebone, minimal-overhead future backend for troubleshooting etc. Things like lazy evaluation (lazy = TRUE) makes this much complicated since we cannot just call eval() on the future expression immediately when the future is created. Having said that, I'll add it to the list of simplifying transparent, which currently just utilizes the sequential backend.

HenrikBengtsson avatar Nov 09 '18 18:11 HenrikBengtsson

This is quite an old issue, but regarding FR 2, there's backtrace();

library(future)
plan(sequential)
f <- function(x) if (x > 5) stop("whoops") else x
g <- function(x) f(x)
result %<-% g(10)

which gives

> result
Error in f(x) : whoops

We can get a clean stack trace by calling backtrace() on this future/promise:

> backtrace(result)
[[1]]
result %<-% g(10)

[[2]]
futureAssignInternal(target, expr, envir = envir, substitute = FALSE)

[[3]]
futureAssign(name, expr, envir = envir, assign.env = assign.env, 
    substitute = FALSE)

[[4]]
do.call(future::future, args = future.args, envir = assign.env)

[[5]]
(function (expr, envir = parent.frame(), substitute = TRUE, lazy = FALSE, 
    seed = FALSE, globals = TRUE, packages = NULL, label = NULL, 
    gc = FALSE, ...) 
{
    if (substitute) 
        expr <- substitute(expr)
    makeFuture <- plan("next")
    future <- makeFuture(expr, substitute = FALSE, envir = envir, 
        lazy = lazy, seed = seed, globals = globals, packages = packages, 
        label = label, gc = gc, ...)
    if (!inherits(future, "Future")) {
        stop(FutureError("plan(\"next\") returned a function that does not return a Future object: ", 
            paste(sQuote(class(future)), collapse = ", ")))
    }
    future
})(g(10), envir = <environment>, lazy = FALSE, seed = NULL, globals = TRUE)

[[6]]
makeFuture(expr, substitute = FALSE, envir = envir, lazy = lazy, 
    seed = seed, globals = globals, packages = packages, label = label, 
    gc = gc, ...)

[[7]]
SequentialFuture(..., envir = envir)

[[8]]
UniprocessFuture(expr = expr, envir = envir, substitute = FALSE, 
    lazy = lazy, globals = globals, local = local, ...)

[[9]]
Future(expr = expr, substitute = FALSE, envir = envir, lazy = lazy, 
    asynchronous = FALSE, local = local, globals = globals, packages = packages, 
    ...)

[[10]]
eval(quote(g(10)), new.env())

[[11]]
g(10)

[[12]]
function(x) f(x)

[[13]]
function(x) if (x > 5) stop("whoops") else x

[[14]]
f(x)

HenrikBengtsson avatar Nov 07 '20 01:11 HenrikBengtsson