summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/analyze-kconfig.py50
-rwxr-xr-xbin/explore-kconfig.py3
-rw-r--r--lib/loader.py42
3 files changed, 80 insertions, 15 deletions
diff --git a/bin/analyze-kconfig.py b/bin/analyze-kconfig.py
index ff220b0..444ea2c 100755
--- a/bin/analyze-kconfig.py
+++ b/bin/analyze-kconfig.py
@@ -24,6 +24,16 @@ def main():
formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__
)
parser.add_argument(
+ "--failing-symbols",
+ action="store_true",
+ help="Show Kconfig symbols related to build failures. Must be used with an experiment result directory.",
+ )
+ parser.add_argument(
+ "--nop-symbols",
+ action="store_true",
+ help="Show Kconfig symbols which are only present in a single configuration. Must be used with an experiment result directory.",
+ )
+ parser.add_argument(
"--export-tree",
type=str,
help="Export decision tree model to file",
@@ -76,6 +86,11 @@ def main():
if os.path.isdir(args.model):
data = KConfigAttributes(args.kconfig_path, args.model)
+ if args.failing_symbols:
+ show_failing_symbols(data)
+ if args.nop_symbols:
+ show_nop_symbols(data)
+
if args.sample_size:
shuffled_data_indices = np.random.permutation(np.arange(len(data.data)))
sample_indices = shuffled_data_indices[: args.sample_size]
@@ -161,5 +176,40 @@ def main():
)
+def show_failing_symbols(data):
+ for symbol in data.symbol_names:
+ failed_true = len(
+ list(filter(lambda config: config[symbol] == True, data.failures))
+ )
+ failed_false = len(
+ list(filter(lambda config: config[symbol] == False, data.failures))
+ )
+ success_true = len(
+ list(filter(lambda config: config[0][symbol] == True, data.data))
+ )
+ success_false = len(
+ list(filter(lambda config: config[0][symbol] == False, data.data))
+ )
+ if success_false == 0 and failed_false > 0:
+ print(f"Setting {symbol} to n reliably causes the build to fail")
+ if success_true == 0 and failed_true > 0:
+ print(f"Setting {symbol} to y reliably causes the build to fail")
+
+
+def show_nop_symbols(data):
+ for symbol in data.symbol_names:
+ true_count = len(
+ list(filter(lambda config: config[symbol] == True, data.failures))
+ ) + len(list(filter(lambda config: config[0][symbol] == True, data.data)))
+ false_count = len(
+ list(filter(lambda config: config[symbol] == False, data.failures))
+ ) + len(list(filter(lambda config: config[0][symbol] == False, data.data)))
+ if false_count == 0:
+ print(f"Symbol {symbol} is never n")
+ if true_count == 0:
+ print(f"Symbol {symbol} is never y")
+ pass
+
+
if __name__ == "__main__":
main()
diff --git a/bin/explore-kconfig.py b/bin/explore-kconfig.py
index 7602076..5b4bdc6 100755
--- a/bin/explore-kconfig.py
+++ b/bin/explore-kconfig.py
@@ -96,12 +96,13 @@ def main():
for i in range(args.random):
logging.info(f"Running randconfig {i+1} of {args.random}")
status = kconf.run_randconfig()
- if status["success"]:
+ if args.with_neighbourhood and status["success"]:
config_filename = status["config_path"]
logging.info(f"Exploring neighbourhood of {config_filename}")
kconf.run_exploration_from_file(config_filename)
if args.neighbourhood:
+ # TODO also explore range of numeric options
if os.path.isfile(args.neighbourhood):
kconf.run_exploration_from_file(args.neighbourhood)
elif os.path.isdir(args.neighbourhood):
diff --git a/lib/loader.py b/lib/loader.py
index 5e9b20a..a1f9ca6 100644
--- a/lib/loader.py
+++ b/lib/loader.py
@@ -1639,7 +1639,7 @@ class MIMOSA:
:returns: numpy array of mean currents (µA per 10µs)
"""
- ua_max = 1.836 / self.shunt * 1000000
+ ua_max = 1.836 / self.shunt * 1_000_000
ua_step = ua_max / 65535
return charge * ua_step
@@ -1694,7 +1694,7 @@ class MIMOSA:
:param charges: numpy array of charges (pJ per 10µs)
:returns: numpy array of currents (mean µA per 10µs)"""
- ua_max = 1.836 / self.shunt * 1000000
+ ua_max = 1.836 / self.shunt * 1_000_000
ua_step = ua_max / 65535
return charges.astype(np.double) * ua_step
@@ -1711,11 +1711,11 @@ class MIMOSA:
"""
trigidx = []
- if len(triggers) < 1000000:
+ if len(triggers) < 1_000_000:
self.errors.append("MIMOSA log is too short")
return trigidx
- prevtrig = triggers[999999]
+ prevtrig = triggers[999_999]
# if the first trigger is high (i.e., trigger/buzzer pin is active before the benchmark starts),
# something went wrong and are unable to determine when the first
@@ -1735,7 +1735,7 @@ class MIMOSA:
# the device is reset for MIMOSA calibration in the first 10s and may
# send bogus interrupts -> bogus triggers
- for i in range(1000000, triggers.shape[0]):
+ for i in range(1_000_000, triggers.shape[0]):
trig = triggers[i]
if trig != prevtrig:
# Due to MIMOSA's integrate-read-reset cycle, the charge/current
@@ -1758,27 +1758,27 @@ class MIMOSA:
"""
r1idx = 0
r2idx = 0
- ua_r1 = self.voltage / self.r1 * 1000000
+ ua_r1 = self.voltage / self.r1 * 1_000_000
# first second may be bogus
- for i in range(100000, len(currents)):
+ for i in range(100_000, len(currents)):
if r1idx == 0 and currents[i] > ua_r1 * 0.6:
r1idx = i
elif (
r1idx != 0
and r2idx == 0
- and i > (r1idx + 180000)
+ and i > (r1idx + 180_000)
and currents[i] < ua_r1 * 0.4
):
r2idx = i
# 2s disconnected, 2s r1, 2s r2 with r1 < r2 -> ua_r1 > ua_r2
# allow 5ms buffer in both directions to account for bouncing relais contacts
return (
- r1idx - 180500,
+ r1idx - 180_500,
r1idx - 500,
r1idx + 500,
r2idx - 500,
r2idx + 500,
- r2idx + 180500,
+ r2idx + 180_500,
)
def calibration_function(self, charges, cal_edges):
@@ -1817,8 +1817,8 @@ class MIMOSA:
cal_r1_mean = np.mean(chg_r1)
cal_r2_mean = np.mean(chg_r2)
- ua_r1 = self.voltage / self.r1 * 1000000
- ua_r2 = self.voltage / self.r2 * 1000000
+ ua_r1 = self.voltage / self.r1 * 1_000_000
+ ua_r2 = self.voltage / self.r2 * 1_000_000
if cal_r2_mean > cal_0_mean:
b_lower = (ua_r2 - 0) / (cal_r2_mean - cal_0_mean)
@@ -1947,11 +1947,14 @@ class MIMOSA:
class KConfigAttributes:
def __init__(self, kconfig_path, datadir):
experiments = list()
+ failed_experiments = list()
for direntry in os.listdir(datadir):
config_path = f"{datadir}/{direntry}/.config"
attr_path = f"{datadir}/{direntry}/attributes.json"
if os.path.exists(attr_path):
experiments.append((config_path, attr_path))
+ elif os.path.exists(config_path):
+ failed_experiments.append(config_path)
kconf = kconfiglib.Kconfig(kconfig_path)
self.kconf = kconf
@@ -1966,15 +1969,18 @@ class KConfigAttributes:
)
)
- self.choice_names = sorted(map(lambda choice: choice.name, kconf.choices))
+ self.choice_names = sorted(
+ map(lambda choice: choice.name or choice.name_and_loc, kconf.choices)
+ )
self.symbol = kconf.syms
self.choice = dict()
for choice in kconf.choices:
- self.choice[choice.name] = choice
+ self.choice[choice.name or choice.name_and_loc] = choice
self.data = list()
self.configs = list()
+ self.failures = list()
for config_path, attr_path in experiments:
self.configs.append(config_path)
@@ -1987,3 +1993,11 @@ class KConfigAttributes:
if kconf.syms[sym].tri_value == 2:
config[sym] = True
self.data.append((frozendict(config), attr))
+
+ for config_path in failed_experiments:
+ kconf.load_config(config_path)
+ config = dict.fromkeys(self.symbol_names, False)
+ for sym in self.symbol_names:
+ if kconf.syms[sym].tri_value == 2:
+ config[sym] = True
+ self.failures.append(frozendict(config))