diff options
-rw-r--r-- | include/gras/detail/block.hpp | 8 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/block_props.cpp | 10 | ||||
-rw-r--r-- | lib/boost_fail/json_parser_read_104900.hpp | 331 | ||||
-rw-r--r-- | lib/gras_impl/block_actor.hpp | 8 | ||||
-rw-r--r-- | lib/json_parser.cpp | 36 | ||||
-rw-r--r-- | lib/top_block_query.cpp | 101 | ||||
-rw-r--r-- | python/gras/GRAS_Block.i | 22 | ||||
-rw-r--r-- | python/gras/GRAS_HierBlock.i | 8 | ||||
-rw-r--r-- | query/__init__.py | 14 | ||||
-rw-r--r-- | query/chart_factory.js | 11 | ||||
-rw-r--r-- | query/chart_overhead_compare.js | 7 | ||||
-rw-r--r-- | query/main.html | 2 | ||||
-rw-r--r-- | query/main.js | 4 | ||||
-rw-r--r-- | tests/query_test.py | 55 |
15 files changed, 544 insertions, 74 deletions
diff --git a/include/gras/detail/block.hpp b/include/gras/detail/block.hpp index ac9a669..d975b0f 100644 --- a/include/gras/detail/block.hpp +++ b/include/gras/detail/block.hpp @@ -3,6 +3,8 @@ #ifndef INCLUDED_GRAS_DETAIL_BLOCK_HPP #define INCLUDED_GRAS_DETAIL_BLOCK_HPP +#include <typeinfo> + namespace gras { @@ -12,6 +14,7 @@ struct GRAS_API PropertyRegistry virtual ~PropertyRegistry(void); virtual void set(const PMCC &) = 0; virtual PMCC get(void) = 0; + virtual const std::type_info &type(void) const = 0; }; template <typename ClassType, typename ValueType> @@ -39,6 +42,11 @@ public: return PMC_M((_my_class->*_getter)()); } + const std::type_info &type(void) const + { + return typeid(ValueType); + } + private: ClassType *_my_class; ValueType(ClassType::*_getter)(void); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f23d6ea..add46db 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -65,6 +65,7 @@ list(APPEND GRAS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hier_block.cpp ${CMAKE_CURRENT_SOURCE_DIR}/top_block.cpp ${CMAKE_CURRENT_SOURCE_DIR}/top_block_query.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/json_parser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/register_messages.cpp ${CMAKE_CURRENT_SOURCE_DIR}/weak_container.cpp ${CMAKE_CURRENT_SOURCE_DIR}/serialize_types.cpp diff --git a/lib/block_props.cpp b/lib/block_props.cpp index f32dc69..5d536bb 100644 --- a/lib/block_props.cpp +++ b/lib/block_props.cpp @@ -45,10 +45,8 @@ void BlockActor::handle_prop_access( PMCC Block::_handle_prop_access(const std::string &key, const PMCC &value, const bool set) { - PropertyRegistrySptr pr = (set)? - (*this)->block->setter_registry[key] : - (*this)->block->getter_registry[key] - ; + const PropertyRegistryPair &pair = (*this)->block->property_registry[key]; + PropertyRegistrySptr pr = (set)? pair.setter : pair.getter; if (not pr) throw std::invalid_argument("no property registered for key: " + key); if (set) { @@ -99,12 +97,12 @@ static PMCC prop_access_dispatcher(ActorType &actor, const std::string &key, con void Block::_register_getter(const std::string &key, void *pr) { - (*this)->block->getter_registry[key].reset(reinterpret_cast<PropertyRegistry *>(pr)); + (*this)->block->property_registry[key].getter.reset(reinterpret_cast<PropertyRegistry *>(pr)); } void Block::_register_setter(const std::string &key, void *pr) { - (*this)->block->setter_registry[key].reset(reinterpret_cast<PropertyRegistry *>(pr)); + (*this)->block->property_registry[key].setter.reset(reinterpret_cast<PropertyRegistry *>(pr)); } void Block::_set_property(const std::string &key, const PMCC &value) diff --git a/lib/boost_fail/json_parser_read_104900.hpp b/lib/boost_fail/json_parser_read_104900.hpp new file mode 100644 index 0000000..f7c6515 --- /dev/null +++ b/lib/boost_fail/json_parser_read_104900.hpp @@ -0,0 +1,331 @@ +// ---------------------------------------------------------------------------- +// Copyright (C) 2002-2006 Marcin Kalicinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see www.boost.org +// ---------------------------------------------------------------------------- +#ifndef BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED +#define BOOST_PROPERTY_TREE_DETAIL_JSON_PARSER_READ_HPP_INCLUDED + +//#define BOOST_SPIRIT_DEBUG + +#include <boost/property_tree/ptree.hpp> +#include <boost/property_tree/detail/ptree_utils.hpp> +#include <boost/property_tree/detail/json_parser_error.hpp> +#include <boost/spirit/include/classic.hpp> +#include <boost/limits.hpp> +#include <string> +#include <locale> +#include <istream> +#include <vector> +#include <algorithm> + +namespace boost { namespace property_tree { namespace json_parser +{ + + /////////////////////////////////////////////////////////////////////// + // Json parser context + + template<class Ptree> + struct context + { + + typedef typename Ptree::key_type::value_type Ch; + typedef std::basic_string<Ch> Str; + typedef typename std::vector<Ch>::iterator It; + + Str string; + Str name; + Ptree root; + std::vector<Ptree *> stack; + + struct a_object_s + { + context &c; + a_object_s(context &c): c(c) { } + void operator()(Ch) const + { + if (c.stack.empty()) + c.stack.push_back(&c.root); + else + { + Ptree *parent = c.stack.back(); + Ptree *child = &parent->push_back(std::make_pair(c.name, Ptree()))->second; + c.stack.push_back(child); + c.name.clear(); + } + } + }; + + struct a_object_e + { + context &c; + a_object_e(context &c): c(c) { } + void operator()(Ch) const + { + BOOST_ASSERT(c.stack.size() >= 1); + c.stack.pop_back(); + } + }; + + struct a_name + { + context &c; + a_name(context &c): c(c) { } + void operator()(It, It) const + { + c.name.swap(c.string); + c.string.clear(); + } + }; + + struct a_string_val + { + context &c; + a_string_val(context &c): c(c) { } + void operator()(It, It) const + { + BOOST_ASSERT(c.stack.size() >= 1); + c.stack.back()->push_back(std::make_pair(c.name, Ptree(c.string))); + c.name.clear(); + c.string.clear(); + } + }; + + struct a_literal_val + { + context &c; + a_literal_val(context &c): c(c) { } + void operator()(It b, It e) const + { + BOOST_ASSERT(c.stack.size() >= 1); + c.stack.back()->push_back(std::make_pair(c.name, Ptree(Str(b, e)))); + c.name.clear(); + c.string.clear(); + } + }; + + struct a_char + { + context &c; + a_char(context &c): c(c) { } + void operator()(It b, It e) const + { + c.string += *b; + } + }; + + struct a_escape + { + context &c; + a_escape(context &c): c(c) { } + void operator()(Ch ch) const + { + switch (ch) + { + case Ch('\"'): c.string += Ch('\"'); break; + case Ch('\\'): c.string += Ch('\\'); break; + case Ch('/'): c.string += Ch('/'); break; + case Ch('b'): c.string += Ch('\b'); break; + case Ch('f'): c.string += Ch('\f'); break; + case Ch('n'): c.string += Ch('\n'); break; + case Ch('r'): c.string += Ch('\r'); break; + case Ch('t'): c.string += Ch('\t'); break; + default: BOOST_ASSERT(0); + } + } + }; + + struct a_unicode + { + context &c; + a_unicode(context &c): c(c) { } + void operator()(unsigned long u) const + { + u = (std::min)(u, static_cast<unsigned long>((std::numeric_limits<Ch>::max)())); + c.string += Ch(u); + } + }; + + }; + + /////////////////////////////////////////////////////////////////////// + // Json grammar + + template<class Ptree> + struct json_grammar : + public boost::spirit::classic::grammar<json_grammar<Ptree> > + { + + typedef context<Ptree> Context; + typedef typename Ptree::key_type::value_type Ch; + + mutable Context c; + + template<class Scanner> + struct definition + { + + boost::spirit::classic::rule<Scanner> + root, object, member, array, item, value, string, number; + boost::spirit::classic::rule< + typename boost::spirit::classic::lexeme_scanner<Scanner>::type> + character, escape; + + definition(const json_grammar &self) + { + + using namespace boost::spirit::classic; + // There's a boost::assertion too, so another explicit using + // here: + using boost::spirit::classic::assertion; + + // Assertions + assertion<std::string> expect_root("expected object or array"); + assertion<std::string> expect_eoi("expected end of input"); + assertion<std::string> expect_objclose("expected ',' or '}'"); + assertion<std::string> expect_arrclose("expected ',' or ']'"); + assertion<std::string> expect_name("expected object name"); + assertion<std::string> expect_colon("expected ':'"); + assertion<std::string> expect_value("expected value"); + assertion<std::string> expect_escape("invalid escape sequence"); + + // JSON grammar rules + root + = expect_root(object | array) + >> expect_eoi(end_p) + ; + + object + = ch_p('{')[typename Context::a_object_s(self.c)] + >> (ch_p('}')[typename Context::a_object_e(self.c)] + | (list_p(member, ch_p(',')) + >> expect_objclose(ch_p('}')[typename Context::a_object_e(self.c)]) + ) + ) + ; + + member + = expect_name(string[typename Context::a_name(self.c)]) + >> expect_colon(ch_p(':')) + >> expect_value(value) + ; + + array + = ch_p('[')[typename Context::a_object_s(self.c)] + >> (ch_p(']')[typename Context::a_object_e(self.c)] + | (list_p(item, ch_p(',')) + >> expect_arrclose(ch_p(']')[typename Context::a_object_e(self.c)]) + ) + ) + ; + + item + = expect_value(value) + ; + + value + = string[typename Context::a_string_val(self.c)] + | (number | str_p("true") | "false" | "null")[typename Context::a_literal_val(self.c)] + | object + | array + ; + + number + = !ch_p("-") >> + (ch_p("0") | (range_p(Ch('1'), Ch('9')) >> *digit_p)) >> + !(ch_p(".") >> +digit_p) >> + !(chset_p(detail::widen<Ch>("eE").c_str()) >> + !chset_p(detail::widen<Ch>("-+").c_str()) >> + +digit_p) + ; + + string + = +(lexeme_d[confix_p('\"', *character, '\"')]) + ; + + character + = (anychar_p - "\\" - "\"") + [typename Context::a_char(self.c)] + | ch_p("\\") >> expect_escape(escape) + ; + + escape + = chset_p(detail::widen<Ch>("\"\\/bfnrt").c_str()) + [typename Context::a_escape(self.c)] + | 'u' >> uint_parser<unsigned long, 16, 4, 4>() + [typename Context::a_unicode(self.c)] + ; + + // Debug + BOOST_SPIRIT_DEBUG_RULE(root); + BOOST_SPIRIT_DEBUG_RULE(object); + BOOST_SPIRIT_DEBUG_RULE(member); + BOOST_SPIRIT_DEBUG_RULE(array); + BOOST_SPIRIT_DEBUG_RULE(item); + BOOST_SPIRIT_DEBUG_RULE(value); + BOOST_SPIRIT_DEBUG_RULE(string); + BOOST_SPIRIT_DEBUG_RULE(number); + BOOST_SPIRIT_DEBUG_RULE(escape); + BOOST_SPIRIT_DEBUG_RULE(character); + + } + + const boost::spirit::classic::rule<Scanner> &start() const + { + return root; + } + + }; + + }; + + template<class It, class Ch> + unsigned long count_lines(It begin, It end) + { + return static_cast<unsigned long>(std::count(begin, end, Ch('\n')) + 1); + } + + template<class Ptree> + void read_json_internal(std::basic_istream<typename Ptree::key_type::value_type> &stream, + Ptree &pt, + const std::string &filename) + { + + using namespace boost::spirit::classic; + typedef typename Ptree::key_type::value_type Ch; + typedef typename std::vector<Ch>::iterator It; + + // Load data into vector + std::vector<Ch> v(std::istreambuf_iterator<Ch>(stream.rdbuf()), + std::istreambuf_iterator<Ch>()); + if (!stream.good()) + BOOST_PROPERTY_TREE_THROW(json_parser_error("read error", filename, 0)); + + // Prepare grammar + json_grammar<Ptree> g; + + // Parse + try + { + parse_info<It> pi = parse(v.begin(), v.end(), g, + space_p | comment_p("//") | comment_p("/*", "*/")); + if (!pi.hit || !pi.full) + BOOST_PROPERTY_TREE_THROW((parser_error<std::string, It>(v.begin(), "syntax error"))); + } + catch (parser_error<std::string, It> &e) + { + BOOST_PROPERTY_TREE_THROW(json_parser_error(e.descriptor, filename, count_lines<It, Ch>(v.begin(), e.where))); + } + + // Swap grammar context root and pt + pt.swap(g.c.root); + + } + +} } } + +#endif diff --git a/lib/gras_impl/block_actor.hpp b/lib/gras_impl/block_actor.hpp index bc4ecdd..269674c 100644 --- a/lib/gras_impl/block_actor.hpp +++ b/lib/gras_impl/block_actor.hpp @@ -24,6 +24,11 @@ namespace gras { typedef boost::shared_ptr<PropertyRegistry> PropertyRegistrySptr; +struct PropertyRegistryPair +{ + PropertyRegistrySptr setter; + PropertyRegistrySptr getter; +}; struct BlockActor : Apology::Worker { @@ -163,8 +168,7 @@ struct BlockActor : Apology::Worker std::vector<std::vector<OutputHintMessage> > output_allocation_hints; //property stuff - std::map<std::string, PropertyRegistrySptr> getter_registry; - std::map<std::string, PropertyRegistrySptr> setter_registry; + std::map<std::string, PropertyRegistryPair> property_registry; BlockStats stats; }; diff --git a/lib/json_parser.cpp b/lib/json_parser.cpp new file mode 100644 index 0000000..d66297f --- /dev/null +++ b/lib/json_parser.cpp @@ -0,0 +1,36 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +//--------- begin bullshit --------------// +#include <boost/version.hpp> +//why the fuck does no OS ever patch boost when there is a bug +//https://svn.boost.org/trac/boost/ticket/6785 +#if BOOST_VERSION == 104900 +#include "boost_fail/json_parser_read_104900.hpp" +#endif +//--------- end bullshit --------------// + +#include "gras_impl/debug.hpp" +#include <boost/property_tree/json_parser.hpp> +#include <boost/property_tree/ptree.hpp> +#include <boost/regex.hpp> +#include <sstream> +#include <string> + +boost::property_tree::ptree json_to_ptree(const std::string &s) +{ + std::stringstream ss(s); + boost::property_tree::ptree pt; + boost::property_tree::json_parser::read_json(ss, pt); + return pt; +} + +//http://stackoverflow.com/questions/13464383/boost-property-write-json-incorrect-behaviour +std::string ptree_to_json(const boost::property_tree::ptree &p) +{ + boost::regex exp("\"(null|true|false|[0-9]+(\\.[0-9]+)?)\""); + std::stringstream ss; + boost::property_tree::json_parser::write_json(ss, p); + std::string rv = boost::regex_replace(ss.str(), exp, "$1"); + + return rv; +} diff --git a/lib/top_block_query.cpp b/lib/top_block_query.cpp index 29d3bb0..9d8afbe 100644 --- a/lib/top_block_query.cpp +++ b/lib/top_block_query.cpp @@ -4,15 +4,13 @@ #include <gras/top_block.hpp> #include <boost/foreach.hpp> #include <boost/property_tree/ptree.hpp> -#include <boost/property_tree/json_parser.hpp> -#include <boost/property_tree/xml_parser.hpp> -#include <boost/regex.hpp> #include <Theron/DefaultAllocator.h> #include <algorithm> -#include <sstream> using namespace gras; +using namespace boost::property_tree; + ThreadPool get_active_thread_pool(void); struct GetStatsReceiver : Theron::Receiver @@ -30,39 +28,47 @@ struct GetStatsReceiver : Theron::Receiver std::vector<GetStatsMessage> messages; }; -//http://stackoverflow.com/questions/13464383/boost-property-write-json-incorrect-behaviour -static std::string my_write_json(const boost::property_tree::ptree &pt) -{ - boost::regex exp("\"(null|true|false|[0-9]+(\\.[0-9]+)?)\""); - std::stringstream ss; - boost::property_tree::json_parser::write_json(ss, pt); - std::string rv = boost::regex_replace(ss.str(), exp, "$1"); - - return rv; -} - -static std::string query_blocks(ElementImpl *self, const boost::property_tree::ptree &) +static ptree query_blocks(ElementImpl *self, const ptree &) { - boost::property_tree::ptree root; - boost::property_tree::ptree e; + ptree root; + ptree e; BOOST_FOREACH(Apology::Worker *worker, self->executor->get_workers()) { - boost::property_tree::ptree t; - t.put_value(dynamic_cast<BlockActor *>(worker)->block_ptr->to_string()); - e.push_back(std::make_pair("", t)); + BlockActor *block = dynamic_cast<BlockActor *>(worker); + ptree prop_e; + typedef std::pair<std::string, PropertyRegistryPair> PropRegistryKVP; + BOOST_FOREACH(const PropRegistryKVP &p, block->property_registry) + { + ptree prop_attrs; + if (p.second.setter) + { + ptree type; + type.put_value(p.second.setter->type().name()); + prop_attrs.push_back(std::make_pair("setter", type)); + } + if (p.second.getter) + { + ptree type; + type.put_value(p.second.getter->type().name()); + prop_attrs.push_back(std::make_pair("getter", type)); + } + ptree block_attrs; + block_attrs.push_back(std::make_pair(p.first, prop_attrs)); + prop_e.push_back(std::make_pair("props", block_attrs)); + } + e.push_back(std::make_pair(block->block_ptr->to_string(), prop_e)); } root.push_back(std::make_pair("blocks", e)); - return my_write_json(root); + return root; } -static std::string query_stats(ElementImpl *self, const boost::property_tree::ptree &query) +static ptree query_stats(ElementImpl *self, const ptree &query) { - //parse list of block ids needed in this query std::vector<std::string> block_ids; - BOOST_FOREACH(const boost::property_tree::ptree::value_type &v, query.get_child("args")) + if (query.count("blocks") != 0) { - if (v.first.data() == std::string("block")) + BOOST_FOREACH(const ptree::value_type &v, query.get_child("blocks")) { block_ids.push_back(v.second.get<std::string>("")); } @@ -86,7 +92,7 @@ static std::string query_stats(ElementImpl *self, const boost::property_tree::pt while (outstandingCount) outstandingCount -= receiver.Wait(outstandingCount); //create root level node - boost::property_tree::ptree root; + ptree root; root.put("now", time_now()); root.put("tps", time_tps()); @@ -110,11 +116,11 @@ static std::string query_stats(ElementImpl *self, const boost::property_tree::pt } //iterate through blocks - boost::property_tree::ptree blocks; + ptree blocks; BOOST_FOREACH(const GetStatsMessage &message, receiver.messages) { const BlockStats &stats = message.stats; - boost::property_tree::ptree block; + ptree block; block.put("tps", time_tps()); block.put("stats_time", message.stats_time); block.put("init_time", stats.init_time); @@ -129,9 +135,9 @@ static std::string query_stats(ElementImpl *self, const boost::property_tree::pt block.put("total_time_output", stats.total_time_output); block.put("actor_queue_depth", stats.actor_queue_depth); #define my_block_ptree_append(l) { \ - boost::property_tree::ptree e; \ + ptree e; \ for (size_t i = 0; i < stats.l.size(); i++) { \ - boost::property_tree::ptree t; t.put_value(stats.l[i]); \ + ptree t; t.put_value(stats.l[i]); \ e.push_back(std::make_pair("", t)); \ } \ block.push_back(std::make_pair(#l, e)); \ @@ -151,22 +157,33 @@ static std::string query_stats(ElementImpl *self, const boost::property_tree::pt blocks.push_back(std::make_pair(message.block_id, block)); } root.push_back(std::make_pair("blocks", blocks)); + return root; +} - return my_write_json(root); +static ptree query_props(ElementImpl *self, const ptree &query) +{ + ptree root; + const std::string block_id = query.get<std::string>("block"); + const std::string prop_key = query.get<std::string>("key"); + const std::string action = query.get<std::string>("action"); + const std::string value = query.get<std::string>("value"); + //TODO :-) + return root; } +ptree json_to_ptree(const std::string &s); +std::string ptree_to_json(const ptree &p); + std::string TopBlock::query(const std::string &args) { - //why the fuck does no OS ever patch boost when there is a bug - //https://svn.boost.org/trac/boost/ticket/6785 - //serialize the path args into xml -- but I just wanted json - std::stringstream query_args_ss(args); - boost::property_tree::ptree query_args_pt; - boost::property_tree::xml_parser::read_xml(query_args_ss, query_args_pt); + //convert json args into property tree + const ptree query = json_to_ptree(args); //dispatch based on path arg - std::string path = query_args_pt.get<std::string>("args.path"); - if (path == "/blocks.json") return query_blocks(this->get(), query_args_pt); - if (path == "/stats.json") return query_stats(this->get(), query_args_pt); - return ""; + std::string path = query.get<std::string>("path"); + ptree result; + 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); + return ptree_to_json(result); } diff --git a/python/gras/GRAS_Block.i b/python/gras/GRAS_Block.i index 4cf245e..bedeb85 100644 --- a/python/gras/GRAS_Block.i +++ b/python/gras/GRAS_Block.i @@ -176,6 +176,26 @@ struct BlockPython : Block } virtual PMCC _Py_handle_prop_access(const std::string &key, const PMCC &value, const bool set) = 0; + + void dummy_setter(const PMCC &) + { + //NOP + } + PMCC dummy_getter(void) + { + return PMC(); + } + + void _Py_register_dummy_setter(const std::string &key) + { + this->register_setter(key, &BlockPython::dummy_setter); + } + + void _Py_register_dummy_getter(const std::string &key) + { + this->register_getter(key, &BlockPython::dummy_getter); + } + }; } @@ -291,8 +311,10 @@ class Block(BlockPython): return PMC_M(getter()) def register_getter(self, key, getter): + self._Py_register_dummy_getter(key) self.__getter_registry[key] = getter def register_setter(self, key, setter): + self._Py_register_dummy_setter(key) self.__setter_registry[key] = setter %} diff --git a/python/gras/GRAS_HierBlock.i b/python/gras/GRAS_HierBlock.i index 65eb8d1..563dadd 100644 --- a/python/gras/GRAS_HierBlock.i +++ b/python/gras/GRAS_HierBlock.i @@ -174,6 +174,14 @@ class TopBlock(TopBlockPython): def disconnect(self, *args): return internal_connect__(TopBlockPython.disconnect, self, *args) + def query(self, args): + if isinstance(args, str): return TopBlockPython.query(self, args) + else: + import json + query_str = json.dumps(args) + result_str = TopBlockPython.query(self, query_str) + return json.loads(result_str) + class HierBlock(HierBlockPython): def __init__(self, name="Hier"): HierBlockPython.__init__(self, name) diff --git a/query/__init__.py b/query/__init__.py index c72222b..dc3339c 100644 --- a/query/__init__.py +++ b/query/__init__.py @@ -35,16 +35,10 @@ class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): arg_strs = dict((str(k), str(v)) for k, v in args.iteritems()) s.wfile.write(json.dumps(arg_strs)) else: - #why the fuck does no OS ever patch boost when there is a bug - #https://svn.boost.org/trac/boost/ticket/6785 - #serialize the path args into xml -- but I just wanted json - def xml_from_qs(k, v): - if not isinstance(v, list): v = [v] - return ''.join(['<%s>%s</%s>'%(k, v_i, k) for v_i in v]) - query_args = [xml_from_qs(k,v) for k,v in urlparse.parse_qs(o.query).iteritems()] - query_args.append(xml_from_qs('path', path)) - xml_args = xml_from_qs('args', ''.join(query_args)) - s.wfile.write(args['top_block'].query(xml_args)) + query_args = dict([(k,v) for k,v in urlparse.parse_qs(o.query).iteritems()]) + query_args['path'] = path + json_args = json.dumps(query_args) + s.wfile.write(args['top_block'].query(json_args)) return #clean up path for filesystem diff --git a/query/chart_factory.js b/query/chart_factory.js index 8b9656a..f3e02a7 100644 --- a/query/chart_factory.js +++ b/query/chart_factory.js @@ -39,7 +39,14 @@ function gras_chart_factory_update(registry, point) registry.point = point; //store last data point $.each(registry.active_charts, function(index, chart_info) { - chart_info.chart.update(point); + try + { + chart_info.chart.update(point); + } + catch(err) + { + //jQuery.error("gras_chart_factory_update error: " + err.message); + } }); } @@ -251,7 +258,7 @@ function gras_chart_factory_init(registry) $.getJSON('/blocks.json', function(data) { var container = $('#chart_designer_blocks'); - $.each(data.blocks, function(index, id) + $.each(data.blocks, function(id, attrs) { registry.block_ids.push(id); var cb_id = "chart_designer_blocks " + id; diff --git a/query/chart_overhead_compare.js b/query/chart_overhead_compare.js index 0ec9070..290b15d 100644 --- a/query/chart_overhead_compare.js +++ b/query/chart_overhead_compare.js @@ -23,8 +23,11 @@ GrasChartOverheadCompare.prototype.update = function(point) data_set.push(['Task', 'Percent']); $.each(this.ids, function(index, id) { - var percents = gras_extract_percent_times(point, id); - data_set.push([id, percents['total']]); + if (id in point.blocks) //skip this ID if it didnt show up in the data + { + var percents = gras_extract_percent_times(point, id); + data_set.push([id, percents['total']]); + } }); var data = google.visualization.arrayToDataTable(data_set) diff --git a/query/main.html b/query/main.html index 3fc3508..78f9227 100644 --- a/query/main.html +++ b/query/main.html @@ -20,7 +20,7 @@ <script type="text/javascript" src="/main.js"></script> <script type="text/javascript"> google.load('visualization', '1.0', {'packages':['corechart']}); - google.setOnLoadCallback(gras_stats_main); + google.setOnLoadCallback(gras_query_main); </script> </head> diff --git a/query/main.js b/query/main.js index b17af63..3b2fe31 100644 --- a/query/main.js +++ b/query/main.js @@ -33,7 +33,7 @@ var gras_query_stats = function(registry) url: "/stats.json", dataType: "json", traditional: true, //needed to parse data - data: {block:gras_chart_factory_active_blocks(registry)}, + data: {blocks:gras_chart_factory_active_blocks(registry)}, success: function(response) { registry.online = true; @@ -61,7 +61,7 @@ var gras_query_stats = function(registry) /*********************************************************************** * Init **********************************************************************/ -var gras_stats_main = function() +var gras_query_main = function() { //create a new registry - storage for gui state var registry = new GrasStatsRegistry(); diff --git a/tests/query_test.py b/tests/query_test.py index e93b5d6..ec8fade 100644 --- a/tests/query_test.py +++ b/tests/query_test.py @@ -4,7 +4,27 @@ import unittest import gras import numpy from demo_blocks import * -import json + +class MyBlock(gras.Block): + def __init__(self): + gras.Block.__init__(self, "MyBlock", out_sig=[numpy.uint32], in_sig=[numpy.uint32]) + self.foo = 0 + self.register_getter("foo", self.get_foo) + self.register_setter("foo", self.set_foo) + + def work(self, ins, outs): + n = min(len(ins[0]), len(outs[0])) + outs[0][:n] = ins[0][:n] + self.foo + self.consume(n) + self.produce(n) + + def get_foo(self): + return self.foo + + def set_foo(self, new_foo): + print "new_foo", new_foo + new_foo + 0 #throws if its not a number + self.foo = new_foo class QueryTest(unittest.TestCase): @@ -23,13 +43,34 @@ class QueryTest(unittest.TestCase): self.assertEqual(vec_sink.get_vector(), (0, 9, 8, 7, 6)) - blocks_json = self.tb.query("<args><path>/blocks.json</path></args>") - print blocks_json - json.loads(blocks_json) + #query the block list + blocks_result = self.tb.query(dict(path="/blocks.json")) + self.assertEqual(len(blocks_result['blocks']), 2) + + #pick a block to query below: + block_id = blocks_result['blocks'].keys()[0] + + #query the stats + stats_result = self.tb.query(dict( + path="/stats.json", + blocks=[block_id], + )) + self.assertTrue('tps' in stats_result) + self.assertTrue('now' in stats_result) + + #found the block we asked for + self.assertTrue(block_id in stats_result['blocks']) + + def test_props(self): + vec_source = VectorSource(numpy.uint32, [0, 9, 8, 7, 6]) + vec_sink = VectorSink(numpy.uint32) + block = MyBlock() + self.tb.connect(vec_source, block, vec_sink) + self.tb.run() - stats_json = self.tb.query("<args><path>/stats.json</path></args>") - print stats_json - json.loads(stats_json) + #query the block list + blocks_result = self.tb.query(dict(path="/blocks.json")) + self.assertEqual(len(blocks_result['blocks']), 3) if __name__ == '__main__': unittest.main() |