From 4fac7b40222b1ea86b10fa8c45899c9f8cf04710 Mon Sep 17 00:00:00 2001 From: seanthimons Date: Tue, 20 Oct 2026 12:10:50 -0400 Subject: [PATCH 1/3] perf(bootstrap): stop serializing the task list with every mirai batch The mirai worker was an anonymous function created inside start_mirai_bootstrap(), so its environment was that frame. mirai serializes a function together with its environment, so every batch job carried the full task list and dispatch cost grew with the total replicate count. Build the worker in an internal bootstrap_worker() helper whose environment is globalenv(). Its body uses only namespaced calls, so it needs no free variables. Source references are stripped so that a pkgload::load_all() worker does not ship the source file with each batch. The dev_path load behavior is unchanged. Replicate output for a given seed is unchanged. --- R/bootstrap.R | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/R/bootstrap.R b/R/bootstrap.R index 67c39d0..f977455 100644 --- a/R/bootstrap.R +++ b/R/bootstrap.R @@ -215,14 +215,7 @@ start_mirai_bootstrap <- function(inputs, object) { mapped <- tryCatch( mirai::mirai_map( batches, - function(batch, original_fit, dev_path) { - if (!is.null(dev_path) && !pkgload::is_dev_package("singlehit")) { - pkgload::load_all(dev_path, quiet = TRUE) - } - dplyr::bind_rows(lapply(batch, function(task) { - singlehit:::bootstrap_refit(original_fit, task$sample_data, task$replicate) - })) - }, + bootstrap_worker(), .args = list(original_fit = object, dev_path = dev_path), .compute = compute ), @@ -245,6 +238,25 @@ start_mirai_bootstrap <- function(inputs, object) { ) } +# The function mirai sends to each daemon with every batch. Its environment is +# globalenv() so that mirai does not serialize the frame that created it, which +# holds the full task list. The body uses only namespaced calls, so it needs no +# free variables from that frame. Source references are removed because under +# pkgload::load_all() they would carry the whole source file with each batch. +bootstrap_worker <- function() { + worker <- function(batch, original_fit, dev_path) { + if (!is.null(dev_path) && !pkgload::is_dev_package("singlehit")) { + pkgload::load_all(dev_path, quiet = TRUE) + } + dplyr::bind_rows(lapply(batch, function(task) { + singlehit:::bootstrap_refit(original_fit, task$sample_data, task$replicate) + })) + } + worker <- utils::removeSource(worker) + environment(worker) <- globalenv() + worker +} + bind_bootstrap_results <- function(results) { failed <- vapply(results, function(result) inherits(result, c("miraiError", "errorValue")), logical(1)) if (any(failed)) { From f08e9cbdb278462ad40d6d7df709043426f9a814 Mon Sep 17 00:00:00 2001 From: seanthimons Date: Tue, 20 Oct 2026 12:10:50 -0400 Subject: [PATCH 2/3] test(bootstrap): cover the detached mirai worker Check that the worker's environment is globalenv() and that its serialized payload stays small, that it refits a batch exactly like the sequential path, and that start_mirai_bootstrap() passes the detached worker to mirai_map(). --- tests/testthat/test-bootstrap-dispatch.R | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/testthat/test-bootstrap-dispatch.R diff --git a/tests/testthat/test-bootstrap-dispatch.R b/tests/testthat/test-bootstrap-dispatch.R new file mode 100644 index 0000000..ed28174 --- /dev/null +++ b/tests/testthat/test-bootstrap-dispatch.R @@ -0,0 +1,39 @@ +test_that("the mirai worker does not capture the frame that creates it", { + worker <- bootstrap_worker() + + # A closure built inside start_mirai_bootstrap() would carry that frame, which + # holds every task, and mirai would serialize it with each batch. + expect_identical(environment(worker), globalenv()) + expect_lt(length(serialize(worker, NULL)), 10000L) +}) + +test_that("the mirai worker refits a batch exactly like the sequential path", { + fit <- fit_dose_response(ward_fixture(), "beta_poisson") + tasks <- generate_bootstrap_tasks(fit, fit$data$response, 3L, 42L) + + batched <- bootstrap_worker()(tasks, fit, NULL) + sequential <- run_sequential_bootstrap(tasks, fit) + + expect_equal(tibble::as_tibble(batched), tibble::as_tibble(sequential)) +}) + +test_that("start_mirai_bootstrap sends mirai the detached worker", { + skip_if_not_installed("mirai") + fit <- fit_dose_response(ward_fixture(), "beta_poisson") + inputs <- prepare_bootstrap(fit, 3L, "observed", 42L, "mirai", NULL, NULL) + captured <- NULL + local_mocked_bindings( + daemons_set = function(...) TRUE, + mirai_map = function(.x, .f, ...) { + captured <<- .f + list() + }, + .package = "mirai" + ) + + job <- start_mirai_bootstrap(inputs, fit) + + expect_s3_class(job, "qdr_bootstrap_job") + expect_identical(environment(captured), globalenv()) + expect_lt(length(serialize(captured, NULL)), 10000L) +}) From c88238d3af4fbb32dea0416965e92b06870007c3 Mon Sep 17 00:00:00 2001 From: seanthimons Date: Tue, 20 Oct 2026 12:27:18 -0400 Subject: [PATCH 3/3] build: require testthat 3.1.7 for local_mocked_bindings The mirai dispatch test mocks bindings with local_mocked_bindings(.package = ), which first shipped in testthat 3.1.7. State that minimum so an older install fails with a clear version requirement instead of an unknown-argument error. --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 0ef07a2..7d41977 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -37,6 +37,6 @@ Suggests: pkgload, rmarkdown, Rmpfr, - testthat (>= 3.0.0) + testthat (>= 3.1.7) VignetteBuilder: knitr Config/testthat/edition: 3