?

Log in

No account? Create an account
 
 
13 November 2010 @ 12:29 pm
cowbuilder and eatmydata  

If you use pbuilder, you probably already use cowbuilder too, in order to save on chroot instantiation time. You also probably use ccache in order to save on compilation time.

If you do that, the longest time taken by your build is, by far, the time needed to install the build-dependencies, because dpkg likes to fsync() every file it writes. It’s a good thing it does that on your main system, but in a disposable chroot you really, really don’t care what happens to it if the system crashes. Thanks to Mike, I discovered eatmydata, and tried it with cowbuilder.

If you want to try it out, add this to your pbuilderrc file:

EXTRAPACKAGES="eatmydata"

if [ -z "$LD_PRELOAD" ]; then
  LD_PRELOAD=/usr/lib/libeatmydata/libeatmydata.so
else
  LD_PRELOAD="$LD_PRELOAD":/usr/lib/libeatmydata/libeatmydata.so
fi
export LD_PRELOAD

You will also need to install eatmydata in your chroot, unless you want to regenerate it from scratch. And now you can enjoy your super-fast builds.

 
 
 
heviosso: owlheviosso on November 13th, 2010 12:21 pm (UTC)
I like preload libraries with great names. :)
(Anonymous) on November 13th, 2010 12:55 pm (UTC)
Testing it
How can I test that it's proprly working, please?
np237np237 on November 13th, 2010 12:58 pm (UTC)
Re: Testing it
When it works, dpkg will unpack around 2 packages/second on a reasonably fast machine. Without it, each one will take several seconds to unpack.

You can check the environment in the dpkg process (/proc/$pid/environ) when it is running, to confirm the LD_PRELOAD variable is passed, and check that the preload library is correctly installed in the chroot.
(Anonymous) on November 14th, 2010 06:53 pm (UTC)
Simpler approach to setting LD_PRELOAD
export LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}/usr/lib/libeatmydata/libeatmydata.so"


(Note that this does not require bash; POSIX sh has the :+ mechanism and allows export with a value.)
hyperair [launchpad.net] on November 14th, 2010 08:46 pm (UTC)
sync() not fsync()
I believe recent versions of dpkg prefer to use sync() once per package extract as opposed to fsync() on every file written as an optimization against extN's fsync performance issues. However, this has some impact on other filesystems, especially when using something like sbuild with a aufs layered upon tmpfs setup, as the sync() flushes every other filesystem as well, resulting in unnecessary I/O and delays during the unpacking phase.

Naturally, libeatmydata is an awesome choice. For some reason, setting LD_PRELOAD before sbuild doesn't work so well as schroot likes stripping away env variables, so if you use sbuild, you'll have to dpkg-divert your dpkg (in each chroot) away and use a custom script that adds the LD_PRELOAD and then exec()s the real dpkg. Something like this:-

#!/bin/sh
export LD_PRELOAD=/usr/local/lib/libnosync.so
exec /usr/bin/dpkg.distrib "$@"

In my case, I used a custom written libnosync.so that clobbers sync(), fsync() and fdatasync() because I hadn't heard of eatmydata at that point of time, plus it can be rolled out to old chroots which don't have the package.
mirabilosmirabilos [mirsolutions.de] on November 15th, 2010 12:20 pm (UTC)
Install and wrap
For Debian/m68k, I’m currently using something like this:

cowbuilder --create --mirror http://www.freewrt.org/~tg/debs68k/ --distribution sid --debootstrapopts --variant=buildd --debootstrapopts --include=wtf-debian-keyring,debian-ports-archive-keyring,eatmydata,fakeroot --debootstrapopts --keyring=/usr/share/keyrings/wtf-debian-keyring.gpg

This is to create. Of course, --mirror varies, and the two additional
keyring packages (--include) and SecureAPT validation key (--keyring)
will differ, but the gist is, include eatmydata (and fakeroot, to speed
things up – now if pbuilder wouldn’t try to install it if it’s already
there…) at creation time.

Then, I use wrapper scripts for compilation, like this:

#!/bin/sh
case $DEBEMAIL in
*' <'*'@'*'>') ;;
*) echo >&2 "\$DEBEMAIL ($DEBEMAIL) not correct"; exit 1 ;;
esac
exec env LANG=C LC_CTYPE=C LC_NUMERIC=C LC_TIME=C LC_COLLATE=C LC_MONETARY=C LC_MESSAGES=C LC_PAPER=C LC_NAME=C LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=C LC_IDENTIFICATION=C LC_ALL=C eatmydata cowbuilder --debbuildopts "-m'$DEBEMAIL'" --hookdir $HOME/pb-hook --build "$@"

The -m"$DEBEMAIL" is needed because I “play buildd” and use this for
porter uploads; of course you should skip that for regular use, especially
sponsored uploads. Resetting the locale has also proven better – quells
error messages. I use the hook directory _at least_ to let it error out
into a shell instead of removing the cow-chroot upon build failure, so I
can investigate. (Sometimes, I also use it to pre-install dependencies,
e.g. if I need older arch:all packages – on m68k –, backports – on hardy
(at work) or lenny –, or the .dsc contains architecture wildcards, which
pbuilder (#363193) still doesn’t handle.)

Full details: https://www.freewrt.org/~tg/debs68k/0-NOTE.txt

You can, by the way, “sudo eatmydata cowbuilder --login” (or use the bL
script) and check the environment variables for yourself; if LD_PRELOAD
contains libeatmydata and LC_* and LANG are set to "C", everything is fine.
mirabilosmirabilos [mirsolutions.de] on November 18th, 2010 09:17 am (UTC)
Latest eatmydata…
… has symlink mode. Check that one out. Looks like fun.
(Anonymous) on November 26th, 2010 04:51 am (UTC)
dpkg force-unsafe-io
A much simpler solution is to use dpkg's new force-unsafe-io option (available in 1.15.8.6).
Just drop a small file containing "force-unsage-io" in your etc/dpkg/dpkg.cfg.d directory of your chroot.