From f7aa7b9e09f81970cae710fdd4a6f12aae375d8b Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 8 Oct 2021 14:12:19 +0200 Subject: add basic analyze-kconfig script --- lib/loader/__init__.py | 1 + lib/loader/kconfig.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 lib/loader/kconfig.py (limited to 'lib/loader') diff --git a/lib/loader/__init__.py b/lib/loader/__init__.py index 141c7ca..8f730bb 100644 --- a/lib/loader/__init__.py +++ b/lib/loader/__init__.py @@ -19,6 +19,7 @@ from .energytrace import ( EnergyTraceWithLogicAnalyzer, EnergyTraceWithTimer, ) +from .kconfig import KConfigAttributes from .keysight import DLog, KeysightCSV from .mimosa import MIMOSA diff --git a/lib/loader/kconfig.py b/lib/loader/kconfig.py new file mode 100644 index 0000000..1dbebc8 --- /dev/null +++ b/lib/loader/kconfig.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 + +import kconfiglib +from frozendict import frozendict +import json +import os +import subprocess + + +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" + metadata_path = f"{datadir}/{direntry}/metadata" + 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 + + self.kconfig_hash = self.file_hash(kconfig_path) + self.kconfig_dir = "unknown" + if "/" in kconfig_path: + self.kconfig_dir = kconfig_path.split("/")[-2] + + self.symbol_names = sorted( + map( + lambda sym: sym.name, + filter( + lambda sym: kconfiglib.TYPE_TO_STR[sym.type] + in ("bool", "tristate", "int", "string", "hex"), + kconf.syms.values(), + ), + ) + ) + + self.choice_names = sorted( + map(lambda choice: choice.name or choice.name_and_loc, kconf.choices) + ) + + self.choice = dict() + self.choice_symbol_names = list() + for choice in kconf.choices: + self.choice[choice.name or choice.name_and_loc] = choice + self.choice_symbol_names.extend(map(lambda sym: sym.name, choice.syms)) + + self.symbol = dict() + for symbol_name in self.symbol_names: + self.symbol[symbol_name] = kconf.syms[symbol_name] + + if int(os.getenv("DFATOOL_KCONF_WITH_CHOICE_NODES", 1)): + for sym_name in self.choice_symbol_names: + self.symbol_names.remove(sym_name) + self.param_names = self.symbol_names + self.choice_names + else: + self.param_names = self.symbol_names + + self.data = list() + self.configs = list() + self.failures = list() + + for config_path, attr_path in experiments: + self.configs.append(config_path) + kconf.load_config(config_path) + with open(attr_path, "r") as f: + attr = json.load(f) + + param = self._conf_to_param() + self.data.append((frozendict(param), attr)) + + for config_path in failed_experiments: + kconf.load_config(config_path) + param = self._conf_to_param() + self.failures.append(frozendict(param)) + + def _conf_to_param(self): + param = dict() + for sym_name in self.symbol_names: + sym = self.kconf.syms[sym_name] + if not sym.visibility and sym.str_value == "": + param[sym_name] = None + elif kconfiglib.TYPE_TO_STR[sym.type] in ("int", "hex"): + try: + param[sym_name] = int(sym.str_value, base=0) + except ValueError: + print( + f"Warning: Illegal value for {sym.__repr__()}, defaulting to None" + ) + param[sym_name] = None + else: + param[sym_name] = sym.str_value + for choice in self.choice_names: + if self.choice[choice].selection is None: + param[choice] = None + else: + param[choice] = self.choice[choice].selection.name + return param + + def file_hash(self, config_file): + status = subprocess.run( + ["sha256sum", config_file], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + ) + sha256sum = status.stdout.split()[0] + return sha256sum -- cgit v1.2.3