Skip to content

Commit d373be5

Browse files
print() for Future objects now reports a parallelization efficiency, iff options(future.journal = TRUE)
1 parent 90f2c0a commit d373be5

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Package: future
2-
Version: 1.70.0-9007
2+
Version: 1.70.0-9008
33
Title: Unified Parallel and Distributed Processing in R for Everyone
44
Depends:
55
R (>= 3.2.0)

NEWS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Version (development version)
22

3+
## New Features
4+
5+
* `print()` for `Future` objects now reports a parallelization
6+
efficiency breakdown when journaling is enabled via
7+
`options(future.journal = TRUE)`. The round-trip is reported as
8+
"active" time (overhead + evaluation), with wall-clock and idle
9+
time (e.g. time between `future()` and `value()`) shown separately
10+
so that user idle does not penalise the efficiency ratio.
11+
312
* ...
413

514

R/backend_api-Future-class.R

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,60 @@ print.Future <- function(x, ...) {
462462
t1 <- result[["finished"]]
463463
cat(sprintf("Duration: %s (started %s)\n", format(t1-t0), t0))
464464
cat(sprintf("Worker process: %s\n", result[["session_uuid"]]))
465+
466+
## Efficiency breakdown (when journaling is enabled)
467+
if (inherits(future[[".journal"]], "FutureJournal")) {
468+
j <- tryCatch(journal(future), error = function(e) NULL)
469+
if (!is.null(j)) {
470+
## Only top-level events; sub-events (parent != NA) overlap in
471+
## wall-clock with their parent and would double-count.
472+
j_top <- j[is.na(j[["parent"]]), , drop = FALSE]
473+
j_top[["stop"]] <- j_top[["start"]] + j_top[["duration"]]
474+
create_idx <- which(j_top[["event"]] == "create")
475+
gather_idx <- which(j_top[["event"]] == "gather")
476+
over_idx <- which(j_top[["category"]] == "overhead")
477+
eval_idx <- which(j_top[["category"]] == "evaluation")
478+
if (length(create_idx) > 0L && length(gather_idx) > 0L &&
479+
length(eval_idx) > 0L) {
480+
g <- gather_idx[length(gather_idx)]
481+
walltime <- (j_top[["start"]][g] + j_top[["duration"]][g]) -
482+
j_top[["start"]][create_idx[1]]
483+
eval_dur <- sum(j_top[["duration"]][eval_idx])
484+
over_dur_raw <- sum(j_top[["duration"]][over_idx])
485+
## For backends like 'sequential' where 'launch' temporally
486+
## wraps 'evaluate', subtract that overlap so it isn't
487+
## double-counted as both overhead and evaluation.
488+
overlap_secs <- 0
489+
for (i in over_idx) for (k in eval_idx) {
490+
ov <- as.numeric(min(j_top[["stop"]][i], j_top[["stop"]][k]) -
491+
max(j_top[["start"]][i], j_top[["start"]][k]),
492+
units = "secs")
493+
if (ov > 0) overlap_secs <- overlap_secs + ov
494+
}
495+
over_secs <- max(as.numeric(over_dur_raw, units = "secs") -
496+
overlap_secs, 0)
497+
eval_secs <- as.numeric(eval_dur, units = "secs")
498+
## "Active" round-trip excludes idle time (e.g. between
499+
## future() and value()) and master-blocked-on-worker time
500+
## that runs in parallel with evaluation.
501+
active_secs <- over_secs + eval_secs
502+
wall_secs <- as.numeric(walltime, units = "secs")
503+
idle_secs <- max(wall_secs - active_secs, 0)
504+
overhead <- as.difftime(over_secs, units = "secs")
505+
active <- as.difftime(active_secs, units = "secs")
506+
idle <- as.difftime(idle_secs, units = "secs")
507+
cat("Efficiency:\n")
508+
cat(sprintf(" Round-trip: %s (active = overhead + evaluation; wall-clock %s, idle %s)\n",
509+
format(active), format(walltime), format(idle)))
510+
if (active_secs > 0) {
511+
cat(sprintf(" Evaluation: %s (%.1f%%) [worker]\n",
512+
format(eval_dur), 100 * eval_secs / active_secs))
513+
cat(sprintf(" Overhead: %s (%.1f%%) [orchestration]\n",
514+
format(overhead), 100 * over_secs / active_secs))
515+
}
516+
}
517+
}
518+
}
465519
} else {
466520
cat("Value: <not collected>\n")
467521
cat("Conditions captured: <none>\n")

0 commit comments

Comments
 (0)