#!/usr/bin/env python3 import json import kconfiglib import logging import os import sys import numpy as np numeric_level = getattr(logging, "DEBUG", None) if not isinstance(numeric_level, int): print(f"Invalid log level: {loglevel}", file=sys.stderr) sys.exit(1) logging.basicConfig(level=numeric_level) kconfig_path = "/tmp/multipass/Kconfig" configs_base = "/tmp/multipass-model" kconf = kconfiglib.Kconfig(kconfig_path) symbols = sorted( map( lambda sym: sym.name, filter( lambda sym: kconfiglib.TYPE_TO_STR[sym.type] == "bool", kconf.syms.values() ), ) ) with open("kconfigmodel.json", "r") as f: data = json.load(f) assert symbols == data["symbols"] model = data["model"] kconf.load_config(sys.argv[1]) class DTreeLeaf: def __init__(self, value, stddev): self.value = value self.stddev = stddev def __repr__(self): return f"" def model(self, kconf): # print(f"* leaf") return self.value class DTreeNode: def __init__(self, symbol, false_child=None, true_child=None): self.symbol = symbol self.false_child = false_child self.true_child = true_child def set_false_child(self, child_node): self.false_child = child_node def set_true_child(self, child_node): self.true_child = child_node def __repr__(self): return f"" def model(self, kconf): if kconf.syms[self.symbol].tri_value == 2 and self.true_child: # print(f"* node {self.symbol} == y -> descent") return self.true_child.model(kconf) elif kconf.syms[self.symbol].tri_value == 0 and self.false_child: # print(f"* node {self.symbol} == n -> descent") return self.false_child.model(kconf) return None def load_model(tree): if tree is None: return None if "value" in tree: return DTreeLeaf(tree["value"], tree["stddev"]) return DTreeNode( tree["symbol"], load_model(tree["false"]), load_model(tree["true"]) ) root = load_model(model) current_model = root.model(kconf) print(f"Model result: {current_model}") for symbol in symbols: kconf2 = kconfiglib.Kconfig(kconfig_path) kconf2.load_config(sys.argv[1]) 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(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 = root.model(kconf2) - current_model 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}")