mirror of
https://xff.cz/git/u-boot/
synced 2025-09-01 08:42:12 +02:00
moveconfig: Support looking for implied CONFIG options
Some CONFIG options can be implied by others and this can help to reduce the size of the defconfig files. For example, CONFIG_X86 implies CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to each of the x86 defconfig files. Add a -i option which searches for such options. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Heiko Schocher <hs@denx.de>
This commit is contained in:
@@ -132,6 +132,69 @@ To process CONFIG_CMD_FPGAD only for a subset of configs based on path match:
|
|||||||
./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d -
|
./tools/moveconfig.py -Cy CONFIG_CMD_FPGAD -d -
|
||||||
|
|
||||||
|
|
||||||
|
Finding implied CONFIGs
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Some CONFIG options can be implied by others and this can help to reduce
|
||||||
|
the size of the defconfig files. For example, CONFIG_X86 implies
|
||||||
|
CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
|
||||||
|
all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
|
||||||
|
each of the x86 defconfig files.
|
||||||
|
|
||||||
|
This tool can help find such configs. To use it, first build a database:
|
||||||
|
|
||||||
|
./tools/moveconfig.py -b
|
||||||
|
|
||||||
|
Then try to query it:
|
||||||
|
|
||||||
|
./tools/moveconfig.py -i CONFIG_CMD_IRQ
|
||||||
|
CONFIG_CMD_IRQ found in 311/2384 defconfigs
|
||||||
|
44 : CONFIG_SYS_FSL_ERRATUM_IFC_A002769
|
||||||
|
41 : CONFIG_SYS_FSL_ERRATUM_A007075
|
||||||
|
31 : CONFIG_SYS_FSL_DDR_VER_44
|
||||||
|
28 : CONFIG_ARCH_P1010
|
||||||
|
28 : CONFIG_SYS_FSL_ERRATUM_P1010_A003549
|
||||||
|
28 : CONFIG_SYS_FSL_ERRATUM_SEC_A003571
|
||||||
|
28 : CONFIG_SYS_FSL_ERRATUM_IFC_A003399
|
||||||
|
25 : CONFIG_SYS_FSL_ERRATUM_A008044
|
||||||
|
22 : CONFIG_ARCH_P1020
|
||||||
|
21 : CONFIG_SYS_FSL_DDR_VER_46
|
||||||
|
20 : CONFIG_MAX_PIRQ_LINKS
|
||||||
|
20 : CONFIG_HPET_ADDRESS
|
||||||
|
20 : CONFIG_X86
|
||||||
|
20 : CONFIG_PCIE_ECAM_SIZE
|
||||||
|
20 : CONFIG_IRQ_SLOT_COUNT
|
||||||
|
20 : CONFIG_I8259_PIC
|
||||||
|
20 : CONFIG_CPU_ADDR_BITS
|
||||||
|
20 : CONFIG_RAMBASE
|
||||||
|
20 : CONFIG_SYS_FSL_ERRATUM_A005871
|
||||||
|
20 : CONFIG_PCIE_ECAM_BASE
|
||||||
|
20 : CONFIG_X86_TSC_TIMER
|
||||||
|
20 : CONFIG_I8254_TIMER
|
||||||
|
20 : CONFIG_CMD_GETTIME
|
||||||
|
19 : CONFIG_SYS_FSL_ERRATUM_A005812
|
||||||
|
18 : CONFIG_X86_RUN_32BIT
|
||||||
|
17 : CONFIG_CMD_CHIP_CONFIG
|
||||||
|
...
|
||||||
|
|
||||||
|
This shows a list of config options which might imply CONFIG_CMD_EEPROM along
|
||||||
|
with how many defconfigs they cover. From this you can see that CONFIG_X86
|
||||||
|
implies CONFIG_CMD_EEPROM. Therefore, instead of adding CONFIG_CMD_EEPROM to
|
||||||
|
the defconfig of every x86 board, you could add a single imply line to the
|
||||||
|
Kconfig file:
|
||||||
|
|
||||||
|
config X86
|
||||||
|
bool "x86 architecture"
|
||||||
|
...
|
||||||
|
imply CMD_EEPROM
|
||||||
|
|
||||||
|
That will cover 20 defconfigs. Many of the options listed are not suitable as
|
||||||
|
they are not related. E.g. it would be odd for CONFIG_CMD_GETTIME to imply
|
||||||
|
CMD_EEPROM.
|
||||||
|
|
||||||
|
Using this search you can reduce the size of moveconfig patches.
|
||||||
|
|
||||||
|
|
||||||
Available options
|
Available options
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@@ -195,6 +258,7 @@ To see the complete list of supported options, run
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import collections
|
||||||
import copy
|
import copy
|
||||||
import difflib
|
import difflib
|
||||||
import filecmp
|
import filecmp
|
||||||
@@ -1398,6 +1462,148 @@ def move_config(configs, options, db_queue):
|
|||||||
slots.show_failed_boards()
|
slots.show_failed_boards()
|
||||||
slots.show_suspicious_boards()
|
slots.show_suspicious_boards()
|
||||||
|
|
||||||
|
def imply_config(config_list, find_superset=False):
|
||||||
|
"""Find CONFIG options which imply those in the list
|
||||||
|
|
||||||
|
Some CONFIG options can be implied by others and this can help to reduce
|
||||||
|
the size of the defconfig files. For example, CONFIG_X86 implies
|
||||||
|
CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
|
||||||
|
all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
|
||||||
|
each of the x86 defconfig files.
|
||||||
|
|
||||||
|
This function uses the moveconfig database to find such options. It
|
||||||
|
displays a list of things that could possibly imply those in the list.
|
||||||
|
The algorithm ignores any that start with CONFIG_TARGET since these
|
||||||
|
typically refer to only a few defconfigs (often one). It also does not
|
||||||
|
display a config with less than 5 defconfigs.
|
||||||
|
|
||||||
|
The algorithm works using sets. For each target config in config_list:
|
||||||
|
- Get the set 'defconfigs' which use that target config
|
||||||
|
- For each config (from a list of all configs):
|
||||||
|
- Get the set 'imply_defconfig' of defconfigs which use that config
|
||||||
|
-
|
||||||
|
- If imply_defconfigs contains anything not in defconfigs then
|
||||||
|
this config does not imply the target config
|
||||||
|
|
||||||
|
Params:
|
||||||
|
config_list: List of CONFIG options to check (each a string)
|
||||||
|
find_superset: True to look for configs which are a superset of those
|
||||||
|
already found. So for example if CONFIG_EXYNOS5 implies an option,
|
||||||
|
but CONFIG_EXYNOS covers a larger set of defconfigs and also
|
||||||
|
implies that option, this will drop the former in favour of the
|
||||||
|
latter. In practice this option has not proved very used.
|
||||||
|
|
||||||
|
Note the terminoloy:
|
||||||
|
config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM')
|
||||||
|
defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig')
|
||||||
|
"""
|
||||||
|
# key is defconfig name, value is dict of (CONFIG_xxx, value)
|
||||||
|
config_db = {}
|
||||||
|
|
||||||
|
# Holds a dict containing the set of defconfigs that contain each config
|
||||||
|
# key is config, value is set of defconfigs using that config
|
||||||
|
defconfig_db = collections.defaultdict(set)
|
||||||
|
|
||||||
|
# Set of all config options we have seen
|
||||||
|
all_configs = set()
|
||||||
|
|
||||||
|
# Set of all defconfigs we have seen
|
||||||
|
all_defconfigs = set()
|
||||||
|
|
||||||
|
# Read in the database
|
||||||
|
configs = {}
|
||||||
|
with open(CONFIG_DATABASE) as fd:
|
||||||
|
for line in fd.readlines():
|
||||||
|
line = line.rstrip()
|
||||||
|
if not line: # Separator between defconfigs
|
||||||
|
config_db[defconfig] = configs
|
||||||
|
all_defconfigs.add(defconfig)
|
||||||
|
configs = {}
|
||||||
|
elif line[0] == ' ': # CONFIG line
|
||||||
|
config, value = line.strip().split('=', 1)
|
||||||
|
configs[config] = value
|
||||||
|
defconfig_db[config].add(defconfig)
|
||||||
|
all_configs.add(config)
|
||||||
|
else: # New defconfig
|
||||||
|
defconfig = line
|
||||||
|
|
||||||
|
# Work through each target config option in tern, independently
|
||||||
|
for config in config_list:
|
||||||
|
defconfigs = defconfig_db.get(config)
|
||||||
|
if not defconfigs:
|
||||||
|
print '%s not found in any defconfig' % config
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get the set of defconfigs without this one (since a config cannot
|
||||||
|
# imply itself)
|
||||||
|
non_defconfigs = all_defconfigs - defconfigs
|
||||||
|
num_defconfigs = len(defconfigs)
|
||||||
|
print '%s found in %d/%d defconfigs' % (config, num_defconfigs,
|
||||||
|
len(all_configs))
|
||||||
|
|
||||||
|
# This will hold the results: key=config, value=defconfigs containing it
|
||||||
|
imply_configs = {}
|
||||||
|
rest_configs = all_configs - set([config])
|
||||||
|
|
||||||
|
# Look at every possible config, except the target one
|
||||||
|
for imply_config in rest_configs:
|
||||||
|
if 'CONFIG_TARGET' in imply_config:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Find set of defconfigs that have this config
|
||||||
|
imply_defconfig = defconfig_db[imply_config]
|
||||||
|
|
||||||
|
# Get the intersection of this with defconfigs containing the
|
||||||
|
# target config
|
||||||
|
common_defconfigs = imply_defconfig & defconfigs
|
||||||
|
|
||||||
|
# Get the set of defconfigs containing this config which DO NOT
|
||||||
|
# also contain the taret config. If this set is non-empty it means
|
||||||
|
# that this config affects other defconfigs as well as (possibly)
|
||||||
|
# the ones affected by the target config. This means it implies
|
||||||
|
# things we don't want to imply.
|
||||||
|
not_common_defconfigs = imply_defconfig & non_defconfigs
|
||||||
|
if not_common_defconfigs:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# If there are common defconfigs, imply_config may be useful
|
||||||
|
if common_defconfigs:
|
||||||
|
skip = False
|
||||||
|
if find_superset:
|
||||||
|
for prev in imply_configs.keys():
|
||||||
|
prev_count = len(imply_configs[prev])
|
||||||
|
count = len(common_defconfigs)
|
||||||
|
if (prev_count > count and
|
||||||
|
(imply_configs[prev] & common_defconfigs ==
|
||||||
|
common_defconfigs)):
|
||||||
|
# skip imply_config because prev is a superset
|
||||||
|
skip = True
|
||||||
|
break
|
||||||
|
elif count > prev_count:
|
||||||
|
# delete prev because imply_config is a superset
|
||||||
|
del imply_configs[prev]
|
||||||
|
if not skip:
|
||||||
|
imply_configs[imply_config] = common_defconfigs
|
||||||
|
|
||||||
|
# Now we have a dict imply_configs of configs which imply each config
|
||||||
|
# The value of each dict item is the set of defconfigs containing that
|
||||||
|
# config. Rank them so that we print the configs that imply the largest
|
||||||
|
# number of defconfigs first.
|
||||||
|
ranked_configs = sorted(imply_configs,
|
||||||
|
key=lambda k: len(imply_configs[k]), reverse=True)
|
||||||
|
for config in ranked_configs:
|
||||||
|
num_common = len(imply_configs[config])
|
||||||
|
|
||||||
|
# Don't bother if there are less than 5 defconfigs affected.
|
||||||
|
if num_common < 5:
|
||||||
|
continue
|
||||||
|
missing = defconfigs - imply_configs[config]
|
||||||
|
missing_str = ', '.join(missing) if missing else 'all'
|
||||||
|
missing_str = ''
|
||||||
|
print ' %d : %-30s%s' % (num_common, config.ljust(30),
|
||||||
|
missing_str)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
cpu_count = multiprocessing.cpu_count()
|
cpu_count = multiprocessing.cpu_count()
|
||||||
@@ -1416,6 +1622,8 @@ def main():
|
|||||||
help='a file containing a list of defconfigs to move, '
|
help='a file containing a list of defconfigs to move, '
|
||||||
"one per line (for example 'snow_defconfig') "
|
"one per line (for example 'snow_defconfig') "
|
||||||
"or '-' to read from stdin")
|
"or '-' to read from stdin")
|
||||||
|
parser.add_option('-i', '--imply', action='store_true', default=False,
|
||||||
|
help='find options which imply others')
|
||||||
parser.add_option('-n', '--dry-run', action='store_true', default=False,
|
parser.add_option('-n', '--dry-run', action='store_true', default=False,
|
||||||
help='perform a trial run (show log with no changes)')
|
help='perform a trial run (show log with no changes)')
|
||||||
parser.add_option('-e', '--exit-on-error', action='store_true',
|
parser.add_option('-e', '--exit-on-error', action='store_true',
|
||||||
@@ -1440,7 +1648,8 @@ def main():
|
|||||||
|
|
||||||
(options, configs) = parser.parse_args()
|
(options, configs) = parser.parse_args()
|
||||||
|
|
||||||
if len(configs) == 0 and not any((options.force_sync, options.build_db)):
|
if len(configs) == 0 and not any((options.force_sync, options.build_db,
|
||||||
|
options.imply)):
|
||||||
parser.print_usage()
|
parser.print_usage()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@@ -1450,6 +1659,10 @@ def main():
|
|||||||
|
|
||||||
check_top_directory()
|
check_top_directory()
|
||||||
|
|
||||||
|
if options.imply:
|
||||||
|
imply_config(configs)
|
||||||
|
return
|
||||||
|
|
||||||
config_db = {}
|
config_db = {}
|
||||||
db_queue = Queue.Queue()
|
db_queue = Queue.Queue()
|
||||||
t = DatabaseThread(config_db, db_queue)
|
t = DatabaseThread(config_db, db_queue)
|
||||||
|
Reference in New Issue
Block a user