summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gras/detail/block.hpp8
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/block_props.cpp10
-rw-r--r--lib/boost_fail/json_parser_read_104900.hpp331
-rw-r--r--lib/gras_impl/block_actor.hpp8
-rw-r--r--lib/json_parser.cpp36
-rw-r--r--lib/top_block_query.cpp101
-rw-r--r--python/gras/GRAS_Block.i22
-rw-r--r--python/gras/GRAS_HierBlock.i8
-rw-r--r--query/__init__.py14
-rw-r--r--query/chart_factory.js11
-rw-r--r--query/chart_overhead_compare.js7
-rw-r--r--query/main.html2
-rw-r--r--query/main.js4
-rw-r--r--tests/query_test.py55
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()