Approaching the exclusive “sub-minute” build time club

For the first time in at least two years (and probably even longer), debhelper with the 10.6.2 upload broke the 1 minute milestone for build time (by mere 2 seconds – look for “Build needed 00:00:58, […]”).  Sadly, the result it is not deterministic and the 10.6.3 upload needed 1m + 5s to complete on the buildds.

This is not the result of any optimizations I have done in debhelper itself.  Instead, it is the result of “questionable use of developer time” for the sake of meeting an arbitrary milestone. Basically, I made it possible to parallelize more of the debhelper build (10.6.1) and finally made it possible to run the tests in parallel (10.6.2).

In 10.6.2, I also made the most of the tests run against all relevant compat levels.  Previously, it would only run the tests against one compat level (either the current one or a hard-coded older version).

Testing more than one compat turned out to be fairly simple given a proper test library (I wrote a “Test::DH” module for the occasion).  Below is an example, which is the new test case that I wrote for Debian bug #866570.

$ cat t/dh_install/03-866570-dont-install-from-host.t
use strict;
use warnings;
use Test::More;

use File::Basename qw(dirname);
use lib dirname(dirname(__FILE__));
use Test::DH;
use File::Path qw(remove_tree make_path);
use Debian::Debhelper::Dh_Lib qw(!dirname);

plan(tests => 1);

each_compat_subtest {
  my ($compat) = @_;
  # #866570 - leading slashes must *not* pull things from the root FS.
  ok(run_dh_tool('dh_install', '/bin/grep*'));
  ok(-e "debian/debhelper/bin/grep-i-licious", "#866570 [${compat}]");
  ok(!-e "debian/debhelper/bin/grep", "#866570 [${compat}]");
  remove_tree('debian/debhelper', 'debian/tmp');

I have cheated a bit on the implementation; while the test runs in a temporary directory, the directory is reused between compat levels (accordingly, there is a “clean up” step at the end of the test).

If you want debhelper to maintain this exclusive (and somewhat arbitrary) property (deterministically), you are more than welcome to help me improve the Makefile. 🙂  I am not sure I can squeeze any more out of it with my (lack of) GNU make skills.

This entry was posted in Debhelper, Debian. Bookmark the permalink.

8 Responses to Approaching the exclusive “sub-minute” build time club

  1. I’m extremely excited to see some of the other debhelper changes that will speed up builds across all packages using debhelper. I’d love to see trivial packages (e.g. metapackages or those that just copy files in place, with no build step) completing in a small fraction of a second.

    • Hah, I am afraid that we are a long way from sub-second builds. I got a demo package similar to what you describe (based on the “goodbye” package) and its build time is measured in 3.5s-4s. Furthermore, the optimizations I have done lately is also mostly focused at making debhelper scale better, so there has been some trade-offs that favour “through-put” over “latency”. But on the plus side, I found and fixed #867982 to counter some of it.

      • I get similar results; building my personal set of metapackages takes 3.43s.

        A few notable things:

        Commands like dh_auto_clean, dh_auto_configure, dh_auto_test, and dh_auto_build take a shockingly long amount of time to decide that they have nothing to do:

        $ time dh_auto_clean

        real 0m0.126s
        user 0m0.104s
        sys 0m0.012s
        $ time dh_auto_build

        real 0m0.124s
        user 0m0.108s
        sys 0m0.008s
        $ time dh_auto_test

        real 0m0.122s
        user 0m0.104s
        sys 0m0.008s

        dh_gencontrol takes a long time as well, though I think most of that is dpkg-gencontrol.

        And an overall strace of a minimal build shows a huge number of programs spawned off, including numerous invocations of chmod, chown, find, tar, and many other things that could be done either 1) natively, 2) once and remembered, or 3) not at all.

      • So, for the dh_auto_*, you are tricked by them being slower when called as standalone vs. called from dh. I think just setting SOURCE_DATE_EPOCH should dramatically reduce the runtime for those. It makes them skip loading of Dpkg::Changelog::Parse, which takes up ~100ms (per command). Incidentially, a dpkg-buildpackage build will load it at least 5 times (4x times in dpkg-* tools and 1x in dh_installchangelogs). So there goes half of our 1s runtime just loading a single perl module (I have mentioned this to guillem over IRC just now).

        As for the spawned off programs, that is exactly some of the things I have improved to make debhelper scale better. Either by bulking calls to external tools or by replacing them with “native” built-ins.

      • Sorry, DH_INTERNAL_BUILDFLAGS=1 + SOURCE_DATE_EPOCH=12345 should make dh_auto_* faster

      • $ time DEB_HOST_GNU_TYPE=foo SOURCE_DATE_EPOCH=12314 DH_INTERNAL_BUILDFLAGS=1 /usr/bin/dh_auto_build

        real 0m0.066s
        user 0m0.056s
        sys 0m0.008s

        All variables are set either by dh or/and dpkg-buildpackage, so they basically only take half of what you original say (in those circumstances). Still could be better if we could avoid running them entirely.

  2. (Also, contrary to the XKCD you linked, saving a few seconds per package, times the number of packages in the archive and the number of architecture buildds, seems quite worthwhile.)

    • The linked XKCD was a reference to the time spent making debhelper’s own build faster. That was a rather questionable usage of developer time! 😀

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s