summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/block_handlers.cpp16
-rw-r--r--lib/gras_impl/input_buffer_queues.hpp5
-rw-r--r--lib/gras_impl/stats.hpp6
-rw-r--r--lib/top_block_query.cpp41
-rw-r--r--python/gras/query/__init__.py33
-rw-r--r--python/gras/query/chart_factory.js82
-rw-r--r--python/gras/query/chart_total_io_counts.js31
-rw-r--r--python/gras/query/main.js32
8 files changed, 169 insertions, 77 deletions
diff --git a/lib/block_handlers.cpp b/lib/block_handlers.cpp
index 9865331..1f744f4 100644
--- a/lib/block_handlers.cpp
+++ b/lib/block_handlers.cpp
@@ -137,11 +137,25 @@ void BlockActor::handle_get_stats(
){
MESSAGE_TRACER();
+ //instantaneous states we update here,
+ //and not interleaved with the rest of the code
+ const size_t num_inputs = this->get_num_inputs();
+ this->stats.items_enqueued.resize(num_inputs);
+ this->stats.tags_enqueued.resize(num_inputs);
+ this->stats.msgs_enqueued.resize(num_inputs);
+ for (size_t i = 0; i < num_inputs; i++)
+ {
+ this->stats.items_enqueued[i] = this->input_queues.get_items_enqueued(i);
+ this->stats.tags_enqueued[i] = this->input_tags[i].size();
+ this->stats.msgs_enqueued[i] = this->input_msgs[i].size();
+ }
+
+ //create the message reply object
GetStatsMessage message;
message.block_id = this->block_ptr->to_string();
message.stats = this->stats;
message.stats_time = time_now();
- this->Send(message, from); //ACK
+ this->Send(message, from); //ACK
this->highPrioAck();
}
diff --git a/lib/gras_impl/input_buffer_queues.hpp b/lib/gras_impl/input_buffer_queues.hpp
index 51ff3e6..48533b9 100644
--- a/lib/gras_impl/input_buffer_queues.hpp
+++ b/lib/gras_impl/input_buffer_queues.hpp
@@ -146,6 +146,11 @@ struct InputBufferQueues
_bitset.set(i, _enqueued_bytes[i] >= _reserve_bytes[i]);
}
+ GRAS_FORCE_INLINE size_t get_items_enqueued(const size_t i)
+ {
+ return _enqueued_bytes[i]/_items_sizes[i];
+ }
+
BitSet _bitset;
std::vector<size_t> _items_sizes;
std::vector<size_t> _enqueued_bytes;
diff --git a/lib/gras_impl/stats.hpp b/lib/gras_impl/stats.hpp
index 3f78b8d..7edab29 100644
--- a/lib/gras_impl/stats.hpp
+++ b/lib/gras_impl/stats.hpp
@@ -29,6 +29,7 @@ struct BlockStats
time_ticks_t start_time;
time_ticks_t stop_time;
+ //overall tracking of ports
std::vector<item_index_t> items_consumed;
std::vector<item_index_t> tags_consumed;
std::vector<item_index_t> msgs_consumed;
@@ -36,6 +37,11 @@ struct BlockStats
std::vector<item_index_t> tags_produced;
std::vector<item_index_t> msgs_produced;
+ //instantaneous port status
+ std::vector<size_t> items_enqueued;
+ std::vector<size_t> msgs_enqueued;
+ std::vector<size_t> tags_enqueued;
+
item_index_t work_count;
time_ticks_t time_last_work;
time_ticks_t total_time_prep;
diff --git a/lib/top_block_query.cpp b/lib/top_block_query.cpp
index a8091d2..f00efd2 100644
--- a/lib/top_block_query.cpp
+++ b/lib/top_block_query.cpp
@@ -5,7 +5,9 @@
#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 <algorithm>
#include <sstream>
using namespace gras;
@@ -36,13 +38,28 @@ static std::string my_write_json(const boost::property_tree::ptree &pt)
return rv;
}
-std::string TopBlock::query(const std::string &)
+static std::string query_blocks(ElementImpl *self, const boost::property_tree::ptree &)
+{
+ boost::property_tree::ptree root;
+ boost::property_tree::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));
+ }
+ root.push_back(std::make_pair("blocks", e));
+ return my_write_json(root);
+}
+
+static std::string query_stats(ElementImpl *self, const boost::property_tree::ptree &)
{
//get stats with custom receiver and set high prio
GetStatsReceiver receiver;
size_t outstandingCount(0);
- BOOST_FOREACH(Apology::Worker *worker, (*this)->executor->get_workers())
+ BOOST_FOREACH(Apology::Worker *worker, self->executor->get_workers())
{
+ //send a message to the block's actor to query stats
dynamic_cast<BlockActor *>(worker)->highPrioPreNotify();
worker->Push(GetStatsMessage(), receiver.GetAddress());
outstandingCount++;
@@ -51,7 +68,6 @@ std::string TopBlock::query(const std::string &)
//create root level node
boost::property_tree::ptree root;
- root.put("id", this->to_string());
root.put("now", time_now());
root.put("tps", time_tps());
@@ -81,6 +97,9 @@ std::string TopBlock::query(const std::string &)
} \
block.push_back(std::make_pair(#l, e)); \
}
+ my_block_ptree_append(items_enqueued);
+ my_block_ptree_append(tags_enqueued);
+ my_block_ptree_append(msgs_enqueued);
my_block_ptree_append(items_consumed);
my_block_ptree_append(tags_consumed);
my_block_ptree_append(msgs_consumed);
@@ -93,3 +112,19 @@ std::string TopBlock::query(const std::string &)
return my_write_json(root);
}
+
+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);
+
+ //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 "";
+}
diff --git a/python/gras/query/__init__.py b/python/gras/query/__init__.py
index 06c7b70..b71b7e0 100644
--- a/python/gras/query/__init__.py
+++ b/python/gras/query/__init__.py
@@ -1,7 +1,9 @@
import time
import BaseHTTPServer
+import urlparse
import json
import os
+
__path__ = os.path.abspath(os.path.dirname(__file__))
server_registry = dict()
@@ -15,23 +17,39 @@ class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(s):
"""Respond to a GET request."""
+
+ #extract the path and set default
+ o = urlparse.urlparse(s.path)
args = server_registry[s.server]
- path = s.path
- if path.startswith('/'): path = path[1:]
- if not path: path = 'main.html'
+ path = o.path
+
+ #handle json requests
if path.endswith('.json'):
s.send_response(200)
s.send_header("Content-type", "application/json")
s.end_headers()
- if path == 'args.json':
+ if path == '/args.json':
arg_strs = dict((str(k), str(v)) for k, v in args.iteritems())
s.wfile.write(json.dumps(arg_strs))
- elif path == 'stats.json':
- s.wfile.write(args['top_block'].query(s.path))
else:
- s.wfile.write(json.dumps({}))
+ #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))
return
+
+ #clean up path for filesystem
+ if path.startswith('/'): path = path[1:]
+ if not path: path = 'main.html'
target = os.path.join(__path__, path)
+
+ #get files from the local file system
if os.path.exists(target):
s.send_response(200)
if target.endswith('.js'): s.send_header("Content-type", "text/javascript")
@@ -39,6 +57,7 @@ class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
else: s.send_header("Content-type", "text")
s.end_headers()
s.wfile.write(open(target).read())
+ #otherwise not found do 404
else:
s.send_response(404)
s.send_header("Content-type", "text/html")
diff --git a/python/gras/query/chart_factory.js b/python/gras/query/chart_factory.js
index 5b3239a..ae23728 100644
--- a/python/gras/query/chart_factory.js
+++ b/python/gras/query/chart_factory.js
@@ -1,4 +1,9 @@
/***********************************************************************
+ * Some constants
+ **********************************************************************/
+var GRAS_CHARTS_STD_WIDTH = 250;
+
+/***********************************************************************
* Chart registry for now chart types
**********************************************************************/
var gras_chart_get_registry = function()
@@ -12,43 +17,28 @@ var gras_chart_get_registry = function()
}
/***********************************************************************
- * update after new query event
+ * get blocks that need active querying
**********************************************************************/
-function gras_chart_factory_update(registry, point)
+function gras_chart_factory_active_blocks(registry)
{
+ var block_ids = new Array();
$.each(registry.active_charts, function(index, chart_info)
{
- chart_info.point = point; //store last data point
- chart_info.chart.update(point);
+ $.merge(block_ids, chart_info.args.block_ids);
});
+ return $.unique(block_ids);
}
/***********************************************************************
- * One time setup
+ * update after new query event
**********************************************************************/
-function gras_chart_factory_setup(registry, point)
+function gras_chart_factory_update(registry, point)
{
- //gui init for factory controls
- gras_chart_factory_init(registry);
-
- //block registry and checkboxes init
- $.each(point.blocks, function(id, block)
+ registry.point = point; //store last data point
+ $.each(registry.active_charts, function(index, chart_info)
{
- registry.block_ids.push(id);
- var container = $('#chart_designer_blocks');
- var div = $('<div />');
- $(div).append('<label>' + id + '</label>');
- var input = $('<input />').attr({
- type: 'checkbox',
- name: id
- });
- input.attr('checked', false);
- $(div).append(input);
- $(container).append(div);
+ chart_info.chart.update(point);
});
-
- //try to load last settings
- try{gras_chart_load(registry);}catch(e){}
}
/***********************************************************************
@@ -174,7 +164,7 @@ function gras_chart_factory_make(registry, args)
args['height'] = chart_box.height();
args['position'] = chart_box.offset();
chart.gc_resize = false;
- chart.update(chart_info.point);
+ chart.update(registry.point);
gras_chart_save(registry);
};
@@ -187,7 +177,7 @@ function gras_chart_factory_make(registry, args)
start: function(event, ui)
{
chart.gc_resize = true;
- chart.update(chart_info.point);
+ chart.update(registry.point);
}});
chart_box.css('position', 'absolute');
@@ -204,20 +194,9 @@ function gras_chart_factory_make(registry, args)
}
/***********************************************************************
- * chart factory handle online/offline
- **********************************************************************/
-function gras_chart_factory_online(registry)
-{
- if (!registry.online) registry.offline_count++;
- if (registry.online) $('#page').css('background-color', '#EEEEFF');
- else if (registry.offline_count%2 == 0) $('#page').css('background-color', '#FF4848');
- else if (registry.offline_count%2 == 1) $('#page').css('background-color', '#EEEEFF');
-}
-
-/***********************************************************************
* chart factory init
**********************************************************************/
-function gras_chart_factory_init(registry)
+function gras_chart_factory_init(registry, done_cb)
{
//init registry containers
registry.active_charts = new Array();
@@ -259,4 +238,29 @@ function gras_chart_factory_init(registry)
if (registry.overall_active) gras_query_stats(registry);
else window.clearInterval(registry.timeout_handle);
});
+
+ //block registry and checkboxes init
+ $.getJSON('/blocks.json', function(data)
+ {
+ $.each(data.blocks, function(index, id)
+ {
+ registry.block_ids.push(id);
+ var container = $('#chart_designer_blocks');
+ var div = $('<div />');
+ $(div).append('<label>' + id + '</label>');
+ var input = $('<input />').attr({
+ type: 'checkbox',
+ name: id
+ });
+ input.attr('checked', false);
+ $(div).append(input);
+ $(container).append(div);
+ });
+
+ //try to load last settings
+ try{gras_chart_load(registry);}catch(e){}
+
+ //done callback because getJSON was async
+ done_cb(registry);
+ });
}
diff --git a/python/gras/query/chart_total_io_counts.js b/python/gras/query/chart_total_io_counts.js
index 2f9ced3..f959414 100644
--- a/python/gras/query/chart_total_io_counts.js
+++ b/python/gras/query/chart_total_io_counts.js
@@ -21,20 +21,29 @@ GrasChartTotalIoCounts.prototype.update = function(point)
$('ul', this.div).remove(); //clear old lists
this.div.append(ul);
+ function make_entry(strong, span)
{
- var init_time = parseInt(block_data.init_time);
- var stats_time = parseInt(block_data.stats_time);
- var tps = parseInt(block_data.tps);
- var duration = (stats_time - init_time)/tps;
var li = $('<li />');
- var strong = $('<strong />').text('Elapsed' + ': ');
- var span = $('<span />').text(duration.toFixed(2).toString() + ' secs');
+ var strong = $('<strong />').text(strong + ": ");
+ var span = $('<span />').text(span);
li.append(strong);
li.append(span);
ul.append(li);
}
+ //create total time elapsed entry
+ {
+ var init_time = block_data.init_time;
+ var stats_time = block_data.stats_time;
+ var tps = block_data.tps;
+ var duration = (stats_time - init_time)/tps;
+ make_entry('Elapsed', duration.toFixed(2).toString() + ' secs');
+ }
+
var stuff = [
+ ['Enque', 'items', 'items_enqueued'],
+ ['Enque', 'tags', 'tags_enqueued'],
+ ['Enque', 'msgs', 'msgs_enqueued'],
['Input', 'items', 'items_consumed'],
['Input', 'tags', 'tags_consumed'],
['Input', 'msgs', 'msgs_consumed'],
@@ -50,12 +59,10 @@ GrasChartTotalIoCounts.prototype.update = function(point)
var key = contents[2];
$.each(block_data[key], function(index, count)
{
- var li = $('<li />');
- var strong = $('<strong />').text(dir + index.toString() + ': ');
- var span = $('<span />').text(count.toString() + ' ' + units);
- li.append(strong);
- li.append(span);
- if (count > 0) ul.append(li);
+ if (count > 0)
+ {
+ make_entry(dir + index.toString(), count.toString() + ' ' + units);
+ }
});
});
}
diff --git a/python/gras/query/main.js b/python/gras/query/main.js
index 8a261f9..a9c255b 100644
--- a/python/gras/query/main.js
+++ b/python/gras/query/main.js
@@ -1,9 +1,4 @@
/***********************************************************************
- * Some constants
- **********************************************************************/
-var GRAS_CHARTS_STD_WIDTH = 250;
-
-/***********************************************************************
* Stats registry data structure
**********************************************************************/
var GrasStatsRegistry = function()
@@ -17,6 +12,17 @@ var GrasStatsRegistry = function()
}
/***********************************************************************
+ * Server offline animation
+ **********************************************************************/
+function gras_handle_offline(registry)
+{
+ if (!registry.online) registry.offline_count++;
+ if (registry.online) $('#page').css('background-color', '#EEEEFF');
+ else if (registry.offline_count%2 == 0) $('#page').css('background-color', '#FF4848');
+ else if (registry.offline_count%2 == 1) $('#page').css('background-color', '#EEEEFF');
+}
+
+/***********************************************************************
* Query stats
**********************************************************************/
var gras_query_stats = function(registry)
@@ -26,10 +32,12 @@ var gras_query_stats = function(registry)
async: true,
url: "/stats.json",
dataType: "json",
+ traditional: true, //needed to parse data
+ data: {block:gras_chart_factory_active_blocks(registry)},
success: function(response)
{
registry.online = true;
- gras_chart_factory_online(registry);
+ gras_handle_offline(registry);
if (registry.overall_active)
{
gras_chart_factory_update(registry, response);
@@ -43,7 +51,7 @@ var gras_query_stats = function(registry)
error: function()
{
registry.online = false;
- gras_chart_factory_online(registry);
+ gras_handle_offline(registry);
registry.timeout_handle = window.setTimeout(function()
{
gras_query_stats(registry);
@@ -68,12 +76,6 @@ var gras_stats_main = function()
document.title += ' - ' + registry.top_id;
});
- //query the stats for initial setup
- $.getJSON('/stats.json', function(data)
- {
- gras_chart_factory_setup(registry, data);
- });
-
- //start the query loop in the background
- gras_query_stats(registry);
+ //initialize the charts factory
+ gras_chart_factory_init(registry, gras_query_stats);
}