Kernel Build Caching/Nondeterminism - linux

I run a CI server which I use to build a custom linux kernel. The CI server is not powerful and has a time limit of 3h per build. To work within this limit, I had the idea to cache kernel builds using ccache. My hope was that I could create a cache once every minor version release and reuse it for the patch releases e.g. I have a cache I made for 4.18 which I want to use for all 4.18.x kernels.
After removing the build timestamps, this works great for the exact kernel version I am building for. For the 4.18 kernel referenced above, building that on the CI gives the following statistics:
$ ccache -s
cache directory
primary config
secondary config (readonly) /etc/ccache.conf
stats zero time Thu Aug 16 14:36:22 2018
cache hit (direct) 17812
cache hit (preprocessed) 38
cache miss 0
cache hit rate 100.00 %
called for link 3
called for preprocessing 29039
unsupported code directive 4
no input file 2207
cleanups performed 0
files in cache 53652
cache size 1.4 GB
max cache size 5.0 GB
Cache hit rate of 100% and an hour to complete the build, fantastic stats and as expected.
Unfortunately, when I try to build 4.18.1, I get
cache directory
primary config
secondary config (readonly) /etc/ccache.conf
stats zero time Thu Aug 16 10:36:22 2018
cache hit (direct) 0
cache hit (preprocessed) 233
cache miss 17658
cache hit rate 1.30 %
called for link 3
called for preprocessing 29039
unsupported code directive 4
no input file 2207
cleanups performed 0
files in cache 90418
cache size 2.4 GB
max cache size 5.0 GB
That's a 1.30% hit rate and the build time reflects this poor performance. That from only a single patch version change.
I would have expected the caching performance to degrade over time but not to this extent, so my only thought is that there is more non-determinism than simply the timestamp. For example, are most/all of the source files including the full kernel version string? My understanding is that something like that would break the caching completely. Is there a way to make the caching work as I'd like it to or is it impossible?

There is include/generated/uapi/linux/version.h header (generated in the top Makefile https://elixir.bootlin.com/linux/v4.16.18/source/Makefile)
which includes exact kernel version as macro:
version_h := include/generated/uapi/linux/version.h
old_version_h := include/linux/version.h
define filechk_version.h
(echo \#define LINUX_VERSION_CODE $(shell \
expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef
$(version_h): $(srctree)/Makefile FORCE
$(call filechk,version.h)
$(Q)rm -f $(old_version_h)
So, version.h for linux 4.16.18 will be generated like (266258 is (4 << 16) + (16 << 8) + 18 = 0x41012)
#define LINUX_VERSION_CODE 266258
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
Later, for example in module building there should be way to read LINUX_VERSION_CODE macro value https://www.tldp.org/LDP/lkmpg/2.4/html/lkmpg.html (4.1.6. Writing Modules for Multiple Kernel Versions)
The way to do this to compare the macro LINUX_VERSION_CODE to the macro KERNEL_VERSION. In version a.b.c of the kernel, the value of this macro would be 2^{16}a+2^{8}b+c. Be aware that this macro is not defined for kernel 2.0.35 and earlier, so if you want to write modules that support really old kernels
How version.h is included? The sample module includes <linux/kernel.h> <linux/module.h> and <linux/modversions.h>, and one of these files probably indirectly includes global version.h. And most or even all kernel sources will include version.h.
When your build timestamps were compared, version.h may be regenerated and disables ccache. When timestamps are ignored, LINUX_VERSION_CODE is same only for exactly same linux kernel version, and it is changed for next patchlevel.
Update: Check gcc -H output of some kernel object compilation, there will be another header with full kernel version macro definition. For example: include/generated/utsrelease.h (UTS_RELEASE macro), include/generated/autoconf.h (CONFIG_VERSION_SIGNATURE).
Or even do gcc -E preprocessing of same kernel object compilation between two patchlevels and compare the generated text. With simplest linux module I have -include ./include/linux/kconfig.h directly in gcc command line, and its includes include/generated/autoconf.h (but this is not visible in -H output, is it bug or feature of gcc?).
https://patchwork.kernel.org/patch/9326051/
... because the top Makefile forces to include it with:
-include $(srctree)/include/linux/kconfig.h
It actually does: https://elixir.bootlin.com/linux/v4.16.18/source/Makefile
# Use USERINCLUDE when you must reference the UAPI directories only.
USERINCLUDE := \
-I$(srctree)/arch/$(SRCARCH)/include/uapi \
-I$(objtree)/arch/$(SRCARCH)/include/generated/uapi \
-I$(srctree)/include/uapi \
-I$(objtree)/include/generated/uapi \
-include $(srctree)/include/linux/kconfig.h
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
LINUXINCLUDE := \
-I$(srctree)/arch/$(SRCARCH)/include \
-I$(objtree)/arch/$(SRCARCH)/include/generated \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
-I$(objtree)/include \
$(USERINCLUDE)
LINUXINCLUDE is exported to env and used in source/scripts/Makefile.lib to define compiler flags https://elixir.bootlin.com/linux/v4.16.18/source/scripts/Makefile.lib
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)

Related

Amend boot cmdline in custom image build

I'm building a custom image that uses the meta-intel layer (I'm targeting Intel boards, such as the Minnowboard Turbot, for instance), and I want to tweak the options for booting.
First problem
As far as I understand, meta-intel uses systemd-boot (via rmc-boot) as EFI_PROVIDER.
So I should be able to override the specific BOOT_TIMEOUT parameter by setting :
SYSTEMD_BOOT_TIMEOUT := "0"
in my custom image, as far as I can see in this file
Unfortunately, that doesn't work (the boot timeout is still 4 seconds). How come ?
Second problem
As well, I would like to append options to the boot.conf file (in /boot/loader/entries, loaded by /boot/loader/loader.conf), such as quiet, or vt.global_cursor_default=0 for instance.
I see in the Intel machine conf that there is an APPEND configuration, but overriding it or appending to it in my custom image doesn't work (it's still not written in the boot.conf file) :
APPEND += "quiet vt.global_cursor_default=0"
I've checked that the configuration is correctly read and it's the case :
$ bitbake my-custom-image -e | grep ^APPEND= -A1 -B1
# " quiet rootwait console=ttyS0,115200 console=tty0${#bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs", " ro", "", d)}"
APPEND=" quiet vt.global_cursor_default=0 rootwait console=ttyS0,115200 console=tty0"
#
But no matter what I do, the command line doesn't change on the built image.
What do I miss ? There should be a relatively easy way to achieve what I'm after I guess, but so far I have not managed to do it.
Thanks a lot !
I have been looking at the kernel command line parameters for intel platform in Yocto with the meta-intel.
I have noticed differences between the wic and hddimg yocto images.
The hddimg seems to use the rmc boot entry definition whereas the wic image uses the boot entry defined in the wks kickstart.
My machine conf has the following :
WKS_FILE ?= "${#bb.utils.contains_any("EFI_PROVIDER", "systemd-boot rmc-boot", "systemd-bootdisk.wks", "mkefidisk.wks", d)}"
In turns systemd-bootdisk.wks has the following boot entry "boot" :
bootloader --ptable gpt --timeout=5 --append="rootwait rootfstype=ext4 console=ttyS0,115200 console=tty0"
The RMC definition for my Minnowboard Max has 2 entry a boot and an install.
Minnow Max B3 boot
Minnow Max B3 install
I am using the pyro release for Yocto. Perhaps integration of RMC boot definition has been integrated into the wic images.
I am looking for a common place to add the kernel command line parameter. Any idea ?

How to put an extra file in the kernel image by yocto

I have a trouble of putting my initramfs.cpio in my kernel image by yocto.
I have two bb files, one is used to build an initramfs, and the other one is used to build a fitimage.
I successful to build the fitimage bundled with my initramfs image.
But it always failed to build a fitImage that has an initramfs.cpio.gz in the /usr directory in the fitImage.
( I mean, I want to see a file named initramfs.cpio in the /usr when I use my fitImage booting to console )
====================================================================
Here are my error message..
ERROR: linux-mine-1_4.9.27+gitAUTOINC+d87116e608-r0 do_package: QA Issue: linux-mine: Files/directories were installed but not shipped in any package:
/usr
/usr/initramfs-mine-qemu.cpio
Please set FILES such that these items are packaged. Alternatively if they are unneeded, avoid installing them or delete them within do_install.
linux-mine: 2 installed and not shipped files. [installed-vs-shipped]
ERROR: linux-mine-1_4.9.27+gitAUTOINC+d87116e608-r0 do_package: Fatal QA errors found, failing task.
ERROR: linux-mine-1_4.9.27+gitAUTOINC+d87116e608-r0 do_package: Function failed: do_package
ERROR: Logfile of failure stored in: /home/paul/projects/Test/yocto/build/tmp/work/mine-poky-linux-gnueabi/linux-mine/1_4.9.27+gitAUTOINC+d87116e608-r0/temp/log.do_package.26149
ERROR: Task (/home/paul/projects/Test/yocto/yocto-2.2/poky/../meta-mine/recipes-kernel/linux/linux-mine_4.9.bb:do_package) failed with exit code '1'
====================================================================
Here is my kernel image bb file
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}-${PV}:"
LINUX_VERSION ?= "4.9.27"
SRCREV = "d87116e608e94ad684b5e94d46c892e33b9e2d78"
SRC_URI = "git://local/kernel;protocol=ssh;branch=master"
#FILES_${PN} += "/usr /usr/initramfs-mine-${MACHINE_ARCH}.cpio"
#FILES_${PN}-${PV} += "/usr /usr/initramfs-mine-${MACHINE_ARCH}.cpio"
#IMAGE_INSTALL = "initramfs-mine"
do_install_append () {
echo "WangPaul : S=[${S}]"
echo "WangPaul : B=[${B}]"
echo "WangPaul : D=[${D}]"
install -d ${D}/usr/
install -m 0444 ${B}/usr/initramfs-mine-${MACHINE_ARCH}.cpio ${D}/usr/
}
====================================================================
Here is my initramfs bb file
LICENSE = "GPLv2"
PACKAGE_INSTALL = "initramfs-live-boot ${VIRTUAL-RUNTIME_base-utils} udev ${ROOTFS_BOOTSTRAP_INSTALL}"
IMAGE_FSTYPES = "${INITRAMFS_FSTYPES}"
inherit core-image
====================================================================
I have found similar questions:
Ship extra files in kernel module recipe and
An example of using FILES_${PN}
The way in aboves discussion are not work...
Any information would be appreciate !!
Thanks !!
The error seems to QA issues it means the source is compiled but not adding to rootfs. Add below line to yourkernel-image.bb. it will solve the issue.
FILES_${PN} += "${exec_prefix}/*"
Note: may be In your kernel.bb file you have given wrong format

docker, openmpi and unexpected end of /proc/mounts line

I have build environment to run code in a Docker container. One of the components is OpenMPI, which I think is the source of problem or manifest it.
When I run code using MPI I getting message,
Unexpected end of /proc/mounts line `overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/NHW6L2TB73FPMK4A52XDP6SO2V:/var/lib/docker/overlay2/l/MKAGUDHZZTJF4KNSUM73QGVRUD:/var/lib/docker/overlay2/l/4PFRG6M47TX5TYVHKQQO2KCG7Q:/var/lib/docker/overlay2/l/4UR3OEP3IW5ZTADZ6OKT77ZBEU:/var/lib/docker/overlay2/l/LGBMK7HFUCHRTM2MMITMD6ILMG:/var/lib/docker/overlay2/l/ODJ2DJIGYGWRXEJZ6ECSLG7VDJ:/var/lib/docker/overlay2/l/JYQIR5JVEUVQPHEF452BRDVC23:/var/lib/docker/overlay2/l/AUDTRIBKXDZX62ANXO75LD3DW5:/var/lib/docker/overlay2/l/RFFN2MQPDHS2Z'
Unexpected end of /proc/mounts line `KNEJCAQH6YG5S:/var/lib/docker/overlay2/l/7LZSAIYKPQ56QB6GEIB2KZTDQA:/var/lib/docker/overlay2/l/CP2WSFS5347GXQZMXFTPWU4F3J:/var/lib/docker/overlay2/l/SJHIWRVQO5IENQFYDG6R5VF7EB:/var/lib/docker/overlay2/l/ICNNZZ4KB64VEFSKEQZUF7XI63:/var/lib/docker/overlay2/l/SOHRMEBEIIP4MRKRRUWMFTXMU2:/var/lib/docker/overlay2/l/DL4GM7DYQUV4RQE4Z6H5XWU2AB:/var/lib/docker/overlay2/l/JNEAR5ISUKIBKQKKZ6GEH6T6NP:/var/lib/docker/overlay2/l/LIAK7F7Q4SSOJBKBFY4R66J2C3:/var/lib/docker/overlay2/l/MYL6XNGBKKZO5CR3PG3HIB475X:/var/lib/do'
That message is printed for code line
MPI_Init(&argc,&argv);
To make the problem more complex to understand, a warning message is printed only when the host machine is mac os x, for linux host all is ok.
Except for warning message all works fine. I do not know how OpenMPI and docker well enough how this can be fixed.
This is likely due to your /proc/mount file having a line in it greater than 512 characters, causing the hwloc module of OpenMPI to fail to parse it correctly. Docker has a tendency to put very long lines into /proc/mounts. You can see the bug in openmpi-1.10.7/opal/mca/hwloc/hwloc191/hwloc/src/topology-linux.c:1677:
static void
hwloc_find_linux_cpuset_mntpnt(char **cgroup_mntpnt, char **cpuset_mntpnt, int fsroot_fd)
{
#define PROC_MOUNT_LINE_LEN 512
char line[PROC_MOUNT_LINE_LEN];
FILE *fd;
*cgroup_mntpnt = NULL;
*cpuset_mntpnt = NULL;
/* ideally we should use setmntent, getmntent, hasmntopt and endmntent,
* but they do not support fsroot_fd.
*/
fd = hwloc_fopen("/proc/mounts", "r", fsroot_fd);
if (!fd)
return;
This can be fixed by increasing the value of PROC_MOUNT_LINE_LEN, although that should be considered a temporary workaround.
This issue should be fixed in hwloc since 1.11.3 (released 2 years ago). You can either upgrade to OpenMPI 3.0 which contains a hwloc 1.11.7 >= 1.11.3. Or recompile OpenMPI to use an external hwloc instead of the old embedded one.

Reserving physical memory space as early as possible in Linux boot-time

I am trying to find a way to reserve physical memory for a proprietary memory type hardware as early as possible after system boots up (Linux CentOs with Intel Xeon server platform).
I did the following at setup_arch() in arch/x86/kernel/setup.c and it works, but found out that I am not allowed to patch the kernel. The requirement is no BIOS and kernel mod.
setup_arch()
{
....
// Calls a proprietary function that returns custom proprietary memory module's starting address and size.
memblock_reserve(mem_start_addr, mem_size);
.....
}
I cannot use memmap=xx/xx either at Grub, because the start and size of the device is unknown (it has to be "discovered" by software)
Is there any way to do this?
One idea is to write a custom grub module and set memmap=xx using it.
The following is how to do it.
Note that following method only works above CentOS 7 since CentOS 6.x or below uses grub 0.9x .
In that case, you may have to modify code of grub 0.9x and replace /boot/grub/stage1 or /boot/grub/stage2
$ git clone git://git.savannah.gnu.org/grub.git
$ cd grub
$ git checkout grub-2.02-beta2 # CentOS 7 currently uses grub-2.02-beta
$ vim grub-core/Makefile.core.def # add following row
module = {
name = my_custom_module;
common = lib/my_custom_module.c;
};
$ vim grub-core/lib/my_custom_module.c # create following file
#include <grub/dl.h>
#include <grub/env.h>
GRUB_MOD_LICENSE ("GPLv3+");
GRUB_MOD_INIT(my_custom_module){
// Calls a proprietary function that returns custom proprietary memory module's starting address and size.
const char *mem_size = "123";
grub_env_set("my_memsize",mem_size);
}
GRUB_MOD_FINI(my_custom_module){
}
$ ./autogen.sh
$ ./configure
$ make
Now you can find that grub-core/my_custom_module.mod is created.
so copy it to /boot/grub2/i386-pc/ (or whatever your *.mod file exists)
Edit the grub.conf and add something like
insmod my_custom_module
linux /boot/vmlinuz-3.10.el7.x86_64 root=UUID=1a3b5c7d9 ro memmap=${my_memsize}

make oldconfig overwriting value in .config

I'm attempting to compile the linux kernel and use a custom .config file.
So I copy the .config to my folder where the kernel source is, and run "make oldconfig" on the file to see if I'm missing anything. However, it appears that doing so modifies a few of my values back to what they were before I edited them:
< CONFIG_TRACEPOINTS=y
---
> CONFIG_TRACEPOINTS=n
< # CONFIG_DEBUG_RODATA is not set
< # CONFIG_DEBUG_SET_MODULE_RONX is not set
---
> CONFIG_DEBUG_RODATA=n
> CONFIG_DEBUG_SET_MODULE_RONX=n
How can I get oldconfig to keep the values as they were modified?
Thanks
Usually kernel config options are dependent on other config options. So even if you disable one config option, as its enabled by some other config option it will fall back to its original value after you do make oldconfig
In case of CONFIG_TRACEPOINTS it depends on or set by several other flags TRACING [=y] || BLK_DEV_IO_TRACE [=y] && TRACING_SUPPORT [=y] && FTRACE [=y] && SYSFS [=y] && BLOCK [=y]
Try setting one by one of them to =n along with CONFIG_TRACEPOINTS=n and see if its persistent after doing make oldconfig. For me setting CONFIG_FTRACE=n worked
How to find dependency. Run make menuconfig. Press / to search the config option and see the Selected by. Those are the config flags who are also setting your config option. See their current value next to them. For e.g. above you can see that TRACING_SUPPORT is set to y

Resources