From de2068519d2a021ae7fbbf912fb21d1ab9964bcd Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Fri, 10 Apr 2026 13:36:49 +0200 Subject: [PATCH] perf(dracut-functions): optimize _inst_rule_programs() Let's start analyzing the output of a non-hostonly build, counting how many times `_inst_rule_programs()` calls an `inst*()` function and with what arguments: ``` $ dracut -f -N --debug testn.img 2>&1 &> testn.txt $ grep -r -c "(_inst_rule_programs): inst_" testn.txt 59 $ grep -r "(_inst_rule_programs): inst_" testn.txt /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/systemctl /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/udevadm /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/dmsetup /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/dmsetup /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/dmsetup /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/sbin/dmsetup /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/sbin/kpartx /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /bin/sh /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /bin/sh /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /bin/sh /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/dmsetup /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/bin/readlink /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/bin/basename /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/bin/basename /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/bin/basename /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /bin/sh /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /sbin/partx /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/rm /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/systemd-run /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/systemctl /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/sbin/multipath /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/sbin/kpartx /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/bin/logger /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/sbin/multipath /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/bin/logger /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/kpartx_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/kpartx_id /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /bin/sh /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /bin/sh /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /bin/logger /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/lib/udev/cdrom_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/cdrom_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/fido_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/scsi_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/scsi_id /usr/lib/dracut/dracut-functions.sh@1244(_inst_rule_programs): inst_binary /usr/lib/udev/scsi_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/ata_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/ata_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/ata_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/scsi_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/scsi_id /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/v4l_id /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/udevadm /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/dmi_memory_id /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/udevadm /usr/lib/dracut/dracut-functions.sh@1259(_inst_rule_programs): inst_binary /usr/bin/loginctl /usr/lib/dracut/dracut-functions.sh@1274(_inst_rule_programs): inst_multiple /usr/lib/udev/mtd_probe ``` This means that `_inst_rule_programs()` spawns 59 dracut-install processes, without grouping the binaries of the same rule, and sometimes trying to install the same binary. Therefore, this can be optimized: - Instead of calling `inst_binary()` and `inst_multiple()` within the 3 loops for each PROGRAM/RUN/IMPORT element, collect the different binaries to be installed and call `inst_multiple()` once at the end. Note that `inst_binary()` only differs from `inst_multiple()` because it only expects 1 argument. - Cache the binaries already installed from previous rules, to avoid unnecessary calls. After this simple patch, the number of spawned dracut-install processes drops from 59 to 18, i.e., 41 less. ``` $ grep -r -c "(_inst_rule_programs): inst_" testn2.txt 18 $ grep -r "(_inst_rule_programs): inst_" testn2.txt /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/bin/systemctl /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/bin/udevadm /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/sbin/dmsetup /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/sbin/kpartx /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /bin/sh /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/bin/readlink /usr/bin/basename /usr/sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /sbin/partx /sbin/mdadm /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/sbin/multipath /usr/bin/systemd-run /usr/bin/rm /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/kpartx_id /usr/bin/logger /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /bin/logger /usr/bin/sg_inq /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/cdrom_id /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/fido_id /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/scsi_id /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/ata_id /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/v4l_id /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/dmi_memory_id /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/bin/loginctl /usr/lib/dracut/dracut-functions.sh@1291(_inst_rule_programs): inst_multiple /usr/lib/udev/mtd_probe ``` Double-check that we are installing the same binaries: ``` $ grep -r "(_inst_rule_programs): inst_" testn.txt | cut -d ' ' -f 3 | sort -u | wc -l 25 $ grep -r "(_inst_rule_programs): inst_" testn2.txt | awk -F"inst_multiple " '{ print $2 }' | tr ' ' '\n' | sort | wc -l 25 $ diff \ > <(grep -r "(_inst_rule_programs): inst_" testn.txt | cut -d ' ' -f 3 | sort -u) \ > <(grep -r "(_inst_rule_programs): inst_" testn2.txt | awk -F"inst_multiple " '{ print $2 }' | tr ' ' '\n' | sort) $ echo $? 0 ``` --- dracut-functions.sh | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/dracut-functions.sh b/dracut-functions.sh index 8d4785ddae..f73de25069 100755 --- a/dracut-functions.sh +++ b/dracut-functions.sh @@ -1202,6 +1202,12 @@ dracut_need_initqueue() { # attempt to install any programs specified in a udev rule _inst_rule_programs() { local _prog _bin + local -A _rule_bins=() + + # cache installed rule programs + if ! declare -p _rule_programs_cache 2> /dev/null | grep -q "declare -A"; then + declare -gxA _rule_programs_cache=() + fi # shellcheck disable=SC2013 for _prog in $(sed -nr 's/.*PROGRAM==?"([^ "]+).*/\1/p' "$1"); do @@ -1215,7 +1221,10 @@ _inst_rule_programs() { } fi - [[ $_bin ]] && inst_binary "$_bin" + if [[ $_bin ]] && [[ ${_rule_bins[$_bin]:-} != 1 ]] && [[ ${_rule_programs_cache[$_bin]:-} != 1 ]]; then + _rule_bins[$_bin]=1 + _rule_programs_cache[$_bin]=1 + fi done # shellcheck disable=SC2013 @@ -1230,7 +1239,10 @@ _inst_rule_programs() { } fi - [[ $_bin ]] && inst_binary "$_bin" + if [[ $_bin ]] && [[ ${_rule_bins[$_bin]:-} != 1 ]] && [[ ${_rule_programs_cache[$_bin]:-} != 1 ]]; then + _rule_bins[$_bin]=1 + _rule_programs_cache[$_bin]=1 + fi done # shellcheck disable=SC2013 @@ -1245,8 +1257,13 @@ _inst_rule_programs() { } fi - [[ $_bin ]] && inst_multiple "$_bin" + if [[ $_bin ]] && [[ ${_rule_bins[$_bin]:-} != 1 ]] && [[ ${_rule_programs_cache[$_bin]:-} != 1 ]]; then + _rule_bins[$_bin]=1 + _rule_programs_cache[$_bin]=1 + fi done + + ((${#_rule_bins[@]} > 0)) && inst_multiple "${!_rule_bins[@]}" } # attempt to create any groups and users specified in a udev rule