From: Heiko Schocher <hs@denx.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 6/6] moveconfig: Support looking for implied CONFIG options
Date: Tue, 16 May 2017 05:40:37 +0200 [thread overview]
Message-ID: <591A74B5.7060500@denx.de> (raw)
In-Reply-To: <20170515114736.17521-7-sjg@chromium.org>
Hello Simon,
Am 15.05.2017 um 13:47 schrieb Simon Glass:
> 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>
> ---
>
> tools/moveconfig.py | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 214 insertions(+), 1 deletion(-)
Thanks!
Reviewed-by: Heiko Schocher <hs@denx.de>
bye,
Heiko
>
> diff --git a/tools/moveconfig.py b/tools/moveconfig.py
> index ed576f4b83..f33203d51b 100755
> --- a/tools/moveconfig.py
> +++ b/tools/moveconfig.py
> @@ -128,6 +128,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
> -----------------
>
> @@ -191,6 +254,7 @@ To see the complete list of supported options, run
>
> """
>
> +import collections
> import copy
> import difflib
> import filecmp
> @@ -1395,6 +1459,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()
> @@ -1413,6 +1619,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',
> @@ -1437,7 +1645,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)
>
> @@ -1447,6 +1656,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)
>
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
prev parent reply other threads:[~2017-05-16 3:40 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-15 11:47 [U-Boot] [PATCH 0/6] moveconfig: A few more features Simon Glass
2017-05-15 11:47 ` [U-Boot] [PATCH 1/6] moveconfig: Support providing a path to the defconfig files Simon Glass
2017-05-19 17:20 ` Masahiro Yamada
2017-05-15 11:47 ` [U-Boot] [PATCH 2/6] moveconfig: Allow reading the defconfig list from stdin Simon Glass
2017-05-15 12:24 ` Tom Rini
2017-05-17 1:38 ` Simon Glass
2017-05-15 11:47 ` [U-Boot] [PATCH 3/6] moveconfig: Tidy up the documentation and add hints Simon Glass
2017-05-15 12:26 ` Tom Rini
2017-05-19 17:16 ` Masahiro Yamada
2017-05-15 11:47 ` [U-Boot] [PATCH 4/6] moveconfig: Add a constant for auto.conf Simon Glass
2017-05-15 11:47 ` [U-Boot] [PATCH 5/6] moveconfig: Support building a simple config database Simon Glass
[not found] ` <CAFOYHZBzSXdEJ5vG87jzBSEeuhsxzXHb8LvdfFfHT=9QizFs_A@mail.gmail.com>
[not found] ` <CAFOYHZAVn15QqECuWmXsrCKKbq3+mkdFU3970AdoL0hYbK1fKA@mail.gmail.com>
2017-05-16 6:58 ` Chris Packham
2017-08-13 22:03 ` Simon Glass
2017-05-15 11:47 ` [U-Boot] [PATCH 6/6] moveconfig: Support looking for implied CONFIG options Simon Glass
2017-05-15 12:27 ` Tom Rini
2017-05-17 1:38 ` Simon Glass
2017-05-16 3:40 ` Heiko Schocher [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=591A74B5.7060500@denx.de \
--to=hs@denx.de \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.