diff options
author | Daniel Friesel <daniel.friesel@uos.de> | 2020-09-11 11:55:46 +0200 |
---|---|---|
committer | Daniel Friesel <daniel.friesel@uos.de> | 2020-09-11 11:55:46 +0200 |
commit | 5af6a1a0f32ca7c75c731b0e84cf9b234cdb757d (patch) | |
tree | c3eeaf01f4b1af466311c6e796b59079072cdbee /bin | |
parent | b2325314cc3a689a7bbc0e557aa41b47652eb6cb (diff) |
add analyze-kconfig script
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/analyze-kconfig.py | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/bin/analyze-kconfig.py b/bin/analyze-kconfig.py new file mode 100755 index 0000000..2f2e973 --- /dev/null +++ b/bin/analyze-kconfig.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 + +"""analyze-kconfig - Generate a model for KConfig selections + +analyze-kconfig builds a model determining system attributes +(e.g. ROM or RAM usage) based on KConfig configuration variables. +Only boolean variables are supported at the moment. +""" + +import argparse +import json +import kconfiglib +import logging + +from dfatool.loader import KConfigAttributes +from dfatool.model import KConfigModel + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__ + ) + parser.add_argument( + "--export-tree", type=str, help="Export decision tree model to file" + ) + parser.add_argument( + "--config", type=str, help="Show model results for symbols in .config file" + ) + parser.add_argument( + "--attribute", choices=["rom", "ram"], default="rom", help="Model attribute" + ) + parser.add_argument("kconfig_path", type=str, help="Path to Kconfig file") + parser.add_argument("experiment_root", type=str, help="Path to experiment results") + + args = parser.parse_args() + + data = KConfigAttributes(args.kconfig_path, args.experiment_root) + model = KConfigModel(data, args.attribute) + + if args.export_tree: + with open(args.export_tree, "w") as f: + json.dump(model.get_tree(), f) + + if args.config: + kconf = kconfiglib.Kconfig(args.kconfig_path) + kconf.load_config(args.config) + print(f"Model result for .config: {model.value_for_config(kconf)}") + + for symbol in model.symbols: + kconf2 = kconfiglib.Kconfig(args.kconfig_path) + kconf2.load_config(args.config) + kconf_sym = kconf2.syms[symbol] + if kconf_sym.tri_value == 0 and 2 in kconf_sym.assignable: + kconf_sym.set_value(2) + elif kconf_sym.tri_value == 2 and 0 in kconf_sym.assignable: + kconf_sym.set_value(0) + else: + continue + + # specific to multipass: + # Do not suggest changes which affect the application + skip = False + num_changes = 0 + changed_symbols = list() + for i, csymbol in enumerate(model.symbols): + if kconf.syms[csymbol].tri_value != kconf2.syms[csymbol].tri_value: + num_changes += 1 + changed_symbols.append(csymbol) + if ( + csymbol.startswith("app_") + and kconf.syms[csymbol].tri_value + != kconf2.syms[csymbol].tri_value + ): + skip = True + break + if skip: + continue + + model_diff = model.value_for_config(kconf2) - model.value_for_config(kconf) + if kconf_sym.choice: + print( + f"Setting {kconf_sym.choice.name} to {kconf_sym.name} changes {num_changes:2d} symbols, model change: {model_diff:+5.0f}" + ) + else: + print( + f"Setting {symbol} to {kconf_sym.str_value} changes {num_changes:2d} symbols, model change: {model_diff:+5.0f}" + ) + for changed_symbol in changed_symbols: + print( + f" {changed_symbol:30s} -> {kconf2.syms[changed_symbol].str_value}" + ) + + +if __name__ == "__main__": + main() |