]> rtime.felk.cvut.cz Git - linux-conf-perf.git/commitdiff
Add kconfig2dot tool
authorMichal Sojka <sojkam1@fel.cvut.cz>
Sat, 10 Oct 2015 21:03:23 +0000 (23:03 +0200)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Sat, 10 Oct 2015 21:03:23 +0000 (23:03 +0200)
scripts/kconfig2dot/.gitignore [new file with mode: 0644]
scripts/kconfig2dot/Makefile [new file with mode: 0644]
scripts/kconfig2dot/kconfig2dot.c [new file with mode: 0644]
scripts/shared/kconfig/expr.h

diff --git a/scripts/kconfig2dot/.gitignore b/scripts/kconfig2dot/.gitignore
new file mode 100644 (file)
index 0000000..f80c253
--- /dev/null
@@ -0,0 +1,3 @@
+x.dot
+x.pdf
+kconfig2dot
diff --git a/scripts/kconfig2dot/Makefile b/scripts/kconfig2dot/Makefile
new file mode 100644 (file)
index 0000000..1b14c60
--- /dev/null
@@ -0,0 +1,27 @@
+MAKEFLAGS += --no-builtin-rules
+.PHONY: all clean
+.SUFFIXES:
+
+all: kconfig2dot
+
+KCONFIG_PREFIX = ../shared/kconfig
+include $(KCONFIG_PREFIX)/files.mk
+
+SRC  = kconfig2dot.c
+OBJ = $(patsubst %.c,%.o,$(SRC))
+CFLAGS = -O0 -Wall -ggdb -DDEBUG
+INCLUDES = -I../shared
+
+%.o: %.c
+       gcc -c $(CFLAGS) -o $@ $^ $(INCLUDES)
+
+kconfig2dot: $(OBJ) $(KCONFIG_OBJ)
+       gcc -o $@ $^
+
+clean::
+       $(RM) $(OBJ)
+       $(RM) kconfig2dot
+
+test: kconfig2dot
+       ./kconfig2dot ../../targets/ryuglab/linux/Kconfig x.dot
+       dot -Tpdf x.dot > x.pdf
diff --git a/scripts/kconfig2dot/kconfig2dot.c b/scripts/kconfig2dot/kconfig2dot.c
new file mode 100644 (file)
index 0000000..9e49e60
--- /dev/null
@@ -0,0 +1,331 @@
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <kconfig/lkc.h>
+#include <build_files.h>
+#include <macros.h>
+
+#define STRINGIFY(val) #val
+#define TOSTRING(val) STRINGIFY(val)
+#define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
+#define CHECKPTR(cmd) ({ void *ptr = (cmd); if (ptr == (void*)-1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ptr; })
+#define CHECKNULL(cmd) ({ void *ptr = (cmd); if (ptr == NULL) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ptr; })
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
+
+int verbose_level;
+
+char *kconfig_file;
+char *dot_file;
+/* char *input_config_file; */
+
+const char *interesting_opts[] = {
+    "BLK_DEV_IO_TRACE",
+    "BRANCH_PROFILE_NONE",
+    "BRANCH_TRACER",
+    "CONSTRUCTORS",
+    "DYNAMIC_FTRACE",
+    "ENABLE_DEFAULT_TRACERS",
+    "EVENT_TRACE_TEST_SYSCALLS",
+    "FREEZER",
+    "FTRACE_MCOUNT_RECORD",
+    "FTRACE_SELFTEST",
+    "FTRACE_STARTUP_TEST",
+    "FTRACE_SYSCALLS",
+    "FUNCTION_GRAPH_TRACER",
+    "FUNCTION_PROFILER",
+    "FUNCTION_TRACER",
+    "GCOV_KERNEL",
+    "GENERIC_TRACER",
+    "HIBERNATE_CALLBACKS",
+    "HIBERNATION",
+    "HZ_PERIODIC",
+    "INTERRUPT_OFF_HIST",
+    "IRQSOFF_TRACER",
+    "IRQ_DOMAIN_DEBUG",
+    "LZO_COMPRESS",
+    "LZO_DECOMPRESS",
+    "MISSED_TIMER_OFFSETS_HIST",
+    "NO_HZ",
+    "NO_HZ_COMMON",
+    "NO_HZ_IDLE",
+    "PM",
+    "PM_ADVANCED_DEBUG",
+    "PM_AUTOSLEEP",
+    "PM_CLK",
+    "PM_DEBUG",
+    "PM_RUNTIME",
+    "PM_SLEEP",
+    "PM_SLEEP_DEBUG",
+    "PM_WAKELOCKS",
+    "PM_WAKELOCKS_GC",
+    "PREEMPT_OFF_HIST",
+    "PREEMPT_TRACER",
+    "PROFILE_ANNOTATED_BRANCHES",
+    "RING_BUFFER_ALLOW_SWAP",
+    "RING_BUFFER_BENCHMARK",
+    "RING_BUFFER_STARTUP_TEST",
+    "SCHED_TRACER",
+    "STACK_TRACER",
+    "TRACER_MAX_TRACE",
+    "TRACER_SNAPSHOT",
+    "TRACER_SNAPSHOT_PER_CPU_SWAP",
+    "TRACE_BRANCH_PROFILING",
+    "TRACE_IRQFLAGS",
+    "TRACING_BRANCHES",
+    "WAKEUP_LATENCY_HIST",
+    "WQ_POWER_EFFICIENT_DEFAULT",
+};
+
+bool is_interesting(struct symbol *sym)
+{
+    int i;
+
+    if (!sym->name)
+       return false;
+
+    for (i = 0; i < ARRAY_SIZE(interesting_opts); i++) {
+       if (strcmp(sym->name, interesting_opts[i]) == 0)
+           return true;
+    }
+    return false;
+}
+
+void print_help();
+
+void print_expr(FILE *f, struct expr *e, const char *parent, const char *suffix, const char *edge_opts);
+void print_symbol(FILE *f, struct symbol *sym);
+
+
+void print_oper(FILE *f, struct expr *e, const char *parent, const char *label)
+{
+    fprintf(f, "\"%s\" [shape=diamond,label=\"%s\"];\n", e->id, label);
+    fprintf(f, "\"%s\" -> \"%s\";\n", parent, e->id);
+    print_expr(f, e->left.expr, e->id, "l", "");
+    print_expr(f, e->right.expr, e->id, "r", "");
+}
+
+void print_expr(FILE *f, struct expr *e, const char *parent, const char *suffix, const char *edge_opts)
+{
+    if (e) {
+       switch (e->type) {
+       case E_NONE:
+           printf("NONE\n");
+           break;
+       case E_OR:
+           print_oper(f, e, parent, "|");
+           break;
+       case E_AND:
+           print_oper(f, e, parent, "&");
+           break;
+       case E_NOT:
+           print_expr(f, e->left.expr, parent, suffix, "label=\"!\",color=red");
+           break;
+       case E_EQUAL:
+           print_oper(f, e, parent, "=");
+           break;
+       case E_UNEQUAL:
+           print_oper(f, e, parent, "!=");
+           break;
+       case E_LIST:
+           printf("LIST\n");
+           break;
+       case E_SYMBOL: {
+           if (e->left.sym->name) {
+               fprintf(f, "\"%s\" -> \"%s\" [%s]\n", parent, e->left.sym->name, edge_opts);
+               print_symbol(f, e->left.sym);
+           }
+           break;
+       }
+       case E_RANGE:
+           printf("RANGE\n");
+           break;
+       }
+    }
+}
+
+void print_symbol(FILE *f, struct symbol *sym)
+{
+#define SYMBOL_PRINTED 0x80000000
+    if (sym->flags & SYMBOL_PRINTED)
+       return;
+    sym->flags |= SYMBOL_PRINTED;
+
+    char *opts = "";
+    if (is_interesting(sym))
+       opts = " [color=blue,fontcolor=blue]";
+    fprintf(f, "\"%s\"%s;\n", sym->name, opts);
+    print_expr(f, sym->dir_dep.expr, sym->name, "", "");
+}
+
+
+void generate_expr_id(struct expr *e);
+
+void generate_expr_id_oper(struct expr *e, const char *op_str)
+{
+    generate_expr_id(e->left.expr);
+    generate_expr_id(e->right.expr);
+    asprintf(&e->id, "(%s %s %s)", e->left.expr->id, op_str, e->right.expr->id);
+}
+
+void generate_expr_id(struct expr *e)
+{
+    if (e) {
+       switch (e->type) {
+       case E_NONE:
+           printf("NONE not implemented\n");
+           break;
+       case E_OR:
+           generate_expr_id_oper(e, "||");
+           break;
+       case E_AND:
+           generate_expr_id_oper(e, "&&");
+           break;
+       case E_NOT:
+           generate_expr_id(e->left.expr);
+           asprintf(&e->id, "not_%s", e->left.expr->id);
+           break;
+       case E_EQUAL:
+           generate_expr_id_oper(e, "==");
+           break;
+       case E_UNEQUAL:
+           generate_expr_id_oper(e, "!=");
+           break;
+       case E_LIST:
+           printf("LIST not implemented\n");
+           break;
+       case E_SYMBOL: {
+           if (e->left.sym->name) {
+               asprintf(&e->id, e->left.sym->name);
+               generate_expr_id(e->left.sym->dir_dep.expr);
+           }
+           break;
+       }
+       case E_RANGE:
+           printf("RANGE not implemented\n");
+           break;
+       }
+    }
+}
+
+void generate_expr_ids()
+{
+    int i;
+    struct symbol *sym;
+
+    for_all_symbols(i, sym) {
+        if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE)
+            && sym->name != NULL) {
+           if (is_interesting(sym)) {
+               generate_expr_id(sym->dir_dep.expr);
+           }
+        }
+    }
+}
+
+
+int main(int argc, char **argv)
+{
+    verbose_level = 1;
+    int i;
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
+            print_help();
+            exit(0);
+        } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
+            verbose_level++;
+/*         } else if (!strcmp(argv[i], "--all")) { */
+/*             full_config = true; */
+/*         } else if (!strcmp(argv[i], "--inv")) { */
+/*             inv_config = true; */
+        } else if (kconfig_file == NULL) {
+            kconfig_file = argv[i];
+        } else if (dot_file == NULL) {
+            dot_file = argv[i];
+/*         } else if (output_config_file == NULL) { */
+/*             output_config_file = argv[i]; */
+        } else {
+            Eprintf("Unknown parameter: %s\n", argv[i]);
+            exit(1);
+        }
+    }
+
+    if (dot_file == NULL || kconfig_file == NULL
+        /* || input_config_file == NULL */) {
+        Eprintf("Missing mandatroy arguments.\n");
+        print_help();
+        exit(2);
+    }
+
+    setlocale(LC_ALL, "");
+    bindtextdomain(PACKAGE, LOCALEDIR);
+    textdomain(PACKAGE);
+
+    setenv("ARCH", "powerpc", /*overwrite*/0);
+    setenv("KERNELVERSION", "1.2.3", /*overwrite*/0);
+    setenv("SRCARCH", "powerpc", /*overwrite*/0);
+
+    FILE *f;
+    if (strcmp(dot_file, "-") == 0) {
+       f = stdout;
+    } else {
+       f = fopen(dot_file, "w");
+       if (f == NULL) {
+           perror(dot_file);
+           exit(3);
+       }
+    }
+
+    char *slash = strrchr(kconfig_file, '/');
+    if (slash) {
+       *slash = 0;
+       if (chdir(kconfig_file)) {
+           perror(kconfig_file);
+           exit(1);
+       }
+       kconfig_file = slash + 1;
+    }
+
+    conf_parse(kconfig_file);
+    /* conf_read(input_config_file); */
+
+    generate_expr_ids();
+
+    fprintf(f, "digraph conf {\n");
+
+    struct symbol *sym;
+    for_all_symbols(i, sym) {
+        if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE)
+            && sym->name != NULL) {
+           if (is_interesting(sym)) {
+               print_symbol(f, sym);
+           }
+        }
+    }
+    fprintf(f, "}\n");
+
+    fclose(f);
+
+    return 0;
+}
+
+void print_help() {
+    printf
+        ("Usage: allconfig [-v] [-h] [--all] [--inv] Kconfig Input Output\n");
+    printf("  This is generating full configuration.\n");
+    printf("  Output configuration has all configuration options.\n");
+    printf("\n");
+    printf(" Options:\n");
+    printf("  -v, --verbose Increase level of verbose output.\n");
+    printf("  -h, --help    Print this help text.\n");
+    printf
+        ("  --all         Genetate full configuration. Including non dependency\n");
+    printf("                configuration options");
+    printf
+        ("  --inv         Generate configuration of missing configratuon options.\n");
+}
index 412ea8a2abb8b80c6f0a889e2fb9d7b55bf0bafa..118da41fbe1be478189c213fb7d099f7259d5bcc 100644 (file)
@@ -40,6 +40,7 @@ union expr_data {
 struct expr {
        enum expr_type type;
        union expr_data left, right;
+       char *id;               /* expression identifier - for common subexpression elimination in kconfig2dot */
 };
 
 #define EXPR_OR(dep1, dep2)    (((dep1)>(dep2))?(dep1):(dep2))