summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorDaniel Friesel <daniel.friesel@uos.de>2020-09-11 11:55:46 +0200
committerDaniel Friesel <daniel.friesel@uos.de>2020-09-11 11:55:46 +0200
commit5af6a1a0f32ca7c75c731b0e84cf9b234cdb757d (patch)
treec3eeaf01f4b1af466311c6e796b59079072cdbee /bin
parentb2325314cc3a689a7bbc0e557aa41b47652eb6cb (diff)
add analyze-kconfig script
Diffstat (limited to 'bin')
-rwxr-xr-xbin/analyze-kconfig.py95
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()