How to use Icecream with Yocto Project® builds

Objectives

This post shows you how to use Icecream with Yocto Project® builds – ideally using the “Reliable Embedded Systems Yocto Project®/OpenEmbedded build framework“.

Prerequisites

This build framework uses a docker build container to run “BitBake“. The build framework already contains Icecream [more details here] as an icecc-container and in the build-container are the relevant components installed as well. If you want to learn more about the Yocto Project® and Icecream check out this video:

Icecream

The git repo of Icecream mentions: “Icecream was created by SUSE based on distcc. Like distccIcecream takes compile jobs from a build and distributes them among remote machines allowing a parallel build. But unlike distccIcecream uses a central server that dynamically schedules the compile jobs to the fastest free server. This advantage pays off mostly for shared computers, if you’re the only user on x machines, you have full control over them.”

Icecream-sundae

Icecream-sundae is a Commandline Monitor for Icecream written by our friend Joshua Watt.

Setup

Overview

We have three machines available for our little experiment. Let’s assume they are called e450-4, e450-5 and e450-6

Machineicecc-schedulericeccdicecream-sundaeBitbake build
e450-4yesyesyes
e450-5yesoptionalyes
e450-6yesoptional
What should run on which machine?

e450-4

icecc-container

Let’s start the icecc-container with iceccd and the icecc-scheduler:

student@e450-4:/workdir⟫ 
cd /workdir/crops-container-x86-64/icecc-container/non-local_scripts
./docker_run.sh reliableembeddedsystems/icecream-container:2021-04-08 sched
...
++ docker run --name icecream_container -d -e ICECC_ENABLE_SCHEDULER=1 --net=host reliableembeddedsystems/icecream-container:2021-04-08
Unable to find image 'reliableembeddedsystems/icecream-container:2021-04-08' locally
2021-04-08: Pulling from reliableembeddedsystems/icecream-container
004f1eed87df: Pull complete 
4b53851c008a: Pull complete 
fcc89a6ff4b7: Pull complete 
4b147887ebe6: Pull complete 
579faa19e08b: Pull complete 
Digest: sha256:88ab1391ad5f997ee7d9877e9cb59b24e5d90ed079eeaed2cd05d280b9965950
Status: Downloaded newer image for reliableembeddedsystems/icecream-container:2021-04-08
765f6d502e0f4a30d2578102c72791199c0c652e294f3c3fe240db969fa5a342

icecream-sundae

Let’s start Icecream-sundae from the same or another shell on the same machine:

student@e450-4:~⟫ 
cd /workdir/crops-container-x86-64/icecc-container/non-local_scripts
./icecream-sundae.sh
Command line Icecream status monitor, Version 1.0.0
Copyright (C) 2018 by Garmin Ltd. or its subsidiaries.
This is free software, and you are welcome to redistribute it
under certain conditions; run with '--about' for details.
ignoring localhost lo
broadcast enp3s0 192.168.42.255
broadcast docker0 172.17.255.255
Suitable scheduler found at 192.168.42.104:8765 (version: 39)
Suitable scheduler found at 192.168.42.104:8765 (version: 39)
Selecting scheduler at 192.168.42.104:8765
scheduler is on 192.168.42.104:8765 (net ICECREAM)
Done waiting
Got scheduler 192.168.42.104

You should see something like that, which means that iceccd and the icecc-scheduler are running:

Scheduler: 192.168.42.104 Netname: ICECREAM
Servers: Total:1 Available:1 Active:0
Total: Remote:0 Local:0
Jobs: Maximum:8 Active:0 Local:0 Pending:0
      [        ]

v ID NAME   IN    CUR MAX JOBS       OUT   LOCAL ACTIVE PENDING SPEED
+ 1  e450-4 0     0   8   [        ] 0     0     0      0       0

e450-6

iceccd

Here we only need iceccd as explained in our plan from above.

student@e450-6:/workdir⟫ 
cd /workdir/crops-container-x86-64/icecc-container/non-local_scripts
./docker_run.sh reliableembeddedsystems/icecream-container:2021-04-08

Monitor changes with Icecream-sundae

Scheduler: 192.168.42.104 Netname: ICECREAM
Servers: Total:2 Available:2 Active:0
Total: Remote:0 Local:0
Jobs: Maximum:16 Active:0 Local:0 Pending:0
      [                ]

v ID NAME   IN    CUR MAX JOBS       OUT   LOCAL ACTIVE PENDING SPEED
+ 1  e450-4 0     0   8   [        ] 0     0     0      0       0
+ 2  e450-6 0     0   8   [        ] 0     0     0      0       0

e450-5

Our plan says that we want iceccd. Also BitBake will be started here in a build-container.

iceccd

That’s pretty much the same story with what you saw on the machine e450-6.

student@e450-5:/workdir⟫ 
cd /workdir/crops-container-x86-64/icecc-container/non-local_scripts
./docker_run.sh reliableembeddedsystems/icecream-container:2021-04-08
...
++ docker run --name icecream_container -d --net=host reliableembeddedsystems/icecream-container:2021-04-08
Unable to find image 'reliableembeddedsystems/icecream-container:2021-04-08' locally
2021-04-08: Pulling from reliableembeddedsystems/icecream-container
004f1eed87df: Pull complete 
4b53851c008a: Pull complete 
fcc89a6ff4b7: Pull complete 
4b147887ebe6: Pull complete 
579faa19e08b: Pull complete 
Digest: sha256:88ab1391ad5f997ee7d9877e9cb59b24e5d90ed079eeaed2cd05d280b9965950
Status: Downloaded newer image for reliableembeddedsystems/icecream-container:2021-04-08
d182381e640e6b601fbbfe05863af039c0a8f8b4bb602b6e24d080fae10f4755

Apparently, if you just want to add another builder to the network you could just execute the following on any machine even without installing the “Reliable Embedded Systems Yocto Project®/OpenEmbedded build framework“:

docker run --name icecream_container -d --net=host reliableembeddedsystems/icecream-container:2021-04-08

Monitor changes with Icecream-sundae

If everything works as expected, Icecream-sundae, which runs on the machine e450-4, should show that machine e450-5 has joined:

Scheduler: 192.168.42.104 Netname: ICECREAM
Servers: Total:3 Available:3 Active:0
Total: Remote:0 Local:0
Jobs: Maximum:24 Active:0 Local:0 Pending:0
      [                        ]

v ID NAME   IN    CUR MAX JOBS       OUT   LOCAL ACTIVE PENDING SPEED
+ 1  e450-4 0     0   8   [        ] 0     0     0      0       0
+ 2  e450-6 0     0   8   [        ] 0     0     0      0       0
+ 3  e450-5 0     0   8   [        ] 0     0     0      0       0

build container

Make sure that /workdir/resy-poky-container.sh is configured properly:

#!/bin/bash
...
USE_ICECC="yes"
...
if [[ $USE_ICECC = yes ]]; then
   ICECC="--net=host "
fi

Start up the build container:

student@e450-5:/workdir
./resy-poky-container.sh
pick build target/fetch sources/inspect some variables
pokyuser@e450-5:/workdir/build$ 
# let's pick some generic multi-v7 target:
source /workdir/resy-cooker.sh multi-v7-ml-master
# don't yet configure the icecc stuff, but let's fetch whatever is needed
bitbake core-image-minimal --runall=fetch
# let's try to determine what are the "default" values for some of the values we will change:
bitbake -e | grep ^PARALLEL_MAKE=
PARALLEL_MAKE="-j 8"
bitbake -e | grep ^BB_NUMBER_THREADS=
BB_NUMBER_THREADS="-j 8"
adjust local.conf
student@e450-5:~⟫ 
cd /workdir/build/multi-v7-ml-master/conf
vim local.conf
# --> icecc
# total number of local/builder CPU cores * 2 or * 3?
# This variable usually takes the form of “-j x”, 
# where x represents the maximum number of parallel threads make can run.
# needs some playing
# 68 CPU cores total in my setup
ICECC_PARALLEL_MAKE?= "-j ${@oe.utils.cpu_count()*3}"
######################################################################
# Problem:  Icecream and sstate can be combined, however inheriting
#           icecc.bbclass changes most taskhashes
#           Which makes the SSTATE created with icecc unusable for 
#           builds without it.
# Solution: Always inherit icecc.bbclass and use ICECC_DISABLED ?= “1”
#           to turn off icecream for builds without icecc which want to
#           use the SSTATE created with icecc.

INHERIT += "icecc"
ICECC_DISABLED ??= "0"
######################################################################

# Blacklist packages from compiling with icecream. There really needs to be a
# better way to share this list...
# let's start with an empty Blacklist and see how things are going
ICECC_USER_PACKAGE_BL += "glib-2.0 bazel-native tensorflow-native"
# <-- icecc
build
pokyuser@e450-5:/workdir/build$ bitbake core-image-minimal
Monitor situation with Icecream-sundae

You might want to do some more fine-tuning. Here you see that all three machines are busy:

Scheduler: 192.168.42.104 Netname: ICECREAM
Servers: Total:3 Available:3 Active:3
Total: Remote:2646 Local:1615   
Jobs: Maximum:24 Active:24 Local:1 Pending:3
      [%=======================]

v ID NAME   IN    CUR MAX JOBS       OUT   LOCAL ACTIVE PENDING SPEED
+ 1  e450-4 912   8   8   [========] 0     0     0      0       0
+ 2  e450-6 1522  8   8   [========] 0     0     0      0       0
+ 3  e450-5 212   8   8   [%=======] 2646  1615  24     3       83.6531

With a few more machines it might look like this:

Scheduler: 192.168.42.104 Netname: ICECREAM
Servers: Total:10 Available:10 Active:10
Total: Remote:11617 Local:5349   
Jobs: Maximum:68 Active:54 Local:0 Pending:0
      [======================================================              ]

v ID NAME    IN    CUR MAX JOBS       OUT   LOCAL ACTIVE PENDING SPEED
+ 3  e450-5  966   2   8   [==      ] 11617 5349  54     0       70.4266
+ 9  e450-12 41    2   4   [==  ]     0     0     0      0       0
+ 8  e450-11 67    4   4   [====]     0     0     0      0       47.3424
+ 10 e450-13 79    4   4   [====]     0     0     0      0       79.2168
+ 7  e450-10 111   6   8   [======  ] 0     0     0      0       40.9161
+ 1  e450-4  4243  7   8   [======= ] 0     0     0      0       101.404
+ 2  e450-6  4314  7   8   [======= ] 0     0     0      0       110.203
+ 4  e450-3  1451  7   8   [======= ] 0     0     0      0       158.049
+ 5  e450-7  173   7   8   [======= ] 0     0     0      0       0
+ 6  e450-8  172   8   8   [========] 0     0     0      0       47.6192

Benchmark

The Icecream cluster consists of ten machines (including the build machine) and a total of 68 CPUs. We don’t use any SSTATE_MIRRORS. Therefore it’s enough to clean only the local “sstate“. We will build core-image-minimal with and without the Icecream cluster and measure how long it takes with time(1).

Benchmark with Icecream cluster

Clean local sstate

rm -rf /workdir/build/multi-v7-ml-master/tmp/
rm -rf /workdir/sstate_master/

Adjust local.conf

It should be fine if you use the one from above. Make sure Icecream is enabled:

ICECC_DISABLED ?= "0"

Test run

Let’s monitor the Icecream cluster activity with Icecream-sundae which runs on the machine e450-4 in order to ensure that Icecream is actually being used.

pokyuser@e450-5:/workdir/build/multi-v7-ml-master$ time bitbake core-image-minimal
NOTE: Started PRServer with DBfile: /workdir/build/multi-v7-ml-master/cache/prserv.sqlite3, IP: 127.0.0.1, PORT: 43990, PID: 22009
Loading cache: 100% |                                                                                                                                                         | ETA:  --:--:--
Loaded 0 entries from dependency cache.
Parsing recipes: 100% |########################################################################################################################################################| Time: 0:01:22
Parsing of 2393 .bb files complete (0 cached, 2393 parsed). 3676 targets, 140 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION           = "1.49.2"
BUILD_SYS            = "x86_64-linux"
NATIVELSBSTRING      = "ubuntu-18.04"
TARGET_SYS           = "arm-resy-linux-gnueabi"
MACHINE              = "multi-v7-ml"
DISTRO               = "resy"
DISTRO_VERSION       = "3.3"
TUNE_FEATURES        = "arm armv7a vfp thumb callconvention-hard"
TARGET_FPU           = "hard"
meta
meta-poky
meta-yocto-bsp       = "master:e1839b58ebe05242a52fe050aa9a08140136aa0a"
meta-multi-v7-ml-bsp-master = "master:00f716ef03a6d37489cf8f1704a566938d3c7c64"
meta-resy-master     = "master:48562f43bed481ad342d92b9cdcb45fa75487f58"
meta-oe
meta-networking
meta-filesystems
meta-python          = "master:5d8dfa1ad4ac5d32536a10c9e299a3dd17296fc9"

Initialising tasks: 100% |#####################################################################################################################################################| Time: 0:00:02
Sstate summary: Wanted 973 Local 0 Network 0 Missed 973 Current 0 (0% match, 0% complete)
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 2628 tasks of which 0 didn't need to be rerun and all succeeded.
NOTE: Writing buildhistory
NOTE: Writing buildhistory took: 5 seconds

real    69m45.366s
user    0m14.576s
sys     0m2.208s

Benchmark without Icecream cluster

Let’s clean the local SSTATE

rm -rf /workdir/build/multi-v7-ml-master/tmp/
rm -rf /workdir/sstate_master/

Adjust local.conf

Make sure Icecream is disabled:

ICECC_DISABLED ?= "1"

Test run

Let’s monitor the Icecream cluster activity with Icecream-sundae which runs on the machine e450-4 in order to ensure that Icecream is actually not being used.

pokyuser@e450-5:/workdir/build/multi-v7-ml-master$ time bitbake core-image-minimal
NOTE: Started PRServer with DBfile: /workdir/build/multi-v7-ml-master/cache/prserv.sqlite3, IP: 127.0.0.1, PORT: 33841, PID: 32237
Loading cache: 100% |                                                                                                                                                         | ETA:  --:--:--
Loaded 0 entries from dependency cache.
Parsing recipes: 100% |########################################################################################################################################################| Time: 0:01:25
Parsing of 2393 .bb files complete (0 cached, 2393 parsed). 3676 targets, 140 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies

Build Configuration:
BB_VERSION           = "1.49.2"
BUILD_SYS            = "x86_64-linux"
NATIVELSBSTRING      = "ubuntu-18.04"
TARGET_SYS           = "arm-resy-linux-gnueabi"
MACHINE              = "multi-v7-ml"
DISTRO               = "resy"
DISTRO_VERSION       = "3.3"
TUNE_FEATURES        = "arm armv7a vfp thumb callconvention-hard"
TARGET_FPU           = "hard"
meta                 
meta-poky            
meta-yocto-bsp       = "master:e1839b58ebe05242a52fe050aa9a08140136aa0a"
meta-multi-v7-ml-bsp-master = "master:00f716ef03a6d37489cf8f1704a566938d3c7c64"
meta-resy-master     = "master:48562f43bed481ad342d92b9cdcb45fa75487f58"
meta-oe              
meta-networking      
meta-filesystems     
meta-python          = "master:5d8dfa1ad4ac5d32536a10c9e299a3dd17296fc9"

Initialising tasks: 100% |#####################################################################################################################################################| Time: 0:00:02
Sstate summary: Wanted 973 Local 0 Network 0 Missed 973 Current 0 (0% match, 0% complete)
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 2628 tasks of which 0 didn't need to be rerun and all succeeded.
NOTE: Writing buildhistory
NOTE: Writing buildhistory took: 3 seconds

real    88m8.270s
user    0m15.180s
sys     0m2.608s

Benchmark Result

Icecreamtotal time (min./sec.)time (sec.)increase (%)decrease (%)
Icecream utilized69m45.366s4185.366s20.86%
Icecream not used88m8.270s5288.27026.35%

Conclusion

If we compare the build time without and with the Icecream cluster, we notice a decrease of 20% or an increase of 26%. For our specific benchmark, it’s approximately 88.14 min minus 69.75 min = 18.39 min, which means an improvement of 18 min. The 20% doesn’t look very exciting. Maybe you prefer to say: “It took 18 minutes less time to build”.

Do you build on your own workstation? You mean you don’t have a build server farm? An Icecream cluster might be the solution for you and your colleagues.

Appendix

If you want to learn how Embedded Linux works have a look here. To learn more about the Yocto Project® have a look here.

Upcoming Events

Our 3 points

of differentiation

We provide host and target hardware during all our teaching.

Three or more people from the same company? We provide private customized training – consulting included.

Subject matter experts develop high-quality, job-related, up-to-date, authentic courseware.