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

Incremental build changes #822

Closed
bdrewery opened this issue Jan 16, 2021 · 26 comments
Closed

Incremental build changes #822

bdrewery opened this issue Jan 16, 2021 · 26 comments

Comments

@bdrewery
Copy link
Member

bdrewery commented Jan 16, 2021

We should make bulk -S the default and rely on PORTREVISION bumps. This will greatly reduce package rebuilds.
It depends on freebsd/pkg#1831 which has more details on what needs to change here and how to interact with pkg differently.

Edit: bulk -S isn't exactly same behavior being discussed here. The idea that we don't force rebuild packages because a dependency is updated is what this is. A port version/revision/epoch bump would still do a rebuild.

@bdrewery
Copy link
Member Author

#806 needs to be considered here too.

@karolyi
Copy link

karolyi commented Jul 17, 2021

I'm +1ing here, with elaborating as to why I need this functionality:

I have 2 jails building with mysql dependencies, which in turn (at the time of writing this) builds llvm90 each time of a base system update (freebsd patch level change, for example). llvm90 builds for ~25 minutes each time, with an AMD Ryzen server with 16 cores, while maxing out load.

I think rebuilding llvm only to build mysql-(client|server) is totally superfluous and unnecessary, since it has no custom build options. As it is only needed for the mysql build, it would be fine just to install it from a package repository, for which I have no option now.

So as you can see, the issue isn't just about 'incremental builds', because on a base system change (i.e. the aforementioned freebsd patch level change) poudriere deletes the entire built package tree and rebuilds everything. Which is fine, but llvm could be seeded into the build environment from a binary package, saving lots of time and resources.

@bdrewery
Copy link
Member Author

I have a prototype for this that I will put into the next poudriere-devel for wider testing.

@heliosyne
Copy link

Is there progress on this? I've had to abandon poudriere entirely because I can't get it to not build the entire dependency tree when all I need it to do is build one port with non-default options, and use its testport facility on stuff I maintain.

@bdrewery
Copy link
Member Author

Is there progress on this? I've had to abandon poudriere entirely because I can't get it to not build the entire dependency tree when all I need it to do is build one port with non-default options, and use its testport facility on stuff I maintain.

I'm sorry for the trouble. I feel your pain. The frustration from rebuilds and rust crashing my build system so many times is what keeps me working on this currently.

I have it working locally and have been working over the past month to clean it up before pushing it out. Right now I am focused on adding more tests to capture some of the specific odd cases that the changes ran into. In particular there were no build queue, testport, options, pkgclean, distclean tests committed yet. I have some for each of those now.

It's a big change and as I tested it more I found more pieces which were needing manual testing. So I've been adding more tests around those areas.

 148 files changed, 8783 insertions(+), 2863 deletions(-)

Most of that is just in the test dir:

 108 files changed, 4087 insertions(+), 459 deletions(-)

The new build tests explicitly are checking for what is built to make sure only what is needed to rebuild is rebuilt.

It's coming soon. I want it out within the next week or two.

@karolyi
Copy link

karolyi commented Dec 15, 2022

Really looking forward to this.

Just another example: today another ca_root_nss arrived, which in turn made curl to rebuild, which in turn made rust to rebuild, which in turn made clamd rebuild. I only really use clamd.

Rust builds for ~35 minutes, burning all 16 cores in my server.

@michael-o
Copy link

Really looking forward to this.

Just another example: today another ca_root_nss arrived, which in turn made curl to rebuild, which in turn made rust to rebuild, which in turn made clamd rebuild. I only really use clamd.

Rust builds for ~35 minutes, burning all 16 cores in my server.

I feel with you. ca_root_nss is one of the most useless ports these days, it has been long superseded with the CA certs system in base (though a few fixes need to be done). I am look at you @kevans91 ;-)

@igalic
Copy link
Contributor

igalic commented Dec 16, 2022

this makes me think that there probably are a number of dependencies out there that when bumped don't need packages depending on them to rebuild.

as in: it might need verification / testing, but not a rebuild.

How many people who use poudriere run a package's tests?

@bdrewery
Copy link
Member Author

bdrewery commented Dec 16, 2022

Poudriere running tests will be handled in #355. Probably a lot don't get ran.

Not exactly responding to what you're asking but it made realize I should brain dump this out somewhere.

In general what I can think of that needs a chased rebuild (PORTREVISION bump) are

  • Package provides a shared library with a new name/version
  • Package provides a static library that has changed
  • Package is a generator tool like a compiler
  • Package is a script runtime (Perl, Ruby, Python, PHP)
    • Ruby has bitten me here but I am unsure why.
  • Package consumers modules built by other packages with strict API requirements.
    • PHP will bump its API version and fail to load extensions not rebuilt to match the new version.
  • Default version changes like freebsd/freebsd-ports@8fd85e6

Through testing this change over the past year I have ran into most of those. Each was very confusing to debug and they were not obviously because of this change. That's a big reason I've been moving slow on releasing this.

Simple changes like a shared library package has behavior changed or docs changed but the shlib version does not change - no PORTREVISION chase is needed.

Some of these don't require a chased rebuild for functionality but for the sake of reproducible builds they do. When we communicate the "new" rebuild to porters we'll want the key point that anything that changes reproducibility of downstream packages will require a PORTREVISION chase.

Committers do forget to do a chase, or are unaware that it is needed, or rely on Poudriere to do the chasing for them. Relying on Poudriere was never the right thing because for reproducibility.

The only case I have special checks for are shared libraries. If a package requires shared libraries it will check that the package that provides the library still provides it. If not then it rebuilds the package assuming that the shared library has a newer version/name to use. This is non-trivial. Ports don't tell what libraries they provide in an easy way. Ports do say which they require but not what they provide. So Poudriere needs to do a lot of work to make these decisions which can lead to a NOP-build spending minutes solving which packages provide which libraries. This special case is a big reason I haven't pushed this out yet as I'm unhappy with how it is implemented. I need to make it smarter but need tests for it first. I didn't add tests initially.

I could see handling some of the other special cases depending on community testing of the change.

@bdrewery
Copy link
Member Author

I have 2 more commits to add tests for. It's almost done.

@grahamperrin
Copy link
Contributor

Does work in progress on this issue explain why ports such as llvm15 are sometimes queued, then not (a good thing)?

@karolyi
Copy link

karolyi commented Dec 25, 2023

3.4.0 (installed from latest) shipped with a change that reads amongst others:

…
- testport|bulk -b: New feature to fetch remote packages. See PACKAGE_FETCH
  options in poudriere.conf.sample.
…

@bdrewery, is this the change we've been waiting for? I've set this up, couldn't test it as there are no updates for my jails now (in terms of curl/rust or anything that pulls these). I've did a quick run, couple python packages updated, nothing significant that would put a real strain on my server.

Merry Christmas btw.

@karolyi
Copy link

karolyi commented Jan 9, 2024

Well, if it is, it's not working. Even when I specified PACKAGE_FETCH_WHITELIST="rust", it gets rebuilt no matter what.

@igalic
Copy link
Contributor

igalic commented Jan 9, 2024

sometimes, rust changes underneath, due to transient dependencies, such as curl updating.

if the rust in package repos is recorded with the old version of curl, your local build will, unfortunately correctly, determine that rust needs to be rebuilt.

it would be nice to find ways around this, especially in cases where there was no ABI change to a library.

@ohaucke
Copy link

ohaucke commented Jan 10, 2024

@igalic You could get the lastest commit hash, that was used for the builds, from here https://pkg-status.freebsd.org/api/1/builds?type=package&latest=True and use it for the git checkout to run your build.

That way, i usually don't need to build rust, gcc & llvm

bdrewery added a commit that referenced this issue Feb 19, 2024
This is dealing with dependencies that have a changed PKGBASE from what the
package is looking for.

A specific example here is freebsd/freebsd-ports@9196671
which changed the PKGBASE for net/openldap24-client from openldap-client
to openldap24-client.  Packages such as php74-ldap were depending on
this metadata:
	"openldap-client":{"origin":"net/openldap24-client"}
That would cause pkg-add (during make depends) to try installing
openldap-client-*.pkg.  That would not be found since the openldap package
was now named openldap24-client-VER.pkg, having been rebuilt for a changed
PKGNAME itself.  But reverse deps didn't have the logic to rebuild on
changed dep pkgnames.

Note that this was discovered with the PKG_NO_VERSION_FOR_DEPS feature
because but the root cause is the removal of the recursive deleting of
packages; default SKIP_RECURSIVE_REBUILD==1 causes this.

Issue #822
@bdrewery bdrewery modified the milestones: 3.4.0, 3.5.0 Feb 19, 2024
@bdrewery
Copy link
Member Author

I merged in the major test framework changes this depends on today. I plan to merge the feature in "soon". Subpackages became a distraction but I've decided I'll leave subpackages broken and focus on getting this in.

bdrewery added a commit that referenced this issue Feb 27, 2024
This allows the job queue to have smarter dependencies for ordering
jobs. This will allow things like TEST_DEPENDS, and fixes some issues
with TRIM_ORPHANED_BUILD deps (which the removed XFAIL tests test for).

Some job types do not do anything except provide ordering. They are
trimmed from the queue at the time of running.

Rework the queue to support just-in-time determination of whether a port needs
to build or not.  That is, on startup do not remove items from the queue that
are not needed.  They will be trimmed out when eligible to be ran.  This incurs
slight overhead but avoids a lot of problems with determining the proper
dependency graph needs or optimizing it early on which can do the wrong thing.

This is primarily needed to support PKG_NO_VERSION_FOR_DEPS which avoids
deleting packages that do not need a rebuild (effectively defaults
SKIP_RECURSIVE_REBUILD to 1.  In that case we ended up in a situation where
some dependencies in the middle of the graph did not need a rebuild but items
further down the chain did.  The trimming would incorrectly clear out the
middle down, losing the needed rebuild.  An example is someport -> patchutils
-> bash.  If patchutils did not need a rebuild, but bash did, the queue was
trimming out both patchutils and bash.  Determining what needed to be kept
pre-build was overly complex.  With this method we determine the need on visit
right before build.

Fixes #806 - The TRIM_ORPHANED_BUILD_DEPS problem and similar solution.
Issue #822
bdrewery added a commit that referenced this issue Feb 27, 2024
This flag was a hack to avoid recursively rebuilding packages but a
fatal flaw is that Pkg records the versions of dependencies. If that
specific version is not available then Pkg breaks. The intent of this
feature was to respect version bumps (and other rebuild checks) rather
than forcing a rebuild of everything. That feature is coming in
Issue #822.

If for some reason this is needed then SKIP_RECURSIVE_REBUILD=1 can be
used in poudriere.conf.

Issue #806
@bdrewery
Copy link
Member Author

It's happening. I had a few hundreds commits behind this work that are now merged. There's only 3 commits left to merge. I'm fixing up some shared library tracking changes and then this will be in.

@markmcb
Copy link

markmcb commented May 7, 2024

@bdrewery, not sure if this is the best place to call it out, but -S is still listed 3 times in the poudriere-bulk(8) synopsis (version poudriere-git-3.4.99.20240424).

SYNOPSIS
     poudriere bulk -a -j name [-CcFIikNnRrSTtvw] [-B name] [-b branch]
                    [-J maxjobs[:prebuildmaxjobs]]
                    [-O overlay [-O overlay2 ...]] [-p tree] [-z set]
     poudriere bulk -f file [-f file2 ...] -j name [-CcFIikNnRrSTtvw]
                    [-B name] [-b branch] [-J maxjobs[:prebuildmaxjobs]]
                    [-O overlay [-O overlay2 ...]] [-p tree] [-z set]
     poudriere bulk -j name [-CcFIikNnRrSTtvw] [-B name] [-b branch]
                    [-J maxjobs[:prebuildmaxjobs]]
                    [-O overlay [-O overlay2 ...]] [-p tree] [-z set]
                    origin ...

bdrewery added a commit that referenced this issue Jul 8, 2024
@bdrewery
Copy link
Member Author

bdrewery commented Jul 8, 2024

@markmcb thanks, fixed.

I have merged this into git. Updating the port now. Off-by-default. I will send an email to ports later today explaining how to enable, use, and debug it.

freebsd-git pushed a commit to freebsd/freebsd-ports that referenced this issue Jul 8, 2024
Changes:
 - bulk: Major changes for incremental build with PKG_NO_VERSION_FOR_DEPS=yes
   o Off-by-default for now
   o Poudriere will no longer force rebuild all reverse dependencies when a
     dependency is updated.
   o It will now only rebuild a port if pkg-upgrade(8) would automatically
     reinstall it. Cases such as changed dep libraries, options, ABI.
   o dependencies will be generated into the .pkg files without a
     version. You may see "-(null)" in some places that is expected.
   o Remote fetching will look for both versioned and unversioned
     dependencies that satisfy the current port build request.
   o A recursive rebuild *will be done* if the involved packages in the
     set have versioned dependencies, until all packages involved use
     the new unversioned dependency.
   o Setting PKG_NO_VERSION_FOR_DEPS back to no will recursively rebuild
     all packages back to the previous behavior with versioned deps.
   o PORTREVISION chases are critical to do in cases like language
     updates (ruby,perl,python,etc) or <static> library updates.
   o Shared library version updates still require their port consumers to be
     rebuilt to link to the new shared library. Porters are not used to
     always PORTREVISION chasing when doing this, and it is not always
     practical. Because of this Poudriere will now "inspect" shared
     library consuming packages *during the build* before deciding if
     they need to be rebuilt. There is likely a lot of room for
     optimization here to avoid Poudriere rechecking packages every
     build; currently a scale of seconds per package. Some metadata
     tracking in Ports would help improve this too. More work needs to
     be done still to improve the reporting and display of this process
     in the queue and web interface. Currently they just get marked
     "ignored" after being checked.
   o freebsd/poudriere#822 (link to generate
     notification for interested people)
 - bulk: -S was removed. The new PKG_NO_VERSION_FOR_DEPS feature
   replaces it and will become default after public testing
 - Support MAX_EXECUTION_TIME_$pkgbase in poudriere.conf
 - image: Use gptboot.efi in place of loader.efi to support bootme and bootonce
 - image: Enable space optimisation and disable minfree on read-only firmware images
 - image: Set a GPT label for EFI partition
 - image: Generate the upgrade image too
@bdrewery
Copy link
Member Author

bdrewery commented Jul 8, 2024

See freebsd/freebsd-ports@eef5ff6 for summary of feature

nanorkyo pushed a commit to nanorkyo/freebsd-ports that referenced this issue Jul 9, 2024
Changes:
 - bulk: Major changes for incremental build with PKG_NO_VERSION_FOR_DEPS=yes
   o Off-by-default for now
   o Poudriere will no longer force rebuild all reverse dependencies when a
     dependency is updated.
   o It will now only rebuild a port if pkg-upgrade(8) would automatically
     reinstall it. Cases such as changed dep libraries, options, ABI.
   o dependencies will be generated into the .pkg files without a
     version. You may see "-(null)" in some places that is expected.
   o Remote fetching will look for both versioned and unversioned
     dependencies that satisfy the current port build request.
   o A recursive rebuild *will be done* if the involved packages in the
     set have versioned dependencies, until all packages involved use
     the new unversioned dependency.
   o Setting PKG_NO_VERSION_FOR_DEPS back to no will recursively rebuild
     all packages back to the previous behavior with versioned deps.
   o PORTREVISION chases are critical to do in cases like language
     updates (ruby,perl,python,etc) or <static> library updates.
   o Shared library version updates still require their port consumers to be
     rebuilt to link to the new shared library. Porters are not used to
     always PORTREVISION chasing when doing this, and it is not always
     practical. Because of this Poudriere will now "inspect" shared
     library consuming packages *during the build* before deciding if
     they need to be rebuilt. There is likely a lot of room for
     optimization here to avoid Poudriere rechecking packages every
     build; currently a scale of seconds per package. Some metadata
     tracking in Ports would help improve this too. More work needs to
     be done still to improve the reporting and display of this process
     in the queue and web interface. Currently they just get marked
     "ignored" after being checked.
   o freebsd/poudriere#822 (link to generate
     notification for interested people)
 - bulk: -S was removed. The new PKG_NO_VERSION_FOR_DEPS feature
   replaces it and will become default after public testing
 - Support MAX_EXECUTION_TIME_$pkgbase in poudriere.conf
 - image: Use gptboot.efi in place of loader.efi to support bootme and bootonce
 - image: Enable space optimisation and disable minfree on read-only firmware images
 - image: Set a GPT label for EFI partition
 - image: Generate the upgrade image too
bdrewery added a commit that referenced this issue Aug 11, 2024
This reverts commit 1585103.

Revert "poudriere-bulk.8: -S was removed."

This reverts commit 7dfd84b.

Restore -S for now. The behavior of reverting to recursive delete
with -S for compat was too surprising. The removal of -S was intended
for once PKG_NO_VERSION_FOR_DEPS was done.

Issue #822
@karolyi
Copy link

karolyi commented Sep 27, 2024

Hey,

I started using poudriere-devel a while ago, and wanted to wait for this moment, until curl becomes updated and per the poudriere-stable branch, rust would be recompiled because of it.

I was hoping that this devel version and the changes you added within would solve this issue but it didn't. Curl had a new version today, and rust will be recompiled, whereas rust is only needed for the compilation of clamd, which means a binary version of it would be totally fine for the time of the compilation. Same goes for mysql-server in another jail, that is only pulled in by teamspeak-server and isn't used.

Deleting rust-1.81.0.pkg: missing dependency: curl-8.10.0_1

So my question is: do you have information on how I can avoid this with poudriere-devel? Compiling rust is not only unnecessary, it takes huge resources, as it takes 36 minutes with my server sweating blood. Same with mysql-server.

Thanks for your help in advance.

@markmcb
Copy link

markmcb commented Sep 27, 2024

@karolyi do you have PKG_NO_VERSION_FOR_DEPS=yes set in poudriere.conf?

I had the same update and a rust rebuild was not triggered. It’s been working as expected for me.

@karolyi
Copy link

karolyi commented Sep 27, 2024

@markmcb thanks for your reply. No I don't, because I wasn't sure what exactly I should have used to not have rust rebuilt.

I'll try next time (I guess I can't avoid building it now), but the cleanest solution would be just to pull a rust binary for the build time, and maybe to the packages. In my case, it isn't even installed when I install the jail, since it's not a requirement.

@karolyi
Copy link

karolyi commented Sep 27, 2024

Hm. I made a build with -S (no PKG_NO_VERSION_FOR_DEPS=yes added yet), and it skipped building mysql-server for the other jail.

Now I removed -S as it is claimed to be deprecated and added PKG_NO_VERSION_FOR_DEPS=yes. Now it started to rebuild cmake-core and will rebuild mysql-server too I think.

Update: yes it is rebuilding mysql-server too.

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

No branches or pull requests

9 participants