Skip to content

Commit 8a74054

Browse files
Make it possible to debug evalFuture(), by capturing the debug conditions to the FutureResult object
1 parent e7d0f9e commit 8a74054

File tree

2 files changed

+78
-6
lines changed

2 files changed

+78
-6
lines changed

R/Future-class.R

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -657,13 +657,30 @@ getExpression <- function(future, ...) UseMethod("getExpression")
657657

658658
#' @export
659659
getExpression.Future <- local({
660-
tmpl_expr_evaluate2 <- bquote_compile({
660+
tmpl_expr_evaluate <- bquote_compile({
661661
"# future:::getExpression.Future(): evaluate the future via evalFuture()"
662662
future:::evalFuture(core = .(core), capture = .(capture), context = .(context), split = .(split), immediateConditionClasses = .(immediateConditionClasses), forwardOptions = .(forwardOptions), local = .(local), cleanup = .(cleanup))
663663
})
664664

665+
tmpl_expr_evaluate_with_debug <- bquote_compile({
666+
local({
667+
conditions <- list()
668+
...future.result <- withCallingHandlers({
669+
"# future:::getExpression.Future(): evaluate the future via evalFuture()"
670+
future:::evalFuture(core = .(core), capture = .(capture), context = .(context), split = .(split), immediateConditionClasses = .(immediateConditionClasses), forwardOptions = .(forwardOptions), local = .(local), cleanup = .(cleanup))
671+
}, condition = function(cond) {
672+
conditions <<- c(conditions, list(cond))
673+
})
674+
...future.result$evalFuture <- list(
675+
conditions = conditions
676+
)
677+
...future.result
678+
})
679+
})
680+
665681
function(future, expr = future$expr, immediateConditions = FALSE, threads = NA_integer_, ..., cleanup = TRUE) {
666682
debug <- getOption("future.debug", FALSE)
683+
667684
## mdebug("getExpression() ...")
668685
args <- list(...)
669686

@@ -783,9 +800,12 @@ getExpression.Future <- local({
783800
forwardOptions$mc.cores <- mc.cores
784801
}
785802

786-
expr <- bquote_apply(tmpl_expr_evaluate2)
787-
788-
if (getOption("future.debug", FALSE)) mprint(expr)
803+
if (debug) {
804+
expr <- bquote_apply(tmpl_expr_evaluate_with_debug)
805+
mprint(expr)
806+
} else {
807+
expr <- bquote_apply(tmpl_expr_evaluate)
808+
}
789809

790810
## mdebug("getExpression() ... DONE")
791811

R/expressions.R

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,23 @@ evalFuture <- function(
2424
forwardOptions = NULL,
2525
local = FALSE,
2626
envir = parent.frame(),
27-
cleanup = TRUE) {
27+
cleanup = TRUE,
28+
debug = FALSE) {
29+
30+
debug <- getOption("future.debug", TRUE)
31+
if (debug) {
32+
mdebugf("future:::evalFuture() ...")
33+
34+
mdebugf("Core:")
35+
mstr(core)
36+
37+
mdebugf("Capture:")
38+
mstr(capture)
39+
40+
mdebugf("Context:")
41+
mstr(context)
42+
}
43+
2844
expr <- core$expr
2945
globals <- core$globals
3046
packages <- core$packages
@@ -420,6 +436,12 @@ evalFuture <- function(
420436

421437
## Use the next-level-down ("popped") future strategy
422438
future::plan(strategiesR, .cleanup = FALSE, .init = FALSE)
439+
if (debug) {
440+
mdebugf("Setting future::plan() ...")
441+
mstr(strategiesR)
442+
mprint(future::plan("list"))
443+
mdebugf("Setting future::plan() ... DONE")
444+
}
423445

424446
if (!is.na(...future.ncores)) {
425447
## (b) Identify default number of cores - acknowledging plan settings
@@ -439,6 +461,9 @@ evalFuture <- function(
439461
if (is.numeric(seed)) {
440462
genv <- globalenv()
441463
genv$.Random.seed <- seed
464+
if (debug) {
465+
mdebugf("Setting .Random.seed")
466+
}
442467
}
443468

444469
globalenv <- (getOption("future.globalenv.onMisuse", "ignore") != "ignore")
@@ -450,6 +475,8 @@ evalFuture <- function(
450475
## Attach globals to the global environment
451476
## Undo changes on exit
452477
if (length(globals) > 0) {
478+
if (debug) mdebugf("Attaching globals ...")
479+
453480
## Preserve globals in all environments until the global environment
454481
names <- names(globals)
455482
envs <- list()
@@ -480,6 +507,7 @@ evalFuture <- function(
480507
}
481508

482509
on.exit({
510+
if (debug) mdebugf("Restoring objects overwritten by globals ...")
483511
## Remove globals from the global environment
484512
rm(list = names(globals), envir = genv, inherits = FALSE)
485513
## Restore objects in all modified environments
@@ -491,9 +519,13 @@ evalFuture <- function(
491519
assign(name, value = value, envir = env, inherits = FALSE)
492520
}
493521
} ## for (ee ...)
522+
if (debug) mdebugf("Restoring objects overwritten by globals ... DONE")
494523
}, add = TRUE)
495524

525+
if (debug) mdebugf("- globals: [n=%d] %s", length(globals), commaq(names(globals)))
496526
assign_globals(globalenv(), globals = globals)
527+
528+
if (debug) mdebugf("Attaching globals ... DONE")
497529
}
498530

499531
conditionClassesExclude <- attr(conditionClasses, "exclude", exact = TRUE)
@@ -503,6 +535,10 @@ evalFuture <- function(
503535
...future.frame <- sys.nframe()
504536
...future.conditions <- list()
505537

538+
if (debug) {
539+
mdebugf("Evaluating future ...")
540+
}
541+
506542
## NOTE: We don't want to use local(body) w/ on.exit() because
507543
## evaluation in a local is optional, cf. argument 'local'.
508544
## If this was mandatory, we could. Instead we use
@@ -579,19 +615,28 @@ evalFuture <- function(
579615
} ## function(cond)
580616
})) ## local() + withCallingHandlers()
581617
}, error = function(ex) {
618+
if (debug) {
619+
mdebugf(" - Caught run-time error")
620+
}
582621
FutureResult(
583622
conditions = ...future.conditions,
584623
rng = !identical(globalenv()$.Random.seed, ...future.rng),
585624
globalenv = if (globalenv) list(added = setdiff(names(.GlobalEnv), ...future.globalenv.names)) else NULL,
586625
started = ...future.startTime
587626
)
588627
}) ## tryCatch()
589-
628+
629+
if (debug) {
630+
mdebugf("Evaluating future ... DONE")
631+
}
590632

591633
## -----------------------------------------------------------------
592634
## Get captured standard output?
593635
## -----------------------------------------------------------------
594636
if (!is.na(stdout)) {
637+
if (debug) {
638+
mdebugf("Gathering captured standard output")
639+
}
595640
sink(type = "output", split = split)
596641
if (stdout) {
597642
...future.result$stdout <- rawToChar(
@@ -604,5 +649,12 @@ evalFuture <- function(
604649
...future.stdout <- NULL
605650
}
606651

652+
if (debug) {
653+
mdebugf("Results:")
654+
mprint(...future.result)
655+
mdebugf("Evaluating future ... DONE")
656+
on.exit(mdebugf("future:::evalFuture() ... DONE"))
657+
}
658+
607659
...future.result
608660
} ## evalFuture()

0 commit comments

Comments
 (0)