resolver: print the resolver graph to console in DOT format.
authorIsmo Puustinen <ismo.puustinen@intel.com>
Tue, 17 Dec 2013 14:50:46 +0000 (16:50 +0200)
committerIsmo <ismo.puustinen@intel.com>
Fri, 20 Dec 2013 14:05:26 +0000 (16:05 +0200)
src/resolver/console.c
src/resolver/target.c
src/resolver/target.h

index d1628a4..85de4da 100644 (file)
@@ -1,5 +1,6 @@
 #include <murphy/core/console.h>
 #include <murphy/resolver/resolver.h>
+#include <murphy/resolver/target.h>
 
 static void dump(mrp_console_t *c, void *user_data, int argc, char **argv)
 {
@@ -15,6 +16,19 @@ static void dump(mrp_console_t *c, void *user_data, int argc, char **argv)
     }
 }
 
+static void dot(mrp_console_t *c, void *user_data, int argc, char **argv)
+{
+    mrp_context_t *ctx = c->ctx;
+
+    MRP_UNUSED(user_data);
+    MRP_UNUSED(argc);
+    MRP_UNUSED(argv);
+
+    if (ctx->r != NULL) {
+        mrp_resolver_dump_dot_graph(ctx->r, c->stdout);
+    }
+}
+
 #define RESOLVER_DESCRIPTION                                              \
     "Resolver commands provide runtime diagnostics and debugging for\n"   \
     "the Murphy resolver.\n"
@@ -24,7 +38,14 @@ static void dump(mrp_console_t *c, void *user_data, int argc, char **argv)
 #define DUMP_DESCRIPTION                        \
     "Dump the resolver facts and targets.\n"
 
+#define DOT_SYNTAX  "dot"
+#define DOT_SUMMARY "dump the resolver facts and targets in DOT format"
+#define DOT_DESCRIPTION                        \
+    "Dump the resolver facts and targets in DOT format.\n"
+
 MRP_CORE_CONSOLE_GROUP(resolver_group, "resolver", RESOLVER_DESCRIPTION, NULL, {
         MRP_TOKENIZED_CMD("dump", dump, FALSE,
                           DUMP_SYNTAX, DUMP_SUMMARY, DUMP_DESCRIPTION),
+        MRP_TOKENIZED_CMD("dot", dot, FALSE,
+                          DOT_SYNTAX, DOT_SUMMARY, DOT_DESCRIPTION),
 });
index bd2c998..326e8e1 100644 (file)
@@ -635,3 +635,121 @@ void dump_targets(mrp_resolver_t *r, FILE *fp)
             fprintf(fp, "  no update script\n");
     }
 }
+
+typedef enum {
+    DOT_NODE_TYPE_FACT,
+    DOT_NODE_TYPE_TABLE,
+    DOT_NODE_TYPE_SINK,
+    DOT_NODE_TYPE_SELECT,
+    DOT_NODE_TYPE_OTHER,
+} dot_node_type_t;
+
+
+static dot_node_type_t dot_node_type(char *name)
+{
+    if (!name)
+        return DOT_NODE_TYPE_OTHER;
+
+    if (name[0] == '$')
+        return DOT_NODE_TYPE_FACT;
+
+    if (strncmp(name, "_table_", 7) == 0)
+        return DOT_NODE_TYPE_TABLE;
+
+    if (strncmp(name, "_sink_", 6) == 0)
+        return DOT_NODE_TYPE_SINK;
+
+    if (strncmp(name, "_select_", 8) == 0)
+        return DOT_NODE_TYPE_SELECT;
+
+    return DOT_NODE_TYPE_OTHER;
+}
+
+
+static char *dot_fix(char *name)
+{
+    dot_node_type_t t = dot_node_type(name);
+
+    switch(t) {
+        case DOT_NODE_TYPE_FACT:
+            /* remove illegal characters */
+            return &name[1];
+
+        case DOT_NODE_TYPE_TABLE:
+            return &name[7];
+
+        case DOT_NODE_TYPE_SINK:
+            return &name[6];
+
+        case DOT_NODE_TYPE_SELECT:
+            return &name[8];
+
+        default:
+            break;
+    }
+    return name;
+}
+
+
+static char *dot_get_shape(dot_node_type_t t)
+{
+    switch(t) {
+        case DOT_NODE_TYPE_FACT:
+        case DOT_NODE_TYPE_TABLE:
+            return "box";
+
+        case DOT_NODE_TYPE_SINK:
+            return "trapezium";
+
+        case DOT_NODE_TYPE_SELECT:
+            return "diamond";
+
+        default:
+            break;
+    }
+    return "ellipse";
+}
+
+
+void mrp_resolver_dump_dot_graph(mrp_resolver_t *r, FILE *fp)
+{
+    int i, j;
+    target_t *t;
+
+    fprintf(fp, "digraph decision_graph {\n");
+
+    /* vertexes */
+    for (i = 0; i < r->ntarget; i++) {
+        dot_node_type_t i_type;
+        char *name;
+
+        t = r->targets + i;
+        name = dot_fix(t->name);
+        if (strcmp(name, "autoupdate") == 0)
+            continue;
+
+        i_type = dot_node_type(t->name);
+        fprintf(fp, "    %s [shape=%s];\n", name, dot_get_shape(i_type));
+    }
+
+    fprintf(fp, "\n");
+
+    /* edges */
+    for (i = 0; i < r->ntarget; i++) {
+        t = r->targets + i;
+        char *i_name = dot_fix(t->name);
+
+        if (strcmp(i_name, "autoupdate") == 0)
+            continue;
+
+        if (t->depends != NULL) {
+            for (j = 0; j < t->ndepend; j++) {
+                char *j_name = dot_fix(t->depends[j]);
+
+                fprintf(fp, "    %s -> %s;\n", i_name, j_name);
+            }
+        }
+    }
+
+    fprintf(fp, "}\n");
+}
index aeff4fc..aa894a7 100644 (file)
@@ -50,4 +50,8 @@ int schedule_target_autoupdate(mrp_resolver_t *r);
 target_t *lookup_target(mrp_resolver_t *s, const char *name);
 void dump_targets(mrp_resolver_t *r, FILE *fp);
 
+/** Dump the resolver dependency graph in DOT format. */
+void mrp_resolver_dump_dot_graph(mrp_resolver_t *r, FILE *fp);
+
+
 #endif /* __MURPHY_RESOLVER_TARGET_H__ */