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