mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00: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:
parent
d73fcb12e2
commit
99b66605f0
1 changed files with 214 additions and 1 deletions
|
@ -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 -
|
||||
|
||||
|
||||
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
|
||||
-----------------
|
||||
|
||||
|
@ -195,6 +258,7 @@ To see the complete list of supported options, run
|
|||
|
||||
"""
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import difflib
|
||||
import filecmp
|
||||
|
@ -1398,6 +1462,148 @@ def move_config(configs, options, db_queue):
|
|||
slots.show_failed_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():
|
||||
try:
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
|
@ -1416,6 +1622,8 @@ def main():
|
|||
help='a file containing a list of defconfigs to move, '
|
||||
"one per line (for example 'snow_defconfig') "
|
||||
"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,
|
||||
help='perform a trial run (show log with no changes)')
|
||||
parser.add_option('-e', '--exit-on-error', action='store_true',
|
||||
|
@ -1440,7 +1648,8 @@ def main():
|
|||
|
||||
(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()
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -1450,6 +1659,10 @@ def main():
|
|||
|
||||
check_top_directory()
|
||||
|
||||
if options.imply:
|
||||
imply_config(configs)
|
||||
return
|
||||
|
||||
config_db = {}
|
||||
db_queue = Queue.Queue()
|
||||
t = DatabaseThread(config_db, db_queue)
|
||||
|
|
Loading…
Reference in a new issue