Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build Semaphore: Working prototype. #971

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

0EVSG
Copy link

@0EVSG 0EVSG commented Jan 21, 2022

This PR is meant as a working prototype for a feature I'd like to discuss -
play around with it and see if there's enough interest to develop a serious
implementation from that.

How it works

Create a semaphore, to restrict the number of builders that may enter the
build phase of their ports. This number is controlled by the
BUILD_SEMAPHORE setting. With a setting of e.g. BUILD_SEMAPHORE=3, no more
than 3 builders are allowed to enter the build phase at a time. Other phases
are unaffected, they are only limited by the total number of builders
(PARALLEL_JOBS).

Rationale

Like others I struggle to find a good compromise between many builders
(PARALLEL_JOBS) and high build concurrency (MAKE_JOBS) that:

  1. Doesn't take eons to build heavy ports like www/chromium.
  2. Builds a big number of lightweight ports at a decent speed.
  3. Doesn't completely overload the system, eventually.

The problem of 1. and 3. is that it requires high build concurrency but few
builders, during the build phase. While 2. demands more builders, that
spend most of their time single threaded in the configure and dependency
phases.

Now with the build semaphore, there is a way to have a decent number of
builders working on 2., while allowing high build concurrency for 1. - since
concurrency only affects the build phase, system load is then restricted
by the semaphore (3.).

Assumptions

As a reality check, effectiveness of the semaphore approach is based on the
following assumptions:

  • The build phase of ports is either short or makes use of concurrency.
  • Other phases of ports building are mostly single threaded.

To my knowledge, this holds true for the vast majority of ports.

Example

Old Xeon workstation with 12C/24T, 48GB RAM. For most of the ports, 6 builders
with -j6 works fine, but for the heavy ones I'd want to use 2 builders with
-j18. An uncached build of chromium with -j18 takes about 5h, I never tried
with less (and I don't intend to).

Therefore my current settings are PARALLEL_JOBS=6, BUILD_SEMAPHORE=2, and
MAKE_JOBS_NUMBER=18 in make.conf. This gives me approximately the overall
speed of 6 builders for the lightweight ports, but with -j18 for the heavy
ones. System load never exceeds 40, which is bearable on this machine.

It's not perfect, some ports tend to have long single threaded link times,
which hurts efficiency a bit with a build semaphore of 2. But all in all it's a
lot faster and more adaptive than anything else I tried.

Caveats

I'm obviously not an experienced shell programmer. The semaphore implementation
is hand-crafted, although apparently working. And the lockf should make it
safe and fair.

Proof of concept. DO NOT MERGE!

Create a semaphore, to restrict the number of builders that may enter
the "build" phase of their ports. This number is controlled by the
"BUILD_SEMAPHORE" setting. With a setting of e.g. "BUILD_SEMAPHORE=3",
no more than 3 builders are allowed to enter the "build" phase at a
time. Other phases are unaffected, they are only limited by the total
number of builders ("PARALLEL_JOBS").
@bdrewery
Copy link
Member

I like what you did here. I'm going to play around with it for a while.

@0EVSG
Copy link
Author

0EVSG commented Apr 21, 2024

I like what you did here. I'm going to play around with it for a while.

As a package maintainer I pretty much rely on this patch to build ports in a timely manner. My partial builds sometimes include hundreds of small packages, sometimes heavy ones like llvm, firefox, chromium or libreoffice, often both. I still haven't found any other solution which adapts to all of those scenarios, especially if you want high build concurrency for a single heavy port, but also not overload the machine if there are five of them.

The values for PARALLEL_JOBS and BUILD_SEMAPHORE certainly have to be adapted to the actual CPU and RAM constraints.

If you consider to add this feature, I'd propose to make the semaphore wait a separate build phase. That way it could be displayed consistently in the CTRL-t stats, unlike the debug prints in the current prototype.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants