Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

scripts: kconfig: merge_config.sh: refactor from shell/sed/grep to awk

merge_config.sh shell/sed/grep loop scales poorly and is slow.
With Yocto genericarm64 kernel and around 190 config fragments
the script takes more than 20 minutes to run on a fast build machine.
Re-implementation with awk does the same job in 10 seconds.
Using awk since it is likely available in the build environments
and using perl, python etc would introduce more complex runtime
dependencies. awk is good enough and lot better than shell/sed/grep.

Output stays the same but changed execution time means that
parallel job output may be ordered differently.

Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
Signed-off-by: Mikko Rapeli <mikko.rapeli@linaro.org>
Link: https://patch.msgid.link/20260122105751.2186609-1-mikko.rapeli@linaro.org
Signed-off-by: Nathan Chancellor <nathan@kernel.org>

authored by

Anders Roxell and committed by
Nathan Chancellor
5fa9b82c a081b578

+127 -39
+127 -39
scripts/kconfig/merge_config.sh
··· 16 16 set -e 17 17 18 18 clean_up() { 19 - rm -f $TMP_FILE 20 - rm -f $MERGE_FILE 19 + rm -f "$TMP_FILE" 20 + rm -f "$TMP_FILE.new" 21 21 } 22 22 23 23 usage() { ··· 42 42 STRICT=false 43 43 CONFIG_PREFIX=${CONFIG_-CONFIG_} 44 44 WARNOVERRIDE=echo 45 + 46 + if [ -z "$AWK" ]; then 47 + AWK=awk 48 + fi 45 49 46 50 while true; do 47 51 case $1 in ··· 121 117 fi 122 118 123 119 MERGE_LIST=$* 124 - SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p" 125 - SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p" 126 120 127 121 TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) 128 - MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX) 129 122 130 123 echo "Using $INITFILE as base" 131 124 ··· 137 136 echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2 138 137 exit 1 139 138 fi 140 - cat $ORIG_MERGE_FILE > $MERGE_FILE 141 - CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE) 139 + # Use awk for single-pass processing instead of per-symbol grep/sed 140 + if ! "$AWK" -v prefix="$CONFIG_PREFIX" \ 141 + -v warnoverride="$WARNOVERRIDE" \ 142 + -v strict="$STRICT" \ 143 + -v builtin="$BUILTIN" \ 144 + -v warnredun="$WARNREDUN" ' 145 + BEGIN { 146 + strict_violated = 0 147 + cfg_regex = "^" prefix "[a-zA-Z0-9_]+" 148 + notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$" 149 + } 142 150 143 - for CFG in $CFG_LIST ; do 144 - grep -q -w $CFG $TMP_FILE || continue 145 - PREV_VAL=$(grep -w $CFG $TMP_FILE) 146 - NEW_VAL=$(grep -w $CFG $MERGE_FILE) 147 - BUILTIN_FLAG=false 148 - if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then 149 - ${WARNOVERRIDE} Previous value: $PREV_VAL 150 - ${WARNOVERRIDE} New value: $NEW_VAL 151 - ${WARNOVERRIDE} -y passed, will not demote y to m 152 - ${WARNOVERRIDE} 153 - BUILTIN_FLAG=true 154 - elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then 155 - ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE: 156 - ${WARNOVERRIDE} Previous value: $PREV_VAL 157 - ${WARNOVERRIDE} New value: $NEW_VAL 158 - ${WARNOVERRIDE} 159 - if [ "$STRICT" = "true" ]; then 160 - STRICT_MODE_VIOLATED=true 161 - fi 162 - elif [ "$WARNREDUN" = "true" ]; then 163 - ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE: 164 - fi 165 - if [ "$BUILTIN_FLAG" = "false" ]; then 166 - sed -i "/$CFG[ =]/d" $TMP_FILE 167 - else 168 - sed -i "/$CFG[ =]/d" $MERGE_FILE 169 - fi 170 - done 171 - # In case the previous file lacks a new line at the end 172 - echo >> $TMP_FILE 173 - cat $MERGE_FILE >> $TMP_FILE 151 + # Extract config name from a line, returns "" if not a config line 152 + function get_cfg(line) { 153 + if (match(line, cfg_regex)) { 154 + return substr(line, RSTART, RLENGTH) 155 + } else if (match(line, notset_regex)) { 156 + # Extract CONFIG_FOO from "# CONFIG_FOO is not set" 157 + sub(/^# /, "", line) 158 + sub(/ is not set$/, "", line) 159 + return line 160 + } 161 + return "" 162 + } 163 + 164 + function warn_builtin(cfg, prev, new) { 165 + if (warnoverride == "true") return 166 + print cfg ": -y passed, will not demote y to m" 167 + print "Previous value: " prev 168 + print "New value: " new 169 + print "" 170 + } 171 + 172 + function warn_redefined(cfg, prev, new) { 173 + if (warnoverride == "true") return 174 + print "Value of " cfg " is redefined by fragment " mergefile ":" 175 + print "Previous value: " prev 176 + print "New value: " new 177 + print "" 178 + } 179 + 180 + function warn_redundant(cfg) { 181 + if (warnredun != "true" || warnoverride == "true") return 182 + print "Value of " cfg " is redundant by fragment " mergefile ":" 183 + } 184 + 185 + # First pass: read merge file, store all lines and index 186 + FILENAME == ARGV[1] { 187 + mergefile = FILENAME 188 + merge_lines[FNR] = $0 189 + merge_total = FNR 190 + cfg = get_cfg($0) 191 + if (cfg != "") { 192 + merge_cfg[cfg] = $0 193 + merge_cfg_line[cfg] = FNR 194 + } 195 + next 196 + } 197 + 198 + # Second pass: process base file (TMP_FILE) 199 + FILENAME == ARGV[2] { 200 + cfg = get_cfg($0) 201 + 202 + # Not a config or not in merge file - keep it 203 + if (cfg == "" || !(cfg in merge_cfg)) { 204 + print $0 >> ARGV[3] 205 + next 206 + } 207 + 208 + prev_val = $0 209 + new_val = merge_cfg[cfg] 210 + 211 + # BUILTIN: do not demote y to m 212 + if (builtin == "true" && new_val ~ /=m$/ && prev_val ~ /=y$/) { 213 + warn_builtin(cfg, prev_val, new_val) 214 + print $0 >> ARGV[3] 215 + skip_merge[merge_cfg_line[cfg]] = 1 216 + next 217 + } 218 + 219 + # Values equal - redundant 220 + if (prev_val == new_val) { 221 + warn_redundant(cfg) 222 + next 223 + } 224 + 225 + # "=n" is the same as "is not set" 226 + if (prev_val ~ /=n$/ && new_val ~ / is not set$/) { 227 + print $0 >> ARGV[3] 228 + next 229 + } 230 + 231 + # Values differ - redefined 232 + warn_redefined(cfg, prev_val, new_val) 233 + if (strict == "true") { 234 + strict_violated = 1 235 + } 236 + } 237 + 238 + # output file, skip all lines 239 + FILENAME == ARGV[3] { 240 + nextfile 241 + } 242 + 243 + END { 244 + # Newline in case base file lacks trailing newline 245 + print "" >> ARGV[3] 246 + # Append merge file, skipping lines marked for builtin preservation 247 + for (i = 1; i <= merge_total; i++) { 248 + if (!(i in skip_merge)) { 249 + print merge_lines[i] >> ARGV[3] 250 + } 251 + } 252 + if (strict_violated) { 253 + exit 1 254 + } 255 + }' \ 256 + "$ORIG_MERGE_FILE" "$TMP_FILE" "$TMP_FILE.new"; then 257 + # awk exited non-zero, strict mode was violated 258 + STRICT_MODE_VIOLATED=true 259 + fi 260 + mv "$TMP_FILE.new" "$TMP_FILE" 174 261 done 175 - 176 262 if [ "$STRICT_MODE_VIOLATED" = "true" ]; then 177 263 echo "The fragment redefined a value and strict mode had been passed." 178 264 exit 1