diff options
-rw-r--r-- | lib/element.cpp | 13 | ||||
-rw-r--r-- | lib/top_block_query.cpp | 44 | ||||
-rw-r--r-- | query/__init__.py | 11 |
3 files changed, 59 insertions, 9 deletions
diff --git a/lib/element.cpp b/lib/element.cpp index c2ae39e..008027c 100644 --- a/lib/element.cpp +++ b/lib/element.cpp @@ -5,7 +5,6 @@ #include <boost/format.hpp> #include <boost/foreach.hpp> #include <boost/algorithm/string.hpp> -#include <boost/functional/hash.hpp> #include <cstdlib> using namespace gras; @@ -19,12 +18,10 @@ Element::Element(const std::string &name) { this->reset(new ElementImpl()); (*this)->name = name; - std::string extra; - std::string uid = name; - boost::hash<std::string> string_hash; - std::size_t h = string_hash(uid); + size_t which = 0; while (true) { + const std::string uid = str(boost::format("%s %u") % name % which); try { this->set_uid(uid); @@ -32,12 +29,10 @@ Element::Element(const std::string &name) } catch(const std::invalid_argument &ex) { - extra = str(boost::format("%04x") % short(h++)); - uid = name+" "+extra; + which++; } } - if (not extra.empty()) (*this)->repr = name; - else (*this)->repr = str(boost::format("%s (%s)") % name % extra); + (*this)->repr = str(boost::format("%s (%u)") % name % which); if (GENESIS) std::cerr << "===================================================\n" diff --git a/lib/top_block_query.cpp b/lib/top_block_query.cpp index e1ade67..1a5a408 100644 --- a/lib/top_block_query.cpp +++ b/lib/top_block_query.cpp @@ -3,6 +3,7 @@ #include "element_impl.hpp" #include "gras_impl/query_common.hpp" #include <boost/foreach.hpp> +#include <boost/format.hpp> #include <boost/property_tree/ptree.hpp> #include <Theron/DefaultAllocator.h> #include <algorithm> @@ -199,6 +200,48 @@ static ptree query_props(ElementImpl *self, const ptree &query) return root; } +static std::string query_flows(ElementImpl *self, const ptree &query) +{ + std::string buff; + buff += "digraph flat_flows {\n"; + buff += "rankdir=LR;\n"; + buff += "node [shape=record, fontsize=10];\n"; + + BOOST_FOREACH(Apology::Worker *w, self->executor->get_workers()) + { + BlockActor *actor = dynamic_cast<BlockActor *>(w->get_actor()); + std::string in_ports_str, out_ports_str; + for (size_t i = 0; i < w->get_num_inputs(); i++) + { + if (i) in_ports_str += " | "; + in_ports_str += str(boost::format("<in%u> %u") % i % i); + } + if (in_ports_str.size()) in_ports_str = "{" + in_ports_str + "} | "; + for (size_t i = 0; i < w->get_num_outputs(); i++) + { + if (i) out_ports_str += " | "; + out_ports_str += str(boost::format("<out%u> %u") % i % i); + } + if (out_ports_str.size()) out_ports_str = " | {" + out_ports_str + "}"; + buff += str(boost::format("%s [shape=record, label=\"{ %s %s %s }\", style=filled];\n") + % actor->GetAddress().AsString() % in_ports_str % actor->data->block->to_string() % out_ports_str + ); + } + + BOOST_FOREACH(const Apology::Flow &flow, self->executor->get_flat_flows()) + { + buff += str(boost::format("%s:out%u -> %s:in%u;\n") + % dynamic_cast<const Apology::Worker *>(flow.src.elem)->get_actor()->GetAddress().AsString() + % flow.src.index + % dynamic_cast<const Apology::Worker *>(flow.dst.elem)->get_actor()->GetAddress().AsString() + % flow.dst.index + ); + } + + buff += "}\n"; + return buff; +} + std::string TopBlock::query(const std::string &args) { //convert json args into property tree @@ -207,6 +250,7 @@ std::string TopBlock::query(const std::string &args) //dispatch based on path arg std::string path = query.get<std::string>("path"); ptree result; + if (path == "/flows.dot") return query_flows(this->get(), query); if (path == "/blocks.json") result = query_blocks(this->get(), query); if (path == "/stats.json") result = query_stats(this->get(), query); if (path == "/props.json") result = query_props(this->get(), query); diff --git a/query/__init__.py b/query/__init__.py index dc3339c..40c645b 100644 --- a/query/__init__.py +++ b/query/__init__.py @@ -26,6 +26,17 @@ class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): args = server_registry[s.server] path = o.path + if path == "/flow.png": + s.send_response(200) + s.send_header("Content-type", "image/png") + s.end_headers() + dot = args['top_block'].query(json.dumps(dict(path='/flows.dot'))) + import subprocess + p = subprocess.Popen(args=["dot", "-T", "png"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = p.communicate(input=dot) + s.wfile.write(stdout) + return + #handle json requests if path.endswith('.json'): s.send_response(200) |