summaryrefslogtreecommitdiff
path: root/bin/model-config.py
blob: 2b85a2060031edc52c8f87612cd74386cae6772d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/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"<DTreeLeaf({self.value}, {self.stddev})>"

    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"<DTreeNode({self.false_child}, {self.true_child})>"

    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}")