]> rtime.felk.cvut.cz Git - linux-conf-perf.git/blob - scripts/kconfig2dot/kconfig2dot.cc
kconfig2dot: Eliminate parallel edges between common expressions
[linux-conf-perf.git] / scripts / kconfig2dot / kconfig2dot.cc
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <locale.h>
5 #include <stdbool.h>
6 #include <unistd.h>
7
8 #include <kconfig/lkc.h>
9 #include <build_files.h>
10 #include <macros.h>
11
12 #include <set>
13 #include <string>
14
15 #define STRINGIFY(val) #val
16 #define TOSTRING(val) STRINGIFY(val)
17 #define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; })
18 #define CHECKPTR(cmd) ({ void *ptr = (cmd); if (ptr == (void*)-1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ptr; })
19 #define CHECKNULL(cmd) ({ void *ptr = (cmd); if (ptr == NULL) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ptr; })
20
21 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x)))
22
23 int verbose_level;
24
25 char *kconfig_file;
26 char *dot_file;
27 /* char *input_config_file; */
28
29 const char *interesting_opts[] = {
30     "BLK_DEV_IO_TRACE",
31     "BRANCH_PROFILE_NONE",
32     "BRANCH_TRACER",
33     "CONSTRUCTORS",
34     "DYNAMIC_FTRACE",
35     "ENABLE_DEFAULT_TRACERS",
36     "EVENT_TRACE_TEST_SYSCALLS",
37     "FREEZER",
38     "FTRACE_MCOUNT_RECORD",
39     "FTRACE_SELFTEST",
40     "FTRACE_STARTUP_TEST",
41     "FTRACE_SYSCALLS",
42     "FUNCTION_GRAPH_TRACER",
43     "FUNCTION_PROFILER",
44     "FUNCTION_TRACER",
45     "GCOV_KERNEL",
46     "GENERIC_TRACER",
47     "HIBERNATE_CALLBACKS",
48     "HIBERNATION",
49     "HZ_PERIODIC",
50     "INTERRUPT_OFF_HIST",
51     "IRQSOFF_TRACER",
52     "IRQ_DOMAIN_DEBUG",
53     "LZO_COMPRESS",
54     "LZO_DECOMPRESS",
55     "MISSED_TIMER_OFFSETS_HIST",
56     "NO_HZ",
57     "NO_HZ_COMMON",
58     "NO_HZ_IDLE",
59     "PM",
60     "PM_ADVANCED_DEBUG",
61     "PM_AUTOSLEEP",
62     "PM_CLK",
63     "PM_DEBUG",
64     "PM_RUNTIME",
65     "PM_SLEEP",
66     "PM_SLEEP_DEBUG",
67     "PM_WAKELOCKS",
68     "PM_WAKELOCKS_GC",
69     "PREEMPT_OFF_HIST",
70     "PREEMPT_TRACER",
71     "PROFILE_ANNOTATED_BRANCHES",
72     "RING_BUFFER_ALLOW_SWAP",
73     "RING_BUFFER_BENCHMARK",
74     "RING_BUFFER_STARTUP_TEST",
75     "SCHED_TRACER",
76     "STACK_TRACER",
77     "TRACER_MAX_TRACE",
78     "TRACER_SNAPSHOT",
79     "TRACER_SNAPSHOT_PER_CPU_SWAP",
80     "TRACE_BRANCH_PROFILING",
81     "TRACE_IRQFLAGS",
82     "TRACING_BRANCHES",
83     "WAKEUP_LATENCY_HIST",
84     "WQ_POWER_EFFICIENT_DEFAULT",
85 };
86
87 bool is_interesting(struct symbol *sym)
88 {
89     unsigned i;
90
91     if (!sym->name)
92         return false;
93
94     for (i = 0; i < ARRAY_SIZE(interesting_opts); i++) {
95         if (strcmp(sym->name, interesting_opts[i]) == 0)
96             return true;
97     }
98     return false;
99 }
100
101 void print_help();
102
103 void print_expr(FILE *f, struct expr *e, const char *parent, const char *suffix, const char *edge_opts);
104 void print_symbol(FILE *f, struct symbol *sym);
105
106
107 void print_oper(FILE *f, struct expr *e, const char *parent, const char *label)
108 {
109     using namespace std;
110     static set<string> seen_expr;
111
112     fprintf(f, "\"%s\" -> \"%s\";\n", parent, e->id);
113
114     if (seen_expr.find(e->id) == seen_expr.end()) {
115         seen_expr.insert(e->id);
116         fprintf(f, "\"%s\" [shape=diamond,label=\"%s\"];\n", e->id, label);
117         print_expr(f, e->left.expr, e->id, "l", "");
118         print_expr(f, e->right.expr, e->id, "r", "");
119     }
120 }
121
122 void print_expr(FILE *f, struct expr *e, const char *parent, const char *suffix, const char *edge_opts)
123 {
124     if (e) {
125         switch (e->type) {
126         case E_NONE:
127             break;
128         case E_OR:
129             print_oper(f, e, parent, "|");
130             break;
131         case E_AND:
132             print_oper(f, e, parent, "&");
133             break;
134         case E_NOT:
135             print_expr(f, e->left.expr, parent, suffix, "arrowhead=odot");
136             break;
137         case E_EQUAL:
138             print_oper(f, e, parent, "=");
139             break;
140         case E_UNEQUAL:
141             print_oper(f, e, parent, "!=");
142             break;
143         case E_LIST:
144             printf("LIST\n");
145             break;
146         case E_SYMBOL: {
147             if (e->left.sym->name) {
148                 fprintf(f, "\"%s\" -> \"%s\" [%s];\n", parent, e->left.sym->name, edge_opts);
149                 print_symbol(f, e->left.sym);
150             }
151             break;
152         }
153         case E_RANGE:
154             printf("RANGE\n");
155             break;
156         }
157     }
158 }
159
160 void print_symbol(FILE *f, struct symbol *sym)
161 {
162 #define SYMBOL_PRINTED 0x80000000
163     if (sym->flags & SYMBOL_PRINTED)
164         return;
165     sym->flags |= SYMBOL_PRINTED;
166
167     const char *opts = "";
168     if (is_interesting(sym))
169         opts = " [penwidth=3]";
170     else
171         opts = " [color=gray]";
172     fprintf(f, "\"%s\"%s;\n", sym->name, opts);
173     print_expr(f, sym->dir_dep.expr, sym->name, "", "");
174     if (sym->rev_dep.expr) {
175         // TODO: revese dependencies
176         // printf("REVDEP %s: %s\n", sym->name, sym->rev_dep.expr->id);
177         // print_expr(f, sym->rev_dep.expr, sym->name, "", "color=green");
178     }
179 }
180
181
182 void generate_expr_id(struct expr *e);
183
184 void generate_expr_id_oper(struct expr *e, const char *op_str)
185 {
186     generate_expr_id(e->left.expr);
187     generate_expr_id(e->right.expr);
188     asprintf(&e->id, "(%s %s %s)", e->left.expr->id, op_str, e->right.expr->id);
189 }
190
191 void generate_expr_id(struct expr *e)
192 {
193     if (e) {
194         switch (e->type) {
195         case E_NONE:
196             break;
197         case E_OR:
198             generate_expr_id_oper(e, "||");
199             break;
200         case E_AND:
201             generate_expr_id_oper(e, "&&");
202             break;
203         case E_NOT:
204             generate_expr_id(e->left.expr);
205             asprintf(&e->id, "!%s", e->left.expr->id);
206             break;
207         case E_EQUAL:
208             generate_expr_id_oper(e, "==");
209             break;
210         case E_UNEQUAL:
211             generate_expr_id_oper(e, "!=");
212             break;
213         case E_LIST:
214             printf("LIST not implemented\n");
215             break;
216         case E_SYMBOL: {
217             if (e->left.sym->name && !e->id) {
218                 asprintf(&e->id, e->left.sym->name);
219                 generate_expr_id(e->left.sym->dir_dep.expr);
220                 generate_expr_id(e->left.sym->rev_dep.expr);
221             }
222             break;
223         }
224         case E_RANGE:
225             printf("RANGE not implemented\n");
226             break;
227         }
228     }
229 }
230
231 void generate_expr_ids()
232 {
233     int i;
234     struct symbol *sym;
235
236     for_all_symbols(i, sym) {
237         if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE)
238             && sym->name != NULL) {
239             if (is_interesting(sym)) {
240                 generate_expr_id(sym->dir_dep.expr);
241                 generate_expr_id(sym->rev_dep.expr);
242             }
243         }
244     }
245 }
246
247
248 int main(int argc, char **argv)
249 {
250     verbose_level = 1;
251     int i;
252     for (i = 1; i < argc; i++) {
253         if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
254             print_help();
255             exit(0);
256         } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
257             verbose_level++;
258 /*         } else if (!strcmp(argv[i], "--all")) { */
259 /*             full_config = true; */
260 /*         } else if (!strcmp(argv[i], "--inv")) { */
261 /*             inv_config = true; */
262         } else if (kconfig_file == NULL) {
263             kconfig_file = argv[i];
264         } else if (dot_file == NULL) {
265             dot_file = argv[i];
266 /*         } else if (output_config_file == NULL) { */
267 /*             output_config_file = argv[i]; */
268         } else {
269             Eprintf("Unknown parameter: %s\n", argv[i]);
270             exit(1);
271         }
272     }
273
274     if (dot_file == NULL || kconfig_file == NULL
275         /* || input_config_file == NULL */) {
276         Eprintf("Missing mandatroy arguments.\n");
277         print_help();
278         exit(2);
279     }
280
281     setlocale(LC_ALL, "");
282     bindtextdomain(PACKAGE, LOCALEDIR);
283     textdomain(PACKAGE);
284
285     setenv("ARCH", "powerpc", /*overwrite*/0);
286     setenv("KERNELVERSION", "1.2.3", /*overwrite*/0);
287     setenv("SRCARCH", "powerpc", /*overwrite*/0);
288
289     FILE *f;
290     if (strcmp(dot_file, "-") == 0) {
291         f = stdout;
292     } else {
293         f = fopen(dot_file, "w");
294         if (f == NULL) {
295             perror(dot_file);
296             exit(3);
297         }
298     }
299
300     char *slash = strrchr(kconfig_file, '/');
301     if (slash) {
302         *slash = 0;
303         if (chdir(kconfig_file)) {
304             perror(kconfig_file);
305             exit(1);
306         }
307         kconfig_file = slash + 1;
308     }
309
310     conf_parse(kconfig_file);
311     /* conf_read(input_config_file); */
312
313     generate_expr_ids();
314
315     fprintf(f, "digraph conf {\n");
316
317     struct symbol *sym;
318     for_all_symbols(i, sym) {
319         if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE)
320             && sym->name != NULL) {
321             if (is_interesting(sym)) {
322                 print_symbol(f, sym);
323             }
324         }
325     }
326     fprintf(f, "}\n");
327
328     fclose(f);
329
330     return 0;
331 }
332
333 void print_help() {
334     printf
335         ("Usage: allconfig [-v] [-h] [--all] [--inv] Kconfig Input Output\n");
336     printf("  This is generating full configuration.\n");
337     printf("  Output configuration has all configuration options.\n");
338     printf("\n");
339     printf(" Options:\n");
340     printf("  -v, --verbose Increase level of verbose output.\n");
341     printf("  -h, --help    Print this help text.\n");
342     printf
343         ("  --all         Genetate full configuration. Including non dependency\n");
344     printf("                configuration options");
345     printf
346         ("  --inv         Generate configuration of missing configratuon options.\n");
347 }
348
349 /* Local Variables: */
350 /* c-basic-offset: 4 */
351 /* End: */