Skip to content

perf: speed up C++ core, add benchmark platform with golden master - #24

Open
VincentGuyader wants to merge 14 commits into
masterfrom
bench-optim-mr
Open

perf: speed up C++ core, add benchmark platform with golden master#24
VincentGuyader wants to merge 14 commits into
masterfrom
bench-optim-mr

Conversation

@VincentGuyader

@VincentGuyader VincentGuyader commented Jul 22, 2026

Copy link
Copy Markdown
Owner

What

Performance work on the C++ core, a reproducible benchmark platform with a golden master, and a build portability fix.

Benchmark platform (dev/bench/)

Rscript dev/bench/bench_collage.R measures 6 scenarios (sources 200 to 1500 px, bases samples/kittens/emojis, block sizes 7 to 25) with a per-stage breakdown of the collage() pipeline, and records an md5 golden master of every raw mosaic. --check verifies byte-identical output after any C++ change. Not shipped (^dev$ in .Rbuildignore).

Optimizations (verified byte-identical on all 6 golden scenarios)

  1. find_best_tiles: hoist base color conversion out of the search loop. The raw->double conversion of the base red/green/blue vectors was redone nbase times per block. Converting once upfront (plus exact integer accumulation of block sums) gives a measured 2.1x on this stage, stable across bases of 400 to 4000 tiles (e.g. 84300 blocks x 4000 tiles: 0.278 s -> 0.131 s).
  2. collage_impl: sequential writes. The copy loops were writing tile-by-tile with strided jumps of 4*width*size bytes between rows; reordering to fill each output pixel row sequentially gives 1.05x to 1.29x on the assembly stage (1.29x on a 202 MB mosaic).
  3. collage_impl: R_xlen_t offsets. Offsets were computed in int and overflow beyond 2 GiB of mosaic (reachable: a 5000 px photo at size = 10 with 50 px tiles). Now 64-bit.

End-to-end, collage() remains dominated by the {magick} conversions (image_read() of the final bitmap is up to ~85 % of total on large outputs); that cost is outside this package. Numbers and analysis in dev/bench/README.md and dev/bench/results/.

Build fix

src/Makevars now uses the canonical RcppParallel link line (RcppParallelLibs()), as Makevars.win already did. On Linux it expands to nothing (verified); on macOS it supplies the required -ltbb flags. SystemRequirements: GNU make added accordingly (the line uses $(shell)), which keeps R CMD check --as-cran free of the GNU-extension warning.

Resource findings (documented, no code change)

  • Mosaic size grows as (tile_size/size)^2 vs the source: 1500 px at size = 5 with 50 px tiles is a ~840 MB rgba image, which ImageMagick refuses under default cache policy (cache resources exhausted; boundary measured at ~414 MB OK / ~840 MB fail). Raising MAGICK_MEMORY_LIMIT and friends makes it build in ~3.5 s (2.6 GB peak RSS). Documented in dev/bench/README.md.
  • CPU usage of the parallel stages can be capped with RcppParallel::setThreadOptions(numThreads = ...).

Verification

  • testthat: 13 contexts, all green, before and after.
  • Golden master: 6/6 scenarios byte-identical old vs new C++.
  • R CMD check --no-manual --as-cran: same status as master (the 2 pre-existing NOTEs: non-portable -mno-omit-leaf-frame-pointer flag injected by Ubuntu's Makeconf, and incoming-feasibility remarks). No new WARNING/NOTE.
  • Internal review pass done (offset algebra re-derived, -Wall -Wextra clean on touched files, TBB lambda thread-safety checked).

Note on CI workflows

This branch also carries the local modernization stack (metadata, magick compat fix, testthat suite, examples) that had never been pushed. The two GitHub Actions workflow files (R-CMD-check.yaml, test-coverage.yaml) are included in the final commit (they required a token refresh with the workflow scope, hence the separate commit).

infra-bot added 14 commits June 18, 2026 11:51
Drop the deprecated C++11 specification (R 4.6 builds C++17 by default),
set LazyDataCompression to xz to shrink the lazy-load DB, point URL and
BugReports at the current repository, and declare the test tooling
(testthat, covr, mockery) under Suggests.
as_bitmap() relies on magick::image_data(), which was used but never
imported, so collage() and the histograms only worked when {magick} was
attached. tiles() extracted bitmaps via [[, which now yields 3-channel
RGB for opaque JPEGs, breaking the alpha lookup; force rgba extraction so
tiles stay 4-channel as the C++ engine expects. Regenerate docs/NAMESPACE
with roxygen2 (image_data import, _PACKAGE doc).
guides(colour = FALSE) has been deprecated since ggplot2 3.3.4.
Cover every exported function plus the C++ engine; network helpers
(scrap/npages/tiles_animals) and shinycollage() are exercised through
mocked bindings so the suite stays offline and never launches an app.
The R-CMD-check and test-coverage workflow files exist locally but can
not be pushed with the current token (missing workflow OAuth scope) ;
they will be pushed separately.
Per-stage timings of the collage() pipeline over 6 scenarios, plus an
md5 golden master of every raw mosaic so C++ changes can be checked for
byte-identical output. Includes the measured baseline results.
…loop

Convert the base red/green/blue raw vectors to double once instead of
nbase times per block, and accumulate block sums as integers (exact for
sums of bytes). Measured 2.1x on the find_best_tiles stage across
bases of 400 to 4000 tiles, byte-identical output.
Reorder the copy loops so writes to the output are sequential per pixel
row instead of strided per tile, and compute offsets in R_xlen_t so
mosaics over 2^31 bytes do not overflow int. Measured 1.05-1.29x on the
assembly stage, byte-identical output.
Aligns Makevars with the RcppParallel skeleton and with Makevars.win.
RcppParallelLibs() expands to nothing on Linux (verified) but provides
the -ltbb flags required on macOS.
…U make

The Makevars RcppParallelLibs() line uses GNU extensions, which
R CMD check flags unless SystemRequirements declares GNU make.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant