diff options
-rwxr-xr-x | bin/analyze-kconfig.py | 50 | ||||
-rwxr-xr-x | bin/explore-kconfig.py | 3 | ||||
-rw-r--r-- | lib/loader.py | 42 |
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)) |