Parallelize ObjectStorageProvider downloads - #2088
Conversation
This is microsoft#1485 / microsoft#1392 now that we have the DiagnosticContext infrastructure to make it not painful. Run up to eight external object-storage downloads concurrently while respecting lower VCPKG_MAX_CONCURRENCY values. Each worker writes to its own result slot and FullyBufferedDiagnosticContext; after all workers finish, diagnostics are replayed on the calling thread in action order, avoiding concurrent console I/O. Add a bounded execute_in_parallel overload without changing existing callers, plus regression coverage for its concurrency ceiling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR parallelizes object-storage binary cache downloads in ObjectStorageProvider by introducing a bounded-concurrency execute_in_parallel overload, while preserving ordered diagnostics by buffering them per worker and replaying on the caller thread.
Changes:
- Parallelize
ObjectStorageProvider::acquire_zips()downloads with a fixed upper bound (8) and per-action buffered diagnostics. - Add a
execute_in_parallel(work_count, max_concurrency, ...)overload (keeping the existing signature as a wrapper). - Add a regression test to ensure the new overload respects the provided concurrency ceiling.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/vcpkg/binarycaching.cpp | Runs object-storage downloads concurrently and replays diagnostics deterministically after completion. |
| include/vcpkg/base/parallel-algorithms.h | Adds a max-concurrency overload for execute_in_parallel and keeps the legacy overload. |
| src/vcpkg-test/parallel-algorithms.cpp | Adds test coverage validating the max-concurrency limit is honored. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
include/vcpkg/base/parallel-algorithms.h:145
- On non-Windows,
max_concurrency == 0makesmax_threadsbecome 0, which underflowsbg_thread_count = max_threads - 1and can lead to a hugereserve()/spawn loop. This creates a crash / OOM hazard if a caller ever passes 0 (even accidentally). Consider clampingmax_concurrency(ormax_threads) to at least 1 (the calling thread).
WorkCallbackContext<F> context{work, work_count};
auto max_threads = std::min({work_count, max_concurrency, static_cast<size_t>(get_concurrency())});
max_threads = std::min(max_threads, (SIZE_MAX - work_count) + 1u); // to avoid overflow in fetch_add
auto bg_thread_count = max_threads - 1;
std::vector<JThread> bg_threads;
JC (Crzyrndm)
left a comment
There was a problem hiding this comment.
I'm unable to test this week but the change looks fairly similar to the original experiment otherwise
|
Testing results with 11 dependencies. Timing taken from the log line which looks like Test run using
Baseline (Tag
|
Yeah I was really worried about introducing reliability problems by hammering remotes with like 100 concurrent queries on big build machines tripping DDOS prevention and that sort of thing. |
I did see one example where there was a warning printed about rate limiting but it wasn't replicated and still succeeded. 8 seems like a safe-ish default to start with and the worst potential outcome currently is I believe a local build so not too worried about it for now.
|
This is #1485 / #1392 now that we have the DiagnosticContext infrastructure to make it not painful.
Run up to eight external object-storage downloads concurrently while respecting lower VCPKG_MAX_CONCURRENCY values. Each worker writes to its own result slot and FullyBufferedDiagnosticContext; after all workers finish, diagnostics are replayed on the calling thread in action order, avoiding concurrent console I/O.
Add a bounded execute_in_parallel overload without changing existing callers, plus regression coverage for its concurrency ceiling.