From 9e9308df1599bd13e808cacc6b3cea5a5c697df3 Mon Sep 17 00:00:00 2001
From: Josh Blum
Date: Sat, 11 May 2013 19:56:48 -0700
Subject: gras: moved query app to top level
---
CMakeLists.txt | 1 +
benchmark/.gitignore | 2 +
python/gras/CMakeLists.txt | 5 -
python/gras/query/CMakeLists.txt | 28 ---
python/gras/query/__init__.py | 81 --------
python/gras/query/chart_factory.js | 281 --------------------------
python/gras/query/chart_global_counters.js | 58 ------
python/gras/query/chart_handler_breakdown.js | 39 ----
python/gras/query/chart_overall_throughput.js | 47 -----
python/gras/query/chart_overhead_compare.js | 39 ----
python/gras/query/chart_port_counters.js | 76 -------
python/gras/query/chart_port_downtime.js | 47 -----
python/gras/query/main.css | 167 ---------------
python/gras/query/main.html | 54 -----
python/gras/query/main.js | 79 --------
python/gras/query/utils.js | 88 --------
query/CMakeLists.txt | 28 +++
query/__init__.py | 81 ++++++++
query/chart_factory.js | 281 ++++++++++++++++++++++++++
query/chart_global_counters.js | 58 ++++++
query/chart_handler_breakdown.js | 39 ++++
query/chart_overall_throughput.js | 47 +++++
query/chart_overhead_compare.js | 39 ++++
query/chart_port_counters.js | 76 +++++++
query/chart_port_downtime.js | 47 +++++
query/main.css | 167 +++++++++++++++
query/main.html | 54 +++++
query/main.js | 79 ++++++++
query/utils.js | 88 ++++++++
29 files changed, 1087 insertions(+), 1089 deletions(-)
delete mode 100644 python/gras/query/CMakeLists.txt
delete mode 100644 python/gras/query/__init__.py
delete mode 100644 python/gras/query/chart_factory.js
delete mode 100644 python/gras/query/chart_global_counters.js
delete mode 100644 python/gras/query/chart_handler_breakdown.js
delete mode 100644 python/gras/query/chart_overall_throughput.js
delete mode 100644 python/gras/query/chart_overhead_compare.js
delete mode 100644 python/gras/query/chart_port_counters.js
delete mode 100644 python/gras/query/chart_port_downtime.js
delete mode 100644 python/gras/query/main.css
delete mode 100644 python/gras/query/main.html
delete mode 100644 python/gras/query/main.js
delete mode 100644 python/gras/query/utils.js
create mode 100644 query/CMakeLists.txt
create mode 100644 query/__init__.py
create mode 100644 query/chart_factory.js
create mode 100644 query/chart_global_counters.js
create mode 100644 query/chart_handler_breakdown.js
create mode 100644 query/chart_overall_throughput.js
create mode 100644 query/chart_overhead_compare.js
create mode 100644 query/chart_port_counters.js
create mode 100644 query/chart_port_downtime.js
create mode 100644 query/main.css
create mode 100644 query/main.html
create mode 100644 query/main.js
create mode 100644 query/utils.js
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee09b26..21f1909 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -98,6 +98,7 @@ add_subdirectory(lib)
add_subdirectory(PMC)
add_subdirectory(python/gras)
add_subdirectory(tests)
+add_subdirectory(query)
########################################################################
# add gnuradio as sub-project
diff --git a/benchmark/.gitignore b/benchmark/.gitignore
index a74b07a..e9a5d35 100644
--- a/benchmark/.gitignore
+++ b/benchmark/.gitignore
@@ -1 +1,3 @@
/*.pyc
+/*.png
+/*.pdf
diff --git a/python/gras/CMakeLists.txt b/python/gras/CMakeLists.txt
index e91d8df..8171e7f 100644
--- a/python/gras/CMakeLists.txt
+++ b/python/gras/CMakeLists.txt
@@ -1,8 +1,3 @@
-########################################################################
-# add subdirs
-########################################################################
-add_subdirectory(query)
-
########################################################################
# Include swig generation macros
########################################################################
diff --git a/python/gras/query/CMakeLists.txt b/python/gras/query/CMakeLists.txt
deleted file mode 100644
index f9a855e..0000000
--- a/python/gras/query/CMakeLists.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-########################################################################
-# Install rules
-########################################################################
-include(GrPython)
-
-GR_PYTHON_INSTALL(
- FILES
- __init__.py
- DESTINATION ${GR_PYTHON_DIR}/gras/query
- COMPONENT ${GRAS_COMP_PYTHON}
-)
-
-INSTALL(
- FILES
- main.html
- main.js
- utils.js
- chart_factory.js
- chart_overhead_compare.js
- chart_overall_throughput.js
- chart_handler_breakdown.js
- chart_port_counters.js
- chart_global_counters.js
- chart_port_downtime.js
- main.css
- DESTINATION ${GR_PYTHON_DIR}/gras/query
- COMPONENT ${GRAS_COMP_PYTHON}
-)
diff --git a/python/gras/query/__init__.py b/python/gras/query/__init__.py
deleted file mode 100644
index c72222b..0000000
--- a/python/gras/query/__init__.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import time
-import BaseHTTPServer
-import urlparse
-import json
-import os
-
-__path__ = os.path.abspath(os.path.dirname(__file__))
-
-server_registry = dict()
-
-class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-
- #hide log messages to stdout by default
- def log_message(self, format, *args): pass
-
- def do_HEAD(s):
- s.send_response(200)
- s.send_header("Content-type", "text/html")
- s.end_headers()
-
- 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 = 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':
- 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))
- 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")
- elif target.endswith('.css'): s.send_header("Content-type", "text/css")
- 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")
- s.end_headers()
- s.wfile.write("
not found
")
-
-import select
-
-class http_server(object):
- def __init__(self, args, **kwargs):
- server_class = BaseHTTPServer.HTTPServer
- self._httpd = server_class(args, MyHandler)
- server_registry[self._httpd] = kwargs
-
- def serve_forever(self):
- while True:
- try: self._httpd.serve_forever()
- except select.error: pass
diff --git a/python/gras/query/chart_factory.js b/python/gras/query/chart_factory.js
deleted file mode 100644
index 8b9656a..0000000
--- a/python/gras/query/chart_factory.js
+++ /dev/null
@@ -1,281 +0,0 @@
-/***********************************************************************
- * Some constants
- **********************************************************************/
-var GRAS_CHARTS_STD_WIDTH = 250;
-
-/***********************************************************************
- * Chart registry for now chart types
- **********************************************************************/
-var gras_chart_get_registry = function()
-{
- return [
- {key:'overhead_compare', name:'Overhead Compare', factory:GrasChartOverheadCompare},
- {key:'overall_throughput', name:'Overall Throughput', factory:GrasChartOverallThroughput},
- {key:'handler_breakdown', name:'Handler Breakdown', factory:GrasChartHandlerBreakdown},
- {key:'port_counters', name:'Port Counters', factory:GrasChartPortCounts},
- {key:'global_counters', name:'Global Counters', factory:GrasChartGlobalCounts},
- {key:'port_downtime', name:'Port downtime', factory:GrasChartPortDowntime},
- ];
-}
-
-/***********************************************************************
- * get blocks that need active querying
- **********************************************************************/
-function gras_chart_factory_active_blocks(registry)
-{
- var block_ids = new Array();
- $.each(registry.active_charts, function(index, chart_info)
- {
- $.merge(block_ids, chart_info.args.block_ids);
- });
- return $.unique(block_ids);
-}
-
-/***********************************************************************
- * update after new query event
- **********************************************************************/
-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);
- });
-}
-
-/***********************************************************************
- * chart factory input handler
- **********************************************************************/
-function gras_chart_factory_handle_input(registry)
-{
- //get a list of the selected blocks
- var selected_blocks = new Array();
- $.each($('#chart_designer_blocks input'), function(index, input)
- {
- var input = $(input);
- if (input.is(':checked'))
- {
- selected_blocks.push(input.attr('name'));
- }
- });
-
- //get the type of chart to create
- var chart_type = $('#chart_type_selector').val();
-
- //create args for the factory make
- var args = {
- block_ids:selected_blocks,
- chart_type:chart_type,
- };
-
- //call into the factory with args
- gras_chart_factory_make(registry, args);
-}
-
-/***********************************************************************
- * save/load to/from local storage
- **********************************************************************/
-function gras_chart_save(registry)
-{
- if (typeof(Storage) === "undefined") return;
- var all_args = new Array();
- $.each(registry.active_charts, function(index, info)
- {
- all_args.push(info.args);
- });
- localStorage.setItem(registry.top_id, JSON.stringify({
- chart_args: all_args,
- overall_rate: registry.overall_rate,
- overall_active: registry.overall_active,
- }));
-}
-
-function gras_chart_load(registry)
-{
- if (typeof(Storage) === "undefined") return;
- var storage = JSON.parse(localStorage.getItem(registry.top_id));
- if (!storage) return;
-
- //restore misc settings in storage
- registry.overall_rate = storage.overall_rate;
- registry.overall_active = storage.overall_active;
-
- //rebuild all charts from args
- $.each(storage.chart_args, function(args_i, args)
- {
- //check that the blocks saved in the args actually exist
- var do_make = true;
- $.each(args.block_ids, function(block_id_i, block_id)
- {
- if ($.inArray(block_id, registry.block_ids) < 0)
- {
- do_make = false;
- }
- });
- if (do_make) gras_chart_factory_make(registry, args);
- });
-}
-
-/***********************************************************************
- * chart factory make routine
- **********************************************************************/
-function gras_chart_factory_make(registry, args)
-{
- //create containers
- var chart_box = $('').attr({class:'chart_container'});
- var tr = $('
');
- var td = $(' | ');
- tr.append(td);
-
- //call into the factory
- try
- {
- var chart = new registry.chart_factories[args.chart_type](args, td.get(0));
- }
- catch(err)
- {
- return;
- }
-
- //setup the title
- var tr_title = $('
');
- var th_title = $(' | ');
- tr_title.append(th_title);
- th_title.text(chart.title);
-
- //register the chart
- var chart_info = {chart:chart,args:args,panel:chart_box};
- registry.active_charts.push(chart_info);
- $('#charts_panel').append(chart_box);
-
- //close button
- var close_div = $('').attr({class:'chart_designer_block_close'});
- var close_href = $('').attr({href:'#', class:"ui-dialog-titlebar-close ui-corner-all", role:"button"});
- var close_span = $('').attr({class:"ui-icon ui-icon-closethick"}).text('close');
- close_div.append(close_href);
- close_href.append(close_span);
- th_title.append(close_div);
- $(close_href).click(function()
- {
- var index = $.inArray(chart_info, registry.active_charts);
- registry.active_charts.splice(index, 1);
- chart_box.remove();
- gras_chart_save(registry);
- });
- gras_chart_save(registry);
-
- //finish gui building
- chart_box.append(tr_title);
- chart_box.append(tr);
-
- //implement draggable and resizable from jquery ui
- var handle_stop = function(event, ui)
- {
- args['width'] = chart_box.width();
- args['height'] = chart_box.height();
- args['position'] = chart_box.offset();
- chart.gc_resize = false;
- chart.update(registry.point);
- gras_chart_save(registry);
- };
-
- if ('default_width' in chart) chart_box.width(chart.default_width);
- chart_box.resizable({stop: handle_stop, create: function(event, ui)
- {
- if ('width' in args) chart_box.width(args.width);
- if ('height' in args) chart_box.height(args.height);
- },
- start: function(event, ui)
- {
- chart.gc_resize = true;
- chart.update(registry.point);
- }});
-
- chart_box.css('position', 'absolute');
- chart_box.draggable({stop: handle_stop, create: function(event, ui)
- {
- if ('position' in args) chart_box.offset(args.position);
- }, cursor: "move"});
-
- //set the cursor on the title bar so its obvious
- tr_title.hover(
- function(){$(this).css('cursor','move'); close_div.show();},
- function(){$(this).css('cursor','auto'); close_div.hide();}
- );
- close_div.hide();
-}
-
-/***********************************************************************
- * chart factory init
- **********************************************************************/
-function gras_chart_factory_init(registry)
-{
- //init registry containers
- registry.active_charts = new Array();
- registry.chart_factories = new Array();
-
- //install callback for chart factory
- $('#chart_factory_button').click(function()
- {
- gras_chart_factory_handle_input(registry);
- });
-
- //init the chart selection input
- $.each(gras_chart_get_registry(), function(index, options)
- {
- registry.chart_factories[options.key] = options.factory;
- var option = $('').attr({value: options.key});
- option.text(options.name);
- $('#chart_type_selector').append(option);
- });
-
- //init chart overall gui controls
- var overall_rate = $('#chart_update_rate').attr({size:3});
- overall_rate.spinner({
- min: 1, max: 10, step: 0.5, stop: function(event, ui){$(this).change();}
- });
- var overall_active = $('#chart_active_state');
- overall_active.button();
-
- //callback for overall gui events
- function handle_gui_event()
- {
- registry.overall_active = overall_active.is(':checked');
- registry.overall_rate = overall_rate.val();
- gras_chart_save(registry);
- }
- overall_rate.change(handle_gui_event);
- overall_active.change(handle_gui_event);
-
- //block registry and checkboxes init
- $.getJSON('/blocks.json', function(data)
- {
- var container = $('#chart_designer_blocks');
- $.each(data.blocks, function(index, id)
- {
- registry.block_ids.push(id);
- var cb_id = "chart_designer_blocks " + id;
- var div = $('');
- var label = $('').text(id).attr({'for':cb_id});
- var input = $('').attr({
- type: 'checkbox',
- name: id,
- id: cb_id,
- });
- input.attr('checked', false);
- div.append(input);
- div.append(label);
- container.append(div);
- });
- //container.buttonset();
-
- //try to load last settings
- try{gras_chart_load(registry);}catch(e){}
-
- //init gui elements after settings restore
- overall_rate.val(registry.overall_rate);
- overall_active.attr('checked', registry.overall_active);
- handle_gui_event();
- gras_query_stats(registry);
- });
-}
diff --git a/python/gras/query/chart_global_counters.js b/python/gras/query/chart_global_counters.js
deleted file mode 100644
index 1708c01..0000000
--- a/python/gras/query/chart_global_counters.js
+++ /dev/null
@@ -1,58 +0,0 @@
-function GrasChartGlobalCounts(args, panel)
-{
- //input checking
- if (args.block_ids.length != 0) throw gras_error_dialog(
- "GrasChartGlobalCounts",
- "Error making global counts chart.\n"+
- "Do not specify any blocks for this chart."
- );
-
- //settings
- this.div = $('').attr({class:'chart_total_counts'});
- $(panel).append(this.div);
- this.title = "Global Counters"
-}
-
-GrasChartGlobalCounts.prototype.update = function(point)
-{
- var ul = $('');
- $('ul', this.div).remove(); //clear old lists
- this.div.append(ul);
-
- function make_entry(strong, span)
- {
- var li = $('');
- var strong = $('').text(strong + ": ");
- var span = $('').text(span);
- li.append(strong);
- li.append(span);
- ul.append(li);
- }
-
- var stuff = [
- ['Allocated', 'bytes', 'default_allocator_bytes_allocated'],
- ['Peak size', 'bytes', 'default_allocator_peak_bytes_allocated'],
- ['Num mallocs', '', 'default_allocator_allocation_count'],
-
- ['Total msgs', '', 'framework_counter_messages_processed'],
- ['Thread yields', '', 'framework_counter_yields'],
- ['Local pushes', '', 'framework_counter_local_pushes'],
- ['Shared pushes', '', 'framework_counter_shared_pushes'],
- ['Msg queue max', '', 'framework_counter_mailbox_queue_max'],
- ];
-
- var entries = 0;
- $.each(stuff, function(contents_i, contents)
- {
- var dir = contents[0];
- var units = contents[1];
- var key = contents[2];
- var count = (key in point)? point[key] : 0;
- if (count > 0)
- {
- make_entry(dir, count.toString() + ' ' + units);
- entries++;
- }
- });
- if (entries == 0) make_entry("Counts", "none");
-}
diff --git a/python/gras/query/chart_handler_breakdown.js b/python/gras/query/chart_handler_breakdown.js
deleted file mode 100644
index 5f76d1d..0000000
--- a/python/gras/query/chart_handler_breakdown.js
+++ /dev/null
@@ -1,39 +0,0 @@
-function GrasChartHandlerBreakdown(args, panel)
-{
- //input checking
- if (args.block_ids.length != 1) throw gras_error_dialog(
- "GrasChartHandlerBreakdown",
- "Error making handler breakdown chart.\n"+
- "Specify only one block for this chart."
- );
-
- //save enable
- this.block_id = args.block_ids[0];
-
- //make new chart
- this.chart = new google.visualization.PieChart(panel);
-
- this.title = "Handler Breakdown - " + this.block_id;
- this.default_width = GRAS_CHARTS_STD_WIDTH;
-}
-
-GrasChartHandlerBreakdown.prototype.update = function(point)
-{
- var percents = gras_extract_percent_times(point, this.block_id);
- var data = google.visualization.arrayToDataTable([
- ['Task', 'Percent'],
- ['Work prep', percents['prep']],
- ['Work task', percents['work']],
- ['Work post', percents['post']],
- ['Input tasks', percents['input']],
- ['Output tasks', percents['output']],
- ]);
-
- var options = {
- chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"},
- };
- if (this.gc_resize) options.width = 50;
- if (this.gc_resize) options.height = 50;
-
- this.chart.draw(data, options);
-};
diff --git a/python/gras/query/chart_overall_throughput.js b/python/gras/query/chart_overall_throughput.js
deleted file mode 100644
index 6d66e40..0000000
--- a/python/gras/query/chart_overall_throughput.js
+++ /dev/null
@@ -1,47 +0,0 @@
-function GrasChartOverallThroughput(args, panel)
-{
- //save enables
- this.ids = args.block_ids;
-
- //input checking
- if (this.ids.length == 0) throw gras_error_dialog(
- "GrasChartOverallThroughput",
- "Error making overall thoughput chart.\n"+
- "Specify at least 1 block for this chart."
- );
-
- //make new chart
- this.chart = new google.visualization.LineChart(panel);
-
- this.title = "Overall Throughput vs Time in MIps";
- this.history = new Array();
- this.default_width = 2*GRAS_CHARTS_STD_WIDTH;
-}
-
-GrasChartOverallThroughput.prototype.update = function(point)
-{
- this.history.push(point);
- if (this.history.length == 1) this.p0 = point;
- if (this.history.length < 2) return;
- if (this.history.length > 10) this.history.splice(0, 1);
-
- var data_set = [['Throughput'].concat(this.ids)];
- for (var i = 1; i < this.history.length; i++)
- {
- var row = new Array();
- row.push(gras_extract_stat_time_delta(this.p0, this.history[i]).toFixed(2).toString());
- for (var j = 0; j < this.ids.length; j++)
- {
- row.push(gras_extract_throughput_delta(this.history[i-1], this.history[i], this.ids[j])/1e6);
- }
- data_set.push(row);
- }
-
- var chart_data = google.visualization.arrayToDataTable(data_set);
- var options = {
- legend: {'position': 'bottom'},
- };
- if (this.gc_resize) options.width = 50;
- if (this.gc_resize) options.height = 50;
- this.chart.draw(chart_data, options);
-};
diff --git a/python/gras/query/chart_overhead_compare.js b/python/gras/query/chart_overhead_compare.js
deleted file mode 100644
index 0ec9070..0000000
--- a/python/gras/query/chart_overhead_compare.js
+++ /dev/null
@@ -1,39 +0,0 @@
-function GrasChartOverheadCompare(args, panel)
-{
- //save enables
- this.ids = args.block_ids;
-
- //input checking
- if (this.ids.length <= 1) throw gras_error_dialog(
- "GrasChartOverheadCompare",
- "Error making overhead compare chart.\n"+
- "Specify at least 2 blocks for this chart."
- );
-
- //make new chart
- this.chart = new google.visualization.PieChart(panel);
-
- this.title = "Overhead Comparison";
- this.default_width = GRAS_CHARTS_STD_WIDTH;
-}
-
-GrasChartOverheadCompare.prototype.update = function(point)
-{
- var data_set = new Array();
- 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']]);
- });
-
- var data = google.visualization.arrayToDataTable(data_set)
-
- var options = {
- chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"},
- };
- if (this.gc_resize) options.width = 50;
- if (this.gc_resize) options.height = 50;
-
- this.chart.draw(data, options);
-};
diff --git a/python/gras/query/chart_port_counters.js b/python/gras/query/chart_port_counters.js
deleted file mode 100644
index af74c33..0000000
--- a/python/gras/query/chart_port_counters.js
+++ /dev/null
@@ -1,76 +0,0 @@
-function GrasChartPortCounts(args, panel)
-{
- //input checking
- if (args.block_ids.length != 1) throw gras_error_dialog(
- "GrasChartPortCounts",
- "Error making total port counts chart.\n"+
- "Specify only one block for this chart."
- );
-
- //settings
- this.block_id = args.block_ids[0];
- this.div = $('').attr({class:'chart_total_counts'});
- $(panel).append(this.div);
- this.title = "Port Counters - " + this.block_id;
-}
-
-GrasChartPortCounts.prototype.update = function(point)
-{
- var block_data = point.blocks[this.block_id];
- if (!block_data) return;
- var ul = $('');
- $('ul', this.div).remove(); //clear old lists
- this.div.append(ul);
-
- function make_entry(strong, span)
- {
- var li = $('');
- var strong = $('').text(strong + ": ");
- var 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'],
- ['Output', 'items', 'items_produced'],
- ['Output', 'tags', 'tags_produced'],
- ['Output', 'msgs', 'msgs_produced'],
- ['Copied', 'bytes', 'bytes_copied'],
- ];
-
- $.each(stuff, function(contents_i, contents)
- {
- var dir = contents[0];
- var units = contents[1];
- var key = contents[2];
- $.each(block_data[key], function(index, count)
- {
- if (count > 0)
- {
- make_entry(dir + index.toString(), count.toString() + ' ' + units);
- }
- });
- });
-
- var actor_depth = block_data.actor_queue_depth;
- if (actor_depth > 10) //only show if its large
- {
- make_entry('Actor depth', actor_depth.toString() + ' msgs');
- }
-}
diff --git a/python/gras/query/chart_port_downtime.js b/python/gras/query/chart_port_downtime.js
deleted file mode 100644
index 2de421d..0000000
--- a/python/gras/query/chart_port_downtime.js
+++ /dev/null
@@ -1,47 +0,0 @@
-function GrasChartPortDowntime(args, panel)
-{
- //input checking
- if (args.block_ids.length != 1) throw gras_error_dialog(
- "GrasChartPortDowntime",
- "Error making port downtime chart.\n"+
- "Specify only one block for this chart."
- );
-
- //save enable
- this.block_id = args.block_ids[0];
-
- //make new chart
- this.chart = new google.visualization.PieChart(panel);
-
- this.title = "Port Downtime - " + this.block_id;
- this.default_width = GRAS_CHARTS_STD_WIDTH;
-}
-
-GrasChartPortDowntime.prototype.update = function(point)
-{
- var block_data = point.blocks[this.block_id];
- if (!block_data) return;
-
- var raw_data = new Array();
- raw_data.push(['Port', 'Percent']); //key
-
- //now add input and output port data
- $.each(block_data.inputs_idle, function(index, downtime)
- {
- raw_data.push(['Input'+index.toString(), downtime/block_data.tps]);
- });
- $.each(block_data.outputs_idle, function(index, downtime)
- {
- raw_data.push(['Output'+index.toString(), downtime/block_data.tps]);
- });
-
- //update the chart from raw data
- var data = google.visualization.arrayToDataTable(raw_data);
- var options = {
- chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"},
- };
- if (this.gc_resize) options.width = 50;
- if (this.gc_resize) options.height = 50;
-
- this.chart.draw(data, options);
-};
diff --git a/python/gras/query/main.css b/python/gras/query/main.css
deleted file mode 100644
index 4d933fa..0000000
--- a/python/gras/query/main.css
+++ /dev/null
@@ -1,167 +0,0 @@
-*{
-margin:0px;
-padding:0px;
-}
-
-body{
-font-family:Arial, Helvetica, sans-serif;
-font-size:9pt;
-color:black;
-background-color:white;
-}
-
-.chart_designer_block_close
-{
-float:right;
-}
-
-#chart_designer_blocks div
-{
-float:left;
-}
-
-#chart_designer_blocks label
-{
-text-decoration:underline;
-}
-
-#chart_designer_blocks input
-{
-margin-right:2px;
-margin-left:10px;
-}
-
-#charts_panel
-{
-width:100%;
-height:100%;
-}
-
-.chart_total_counts li
-{
-list-style-type:none;
-text-align: left;
-padding: 0px;
-margin-left: -30px;
-font-size:90%;
-}
-
-.chart_container
-{
-float:none;
-}
-
-#page{
-padding:10px;
-color:inherit;
-background-color:inherit;
-}
-
-#page h1{
-font-size:130%;
-border-left:1px solid #333333;
-border-bottom:1px solid #333333;
-text-align:left;
-padding:10px 0px 10px 10px;
-margin:10px 5px 20px 5px;
-color:#333333;
-background-color:inherit;
-}
-
-#page h2{
-font-size:130%;
-text-align:center;
-padding:20px 0px 10px 0px;
-color:#333333;
-background-color:inherit;
-}
-
-#page h3{
-font-size:110%;
-text-align:left;
-padding:15px 0px 5px 10px;
-text-decoration:underline;
-color:#333333;
-background-color:inherit;
-}
-
-#page h4{
-font-size:105%;
-text-align:center;
-padding:5px 0px 3px 0px;
-text-decoration:underline;
-}
-
-#page p{
-text-indent:20px;
-padding:5px 0px 5px 10px;
-}
-
-#page strong{
-}
-
-#page em{
-}
-
-#page li{
-padding:5px 5px 0px 3px;
-}
-
-#page ul, #page ol{
-padding:5px 0px 5px 40px;
-}
-
-#page img{
-margin:10px auto 10px auto;
-display:block;
-border-style:none;
-}
-
-#page a:link, #page a:visited{
-color:#236B8E;
-background-color:inherit;
-text-decoration:none;
-}
-
-#page a:hover{
-color:#4985D6;
-background-color:inherit;
-text-decoration:none;
-}
-
-#page pre{
-border:1px inset #333333;
-padding:5px;
-margin:10px 5px 10px 5px;
-color:inherit;
-background-color:#FCFCFC;
-font-size:90%;
-}
-
-#page hr{
-margin:10px 0px 0px 0px;
-}
-
-#page table{
-padding:5px;
-}
-
-#page th{
-padding:3px;
-border:1px solid #333333;
-text-align:center;
-color:inherit;
-background-color:#ECECEC;
-}
-
-#page tr{
-}
-
-#page td{
-padding:3px;
-border:1px solid #333333;
-text-align:center;
-color:inherit;
-background-color:#FCFCFC;
-}
-
diff --git a/python/gras/query/main.html b/python/gras/query/main.html
deleted file mode 100644
index 3fc3508..0000000
--- a/python/gras/query/main.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
- GRAS Query Client
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/python/gras/query/main.js b/python/gras/query/main.js
deleted file mode 100644
index b17af63..0000000
--- a/python/gras/query/main.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/***********************************************************************
- * Stats registry data structure
- **********************************************************************/
-var GrasStatsRegistry = function()
-{
- this.overall_rate = 3.0;
- this.overall_active = true;
- this.block_ids = new Array();
- this.top_id = 'top';
- this.online = true;
- this.offline_count = 0;
-}
-
-/***********************************************************************
- * 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)
-{
- $.ajax({
- type: "GET",
- 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_handle_offline(registry);
- if (registry.overall_active) gras_chart_factory_update(registry, response);
-
- var timeout = registry.overall_active? Math.round(1000/registry.overall_rate) : 1000;
- window.setTimeout(function()
- {
- gras_query_stats(registry);
- }, timeout);
- },
- error: function()
- {
- registry.online = false;
- gras_handle_offline(registry);
- window.setTimeout(function()
- {
- gras_query_stats(registry);
- }, 1000);
- },
- });
-}
-
-/***********************************************************************
- * Init
- **********************************************************************/
-var gras_stats_main = function()
-{
- //create a new registry - storage for gui state
- var registry = new GrasStatsRegistry();
-
- //query various server args
- $.getJSON('/args.json', function(data)
- {
- registry.top_id = data.name;
- $('#top_name').append(' - ' + registry.top_id);
- document.title += ' - ' + registry.top_id;
- });
-
- //initialize the charts factory
- gras_chart_factory_init(registry);
-}
diff --git a/python/gras/query/utils.js b/python/gras/query/utils.js
deleted file mode 100644
index 3e4fe4b..0000000
--- a/python/gras/query/utils.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/***********************************************************************
- * Utility functions for stats
- **********************************************************************/
-var gras_extract_total_items = function(point, id)
-{
- var block_data = point.blocks[id];
- var total_items = 0;
- $.each(block_data.items_produced, function(index, value)
- {
- total_items += value;
- });
- $.each(block_data.items_consumed, function(index, value)
- {
- total_items += value;
- });
- return total_items;
-}
-
-var gras_extract_throughput_delta = function(p0, p1, id)
-{
- var d0 = p0.blocks[id];
- var d1 = p1.blocks[id];
- var t0 = d0.stats_time;
- var t1 = d1.stats_time;
- var tps = d0.tps;
- var items0 = gras_extract_total_items(p0, id);
- var items1 = gras_extract_total_items(p1, id);
- return ((items1-items0)*tps)/(t1-t0);
-}
-
-var gras_extract_throughput = function(point, id)
-{
- var block_data = point.blocks[id];
- var start_time = block_data.start_time;
- var stats_time = block_data.stats_time;
- var tps = block_data.tps;
- var total_items = gras_extract_total_items(point, id);
- return (total_items*tps)/(stats_time-start_time);
-}
-
-var gras_extract_stat_time_delta = function(p0, p1)
-{
- var t0 = p0.now;
- var t1 = p1.now;
- var tps = p0.tps;
- return (t1-t0)/(tps);
-}
-
-var gras_extract_percent_times = function(point, id)
-{
- var block_data = point.blocks[id];
- var data = {
- prep: block_data.total_time_prep,
- work: block_data.total_time_work,
- post: block_data.total_time_post,
- input: block_data.total_time_input,
- output: block_data.total_time_output,
- };
- var total = 0;
- $.each(data, function(key, val)
- {
- total += val;
- });
- data['total'] = total;
- return data;
-}
-
-var gras_animate_show_hide = function(elem, show)
-{
- if (show) elem.slideDown("fast");
- else elem.slideUp("fast");
-}
-
-var gras_error_dialog = function(error_title, error_text)
-{
- $("#div-dialog-warning").text(error_text);
- $("#div-dialog-warning").dialog({
- title: error_title,
- resizable: false,
- height: 160,
- modal: true,
- buttons: {
- "Ok" : function () {
- $(this).dialog("close");
- }
- }
- }).parent().addClass("ui-state-error");
-}
diff --git a/query/CMakeLists.txt b/query/CMakeLists.txt
new file mode 100644
index 0000000..f9a855e
--- /dev/null
+++ b/query/CMakeLists.txt
@@ -0,0 +1,28 @@
+########################################################################
+# Install rules
+########################################################################
+include(GrPython)
+
+GR_PYTHON_INSTALL(
+ FILES
+ __init__.py
+ DESTINATION ${GR_PYTHON_DIR}/gras/query
+ COMPONENT ${GRAS_COMP_PYTHON}
+)
+
+INSTALL(
+ FILES
+ main.html
+ main.js
+ utils.js
+ chart_factory.js
+ chart_overhead_compare.js
+ chart_overall_throughput.js
+ chart_handler_breakdown.js
+ chart_port_counters.js
+ chart_global_counters.js
+ chart_port_downtime.js
+ main.css
+ DESTINATION ${GR_PYTHON_DIR}/gras/query
+ COMPONENT ${GRAS_COMP_PYTHON}
+)
diff --git a/query/__init__.py b/query/__init__.py
new file mode 100644
index 0000000..c72222b
--- /dev/null
+++ b/query/__init__.py
@@ -0,0 +1,81 @@
+import time
+import BaseHTTPServer
+import urlparse
+import json
+import os
+
+__path__ = os.path.abspath(os.path.dirname(__file__))
+
+server_registry = dict()
+
+class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+
+ #hide log messages to stdout by default
+ def log_message(self, format, *args): pass
+
+ def do_HEAD(s):
+ s.send_response(200)
+ s.send_header("Content-type", "text/html")
+ s.end_headers()
+
+ 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 = 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':
+ 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))
+ 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")
+ elif target.endswith('.css'): s.send_header("Content-type", "text/css")
+ 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")
+ s.end_headers()
+ s.wfile.write("not found
")
+
+import select
+
+class http_server(object):
+ def __init__(self, args, **kwargs):
+ server_class = BaseHTTPServer.HTTPServer
+ self._httpd = server_class(args, MyHandler)
+ server_registry[self._httpd] = kwargs
+
+ def serve_forever(self):
+ while True:
+ try: self._httpd.serve_forever()
+ except select.error: pass
diff --git a/query/chart_factory.js b/query/chart_factory.js
new file mode 100644
index 0000000..8b9656a
--- /dev/null
+++ b/query/chart_factory.js
@@ -0,0 +1,281 @@
+/***********************************************************************
+ * Some constants
+ **********************************************************************/
+var GRAS_CHARTS_STD_WIDTH = 250;
+
+/***********************************************************************
+ * Chart registry for now chart types
+ **********************************************************************/
+var gras_chart_get_registry = function()
+{
+ return [
+ {key:'overhead_compare', name:'Overhead Compare', factory:GrasChartOverheadCompare},
+ {key:'overall_throughput', name:'Overall Throughput', factory:GrasChartOverallThroughput},
+ {key:'handler_breakdown', name:'Handler Breakdown', factory:GrasChartHandlerBreakdown},
+ {key:'port_counters', name:'Port Counters', factory:GrasChartPortCounts},
+ {key:'global_counters', name:'Global Counters', factory:GrasChartGlobalCounts},
+ {key:'port_downtime', name:'Port downtime', factory:GrasChartPortDowntime},
+ ];
+}
+
+/***********************************************************************
+ * get blocks that need active querying
+ **********************************************************************/
+function gras_chart_factory_active_blocks(registry)
+{
+ var block_ids = new Array();
+ $.each(registry.active_charts, function(index, chart_info)
+ {
+ $.merge(block_ids, chart_info.args.block_ids);
+ });
+ return $.unique(block_ids);
+}
+
+/***********************************************************************
+ * update after new query event
+ **********************************************************************/
+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);
+ });
+}
+
+/***********************************************************************
+ * chart factory input handler
+ **********************************************************************/
+function gras_chart_factory_handle_input(registry)
+{
+ //get a list of the selected blocks
+ var selected_blocks = new Array();
+ $.each($('#chart_designer_blocks input'), function(index, input)
+ {
+ var input = $(input);
+ if (input.is(':checked'))
+ {
+ selected_blocks.push(input.attr('name'));
+ }
+ });
+
+ //get the type of chart to create
+ var chart_type = $('#chart_type_selector').val();
+
+ //create args for the factory make
+ var args = {
+ block_ids:selected_blocks,
+ chart_type:chart_type,
+ };
+
+ //call into the factory with args
+ gras_chart_factory_make(registry, args);
+}
+
+/***********************************************************************
+ * save/load to/from local storage
+ **********************************************************************/
+function gras_chart_save(registry)
+{
+ if (typeof(Storage) === "undefined") return;
+ var all_args = new Array();
+ $.each(registry.active_charts, function(index, info)
+ {
+ all_args.push(info.args);
+ });
+ localStorage.setItem(registry.top_id, JSON.stringify({
+ chart_args: all_args,
+ overall_rate: registry.overall_rate,
+ overall_active: registry.overall_active,
+ }));
+}
+
+function gras_chart_load(registry)
+{
+ if (typeof(Storage) === "undefined") return;
+ var storage = JSON.parse(localStorage.getItem(registry.top_id));
+ if (!storage) return;
+
+ //restore misc settings in storage
+ registry.overall_rate = storage.overall_rate;
+ registry.overall_active = storage.overall_active;
+
+ //rebuild all charts from args
+ $.each(storage.chart_args, function(args_i, args)
+ {
+ //check that the blocks saved in the args actually exist
+ var do_make = true;
+ $.each(args.block_ids, function(block_id_i, block_id)
+ {
+ if ($.inArray(block_id, registry.block_ids) < 0)
+ {
+ do_make = false;
+ }
+ });
+ if (do_make) gras_chart_factory_make(registry, args);
+ });
+}
+
+/***********************************************************************
+ * chart factory make routine
+ **********************************************************************/
+function gras_chart_factory_make(registry, args)
+{
+ //create containers
+ var chart_box = $('').attr({class:'chart_container'});
+ var tr = $('
');
+ var td = $(' | ');
+ tr.append(td);
+
+ //call into the factory
+ try
+ {
+ var chart = new registry.chart_factories[args.chart_type](args, td.get(0));
+ }
+ catch(err)
+ {
+ return;
+ }
+
+ //setup the title
+ var tr_title = $('
');
+ var th_title = $(' | ');
+ tr_title.append(th_title);
+ th_title.text(chart.title);
+
+ //register the chart
+ var chart_info = {chart:chart,args:args,panel:chart_box};
+ registry.active_charts.push(chart_info);
+ $('#charts_panel').append(chart_box);
+
+ //close button
+ var close_div = $('').attr({class:'chart_designer_block_close'});
+ var close_href = $('').attr({href:'#', class:"ui-dialog-titlebar-close ui-corner-all", role:"button"});
+ var close_span = $('').attr({class:"ui-icon ui-icon-closethick"}).text('close');
+ close_div.append(close_href);
+ close_href.append(close_span);
+ th_title.append(close_div);
+ $(close_href).click(function()
+ {
+ var index = $.inArray(chart_info, registry.active_charts);
+ registry.active_charts.splice(index, 1);
+ chart_box.remove();
+ gras_chart_save(registry);
+ });
+ gras_chart_save(registry);
+
+ //finish gui building
+ chart_box.append(tr_title);
+ chart_box.append(tr);
+
+ //implement draggable and resizable from jquery ui
+ var handle_stop = function(event, ui)
+ {
+ args['width'] = chart_box.width();
+ args['height'] = chart_box.height();
+ args['position'] = chart_box.offset();
+ chart.gc_resize = false;
+ chart.update(registry.point);
+ gras_chart_save(registry);
+ };
+
+ if ('default_width' in chart) chart_box.width(chart.default_width);
+ chart_box.resizable({stop: handle_stop, create: function(event, ui)
+ {
+ if ('width' in args) chart_box.width(args.width);
+ if ('height' in args) chart_box.height(args.height);
+ },
+ start: function(event, ui)
+ {
+ chart.gc_resize = true;
+ chart.update(registry.point);
+ }});
+
+ chart_box.css('position', 'absolute');
+ chart_box.draggable({stop: handle_stop, create: function(event, ui)
+ {
+ if ('position' in args) chart_box.offset(args.position);
+ }, cursor: "move"});
+
+ //set the cursor on the title bar so its obvious
+ tr_title.hover(
+ function(){$(this).css('cursor','move'); close_div.show();},
+ function(){$(this).css('cursor','auto'); close_div.hide();}
+ );
+ close_div.hide();
+}
+
+/***********************************************************************
+ * chart factory init
+ **********************************************************************/
+function gras_chart_factory_init(registry)
+{
+ //init registry containers
+ registry.active_charts = new Array();
+ registry.chart_factories = new Array();
+
+ //install callback for chart factory
+ $('#chart_factory_button').click(function()
+ {
+ gras_chart_factory_handle_input(registry);
+ });
+
+ //init the chart selection input
+ $.each(gras_chart_get_registry(), function(index, options)
+ {
+ registry.chart_factories[options.key] = options.factory;
+ var option = $('').attr({value: options.key});
+ option.text(options.name);
+ $('#chart_type_selector').append(option);
+ });
+
+ //init chart overall gui controls
+ var overall_rate = $('#chart_update_rate').attr({size:3});
+ overall_rate.spinner({
+ min: 1, max: 10, step: 0.5, stop: function(event, ui){$(this).change();}
+ });
+ var overall_active = $('#chart_active_state');
+ overall_active.button();
+
+ //callback for overall gui events
+ function handle_gui_event()
+ {
+ registry.overall_active = overall_active.is(':checked');
+ registry.overall_rate = overall_rate.val();
+ gras_chart_save(registry);
+ }
+ overall_rate.change(handle_gui_event);
+ overall_active.change(handle_gui_event);
+
+ //block registry and checkboxes init
+ $.getJSON('/blocks.json', function(data)
+ {
+ var container = $('#chart_designer_blocks');
+ $.each(data.blocks, function(index, id)
+ {
+ registry.block_ids.push(id);
+ var cb_id = "chart_designer_blocks " + id;
+ var div = $('');
+ var label = $('').text(id).attr({'for':cb_id});
+ var input = $('').attr({
+ type: 'checkbox',
+ name: id,
+ id: cb_id,
+ });
+ input.attr('checked', false);
+ div.append(input);
+ div.append(label);
+ container.append(div);
+ });
+ //container.buttonset();
+
+ //try to load last settings
+ try{gras_chart_load(registry);}catch(e){}
+
+ //init gui elements after settings restore
+ overall_rate.val(registry.overall_rate);
+ overall_active.attr('checked', registry.overall_active);
+ handle_gui_event();
+ gras_query_stats(registry);
+ });
+}
diff --git a/query/chart_global_counters.js b/query/chart_global_counters.js
new file mode 100644
index 0000000..1708c01
--- /dev/null
+++ b/query/chart_global_counters.js
@@ -0,0 +1,58 @@
+function GrasChartGlobalCounts(args, panel)
+{
+ //input checking
+ if (args.block_ids.length != 0) throw gras_error_dialog(
+ "GrasChartGlobalCounts",
+ "Error making global counts chart.\n"+
+ "Do not specify any blocks for this chart."
+ );
+
+ //settings
+ this.div = $('').attr({class:'chart_total_counts'});
+ $(panel).append(this.div);
+ this.title = "Global Counters"
+}
+
+GrasChartGlobalCounts.prototype.update = function(point)
+{
+ var ul = $('');
+ $('ul', this.div).remove(); //clear old lists
+ this.div.append(ul);
+
+ function make_entry(strong, span)
+ {
+ var li = $('');
+ var strong = $('').text(strong + ": ");
+ var span = $('').text(span);
+ li.append(strong);
+ li.append(span);
+ ul.append(li);
+ }
+
+ var stuff = [
+ ['Allocated', 'bytes', 'default_allocator_bytes_allocated'],
+ ['Peak size', 'bytes', 'default_allocator_peak_bytes_allocated'],
+ ['Num mallocs', '', 'default_allocator_allocation_count'],
+
+ ['Total msgs', '', 'framework_counter_messages_processed'],
+ ['Thread yields', '', 'framework_counter_yields'],
+ ['Local pushes', '', 'framework_counter_local_pushes'],
+ ['Shared pushes', '', 'framework_counter_shared_pushes'],
+ ['Msg queue max', '', 'framework_counter_mailbox_queue_max'],
+ ];
+
+ var entries = 0;
+ $.each(stuff, function(contents_i, contents)
+ {
+ var dir = contents[0];
+ var units = contents[1];
+ var key = contents[2];
+ var count = (key in point)? point[key] : 0;
+ if (count > 0)
+ {
+ make_entry(dir, count.toString() + ' ' + units);
+ entries++;
+ }
+ });
+ if (entries == 0) make_entry("Counts", "none");
+}
diff --git a/query/chart_handler_breakdown.js b/query/chart_handler_breakdown.js
new file mode 100644
index 0000000..5f76d1d
--- /dev/null
+++ b/query/chart_handler_breakdown.js
@@ -0,0 +1,39 @@
+function GrasChartHandlerBreakdown(args, panel)
+{
+ //input checking
+ if (args.block_ids.length != 1) throw gras_error_dialog(
+ "GrasChartHandlerBreakdown",
+ "Error making handler breakdown chart.\n"+
+ "Specify only one block for this chart."
+ );
+
+ //save enable
+ this.block_id = args.block_ids[0];
+
+ //make new chart
+ this.chart = new google.visualization.PieChart(panel);
+
+ this.title = "Handler Breakdown - " + this.block_id;
+ this.default_width = GRAS_CHARTS_STD_WIDTH;
+}
+
+GrasChartHandlerBreakdown.prototype.update = function(point)
+{
+ var percents = gras_extract_percent_times(point, this.block_id);
+ var data = google.visualization.arrayToDataTable([
+ ['Task', 'Percent'],
+ ['Work prep', percents['prep']],
+ ['Work task', percents['work']],
+ ['Work post', percents['post']],
+ ['Input tasks', percents['input']],
+ ['Output tasks', percents['output']],
+ ]);
+
+ var options = {
+ chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"},
+ };
+ if (this.gc_resize) options.width = 50;
+ if (this.gc_resize) options.height = 50;
+
+ this.chart.draw(data, options);
+};
diff --git a/query/chart_overall_throughput.js b/query/chart_overall_throughput.js
new file mode 100644
index 0000000..6d66e40
--- /dev/null
+++ b/query/chart_overall_throughput.js
@@ -0,0 +1,47 @@
+function GrasChartOverallThroughput(args, panel)
+{
+ //save enables
+ this.ids = args.block_ids;
+
+ //input checking
+ if (this.ids.length == 0) throw gras_error_dialog(
+ "GrasChartOverallThroughput",
+ "Error making overall thoughput chart.\n"+
+ "Specify at least 1 block for this chart."
+ );
+
+ //make new chart
+ this.chart = new google.visualization.LineChart(panel);
+
+ this.title = "Overall Throughput vs Time in MIps";
+ this.history = new Array();
+ this.default_width = 2*GRAS_CHARTS_STD_WIDTH;
+}
+
+GrasChartOverallThroughput.prototype.update = function(point)
+{
+ this.history.push(point);
+ if (this.history.length == 1) this.p0 = point;
+ if (this.history.length < 2) return;
+ if (this.history.length > 10) this.history.splice(0, 1);
+
+ var data_set = [['Throughput'].concat(this.ids)];
+ for (var i = 1; i < this.history.length; i++)
+ {
+ var row = new Array();
+ row.push(gras_extract_stat_time_delta(this.p0, this.history[i]).toFixed(2).toString());
+ for (var j = 0; j < this.ids.length; j++)
+ {
+ row.push(gras_extract_throughput_delta(this.history[i-1], this.history[i], this.ids[j])/1e6);
+ }
+ data_set.push(row);
+ }
+
+ var chart_data = google.visualization.arrayToDataTable(data_set);
+ var options = {
+ legend: {'position': 'bottom'},
+ };
+ if (this.gc_resize) options.width = 50;
+ if (this.gc_resize) options.height = 50;
+ this.chart.draw(chart_data, options);
+};
diff --git a/query/chart_overhead_compare.js b/query/chart_overhead_compare.js
new file mode 100644
index 0000000..0ec9070
--- /dev/null
+++ b/query/chart_overhead_compare.js
@@ -0,0 +1,39 @@
+function GrasChartOverheadCompare(args, panel)
+{
+ //save enables
+ this.ids = args.block_ids;
+
+ //input checking
+ if (this.ids.length <= 1) throw gras_error_dialog(
+ "GrasChartOverheadCompare",
+ "Error making overhead compare chart.\n"+
+ "Specify at least 2 blocks for this chart."
+ );
+
+ //make new chart
+ this.chart = new google.visualization.PieChart(panel);
+
+ this.title = "Overhead Comparison";
+ this.default_width = GRAS_CHARTS_STD_WIDTH;
+}
+
+GrasChartOverheadCompare.prototype.update = function(point)
+{
+ var data_set = new Array();
+ 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']]);
+ });
+
+ var data = google.visualization.arrayToDataTable(data_set)
+
+ var options = {
+ chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"},
+ };
+ if (this.gc_resize) options.width = 50;
+ if (this.gc_resize) options.height = 50;
+
+ this.chart.draw(data, options);
+};
diff --git a/query/chart_port_counters.js b/query/chart_port_counters.js
new file mode 100644
index 0000000..af74c33
--- /dev/null
+++ b/query/chart_port_counters.js
@@ -0,0 +1,76 @@
+function GrasChartPortCounts(args, panel)
+{
+ //input checking
+ if (args.block_ids.length != 1) throw gras_error_dialog(
+ "GrasChartPortCounts",
+ "Error making total port counts chart.\n"+
+ "Specify only one block for this chart."
+ );
+
+ //settings
+ this.block_id = args.block_ids[0];
+ this.div = $('').attr({class:'chart_total_counts'});
+ $(panel).append(this.div);
+ this.title = "Port Counters - " + this.block_id;
+}
+
+GrasChartPortCounts.prototype.update = function(point)
+{
+ var block_data = point.blocks[this.block_id];
+ if (!block_data) return;
+ var ul = $('');
+ $('ul', this.div).remove(); //clear old lists
+ this.div.append(ul);
+
+ function make_entry(strong, span)
+ {
+ var li = $('');
+ var strong = $('').text(strong + ": ");
+ var 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'],
+ ['Output', 'items', 'items_produced'],
+ ['Output', 'tags', 'tags_produced'],
+ ['Output', 'msgs', 'msgs_produced'],
+ ['Copied', 'bytes', 'bytes_copied'],
+ ];
+
+ $.each(stuff, function(contents_i, contents)
+ {
+ var dir = contents[0];
+ var units = contents[1];
+ var key = contents[2];
+ $.each(block_data[key], function(index, count)
+ {
+ if (count > 0)
+ {
+ make_entry(dir + index.toString(), count.toString() + ' ' + units);
+ }
+ });
+ });
+
+ var actor_depth = block_data.actor_queue_depth;
+ if (actor_depth > 10) //only show if its large
+ {
+ make_entry('Actor depth', actor_depth.toString() + ' msgs');
+ }
+}
diff --git a/query/chart_port_downtime.js b/query/chart_port_downtime.js
new file mode 100644
index 0000000..2de421d
--- /dev/null
+++ b/query/chart_port_downtime.js
@@ -0,0 +1,47 @@
+function GrasChartPortDowntime(args, panel)
+{
+ //input checking
+ if (args.block_ids.length != 1) throw gras_error_dialog(
+ "GrasChartPortDowntime",
+ "Error making port downtime chart.\n"+
+ "Specify only one block for this chart."
+ );
+
+ //save enable
+ this.block_id = args.block_ids[0];
+
+ //make new chart
+ this.chart = new google.visualization.PieChart(panel);
+
+ this.title = "Port Downtime - " + this.block_id;
+ this.default_width = GRAS_CHARTS_STD_WIDTH;
+}
+
+GrasChartPortDowntime.prototype.update = function(point)
+{
+ var block_data = point.blocks[this.block_id];
+ if (!block_data) return;
+
+ var raw_data = new Array();
+ raw_data.push(['Port', 'Percent']); //key
+
+ //now add input and output port data
+ $.each(block_data.inputs_idle, function(index, downtime)
+ {
+ raw_data.push(['Input'+index.toString(), downtime/block_data.tps]);
+ });
+ $.each(block_data.outputs_idle, function(index, downtime)
+ {
+ raw_data.push(['Output'+index.toString(), downtime/block_data.tps]);
+ });
+
+ //update the chart from raw data
+ var data = google.visualization.arrayToDataTable(raw_data);
+ var options = {
+ chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"},
+ };
+ if (this.gc_resize) options.width = 50;
+ if (this.gc_resize) options.height = 50;
+
+ this.chart.draw(data, options);
+};
diff --git a/query/main.css b/query/main.css
new file mode 100644
index 0000000..4d933fa
--- /dev/null
+++ b/query/main.css
@@ -0,0 +1,167 @@
+*{
+margin:0px;
+padding:0px;
+}
+
+body{
+font-family:Arial, Helvetica, sans-serif;
+font-size:9pt;
+color:black;
+background-color:white;
+}
+
+.chart_designer_block_close
+{
+float:right;
+}
+
+#chart_designer_blocks div
+{
+float:left;
+}
+
+#chart_designer_blocks label
+{
+text-decoration:underline;
+}
+
+#chart_designer_blocks input
+{
+margin-right:2px;
+margin-left:10px;
+}
+
+#charts_panel
+{
+width:100%;
+height:100%;
+}
+
+.chart_total_counts li
+{
+list-style-type:none;
+text-align: left;
+padding: 0px;
+margin-left: -30px;
+font-size:90%;
+}
+
+.chart_container
+{
+float:none;
+}
+
+#page{
+padding:10px;
+color:inherit;
+background-color:inherit;
+}
+
+#page h1{
+font-size:130%;
+border-left:1px solid #333333;
+border-bottom:1px solid #333333;
+text-align:left;
+padding:10px 0px 10px 10px;
+margin:10px 5px 20px 5px;
+color:#333333;
+background-color:inherit;
+}
+
+#page h2{
+font-size:130%;
+text-align:center;
+padding:20px 0px 10px 0px;
+color:#333333;
+background-color:inherit;
+}
+
+#page h3{
+font-size:110%;
+text-align:left;
+padding:15px 0px 5px 10px;
+text-decoration:underline;
+color:#333333;
+background-color:inherit;
+}
+
+#page h4{
+font-size:105%;
+text-align:center;
+padding:5px 0px 3px 0px;
+text-decoration:underline;
+}
+
+#page p{
+text-indent:20px;
+padding:5px 0px 5px 10px;
+}
+
+#page strong{
+}
+
+#page em{
+}
+
+#page li{
+padding:5px 5px 0px 3px;
+}
+
+#page ul, #page ol{
+padding:5px 0px 5px 40px;
+}
+
+#page img{
+margin:10px auto 10px auto;
+display:block;
+border-style:none;
+}
+
+#page a:link, #page a:visited{
+color:#236B8E;
+background-color:inherit;
+text-decoration:none;
+}
+
+#page a:hover{
+color:#4985D6;
+background-color:inherit;
+text-decoration:none;
+}
+
+#page pre{
+border:1px inset #333333;
+padding:5px;
+margin:10px 5px 10px 5px;
+color:inherit;
+background-color:#FCFCFC;
+font-size:90%;
+}
+
+#page hr{
+margin:10px 0px 0px 0px;
+}
+
+#page table{
+padding:5px;
+}
+
+#page th{
+padding:3px;
+border:1px solid #333333;
+text-align:center;
+color:inherit;
+background-color:#ECECEC;
+}
+
+#page tr{
+}
+
+#page td{
+padding:3px;
+border:1px solid #333333;
+text-align:center;
+color:inherit;
+background-color:#FCFCFC;
+}
+
diff --git a/query/main.html b/query/main.html
new file mode 100644
index 0000000..3fc3508
--- /dev/null
+++ b/query/main.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+ GRAS Query Client
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/query/main.js b/query/main.js
new file mode 100644
index 0000000..b17af63
--- /dev/null
+++ b/query/main.js
@@ -0,0 +1,79 @@
+/***********************************************************************
+ * Stats registry data structure
+ **********************************************************************/
+var GrasStatsRegistry = function()
+{
+ this.overall_rate = 3.0;
+ this.overall_active = true;
+ this.block_ids = new Array();
+ this.top_id = 'top';
+ this.online = true;
+ this.offline_count = 0;
+}
+
+/***********************************************************************
+ * 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)
+{
+ $.ajax({
+ type: "GET",
+ 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_handle_offline(registry);
+ if (registry.overall_active) gras_chart_factory_update(registry, response);
+
+ var timeout = registry.overall_active? Math.round(1000/registry.overall_rate) : 1000;
+ window.setTimeout(function()
+ {
+ gras_query_stats(registry);
+ }, timeout);
+ },
+ error: function()
+ {
+ registry.online = false;
+ gras_handle_offline(registry);
+ window.setTimeout(function()
+ {
+ gras_query_stats(registry);
+ }, 1000);
+ },
+ });
+}
+
+/***********************************************************************
+ * Init
+ **********************************************************************/
+var gras_stats_main = function()
+{
+ //create a new registry - storage for gui state
+ var registry = new GrasStatsRegistry();
+
+ //query various server args
+ $.getJSON('/args.json', function(data)
+ {
+ registry.top_id = data.name;
+ $('#top_name').append(' - ' + registry.top_id);
+ document.title += ' - ' + registry.top_id;
+ });
+
+ //initialize the charts factory
+ gras_chart_factory_init(registry);
+}
diff --git a/query/utils.js b/query/utils.js
new file mode 100644
index 0000000..3e4fe4b
--- /dev/null
+++ b/query/utils.js
@@ -0,0 +1,88 @@
+/***********************************************************************
+ * Utility functions for stats
+ **********************************************************************/
+var gras_extract_total_items = function(point, id)
+{
+ var block_data = point.blocks[id];
+ var total_items = 0;
+ $.each(block_data.items_produced, function(index, value)
+ {
+ total_items += value;
+ });
+ $.each(block_data.items_consumed, function(index, value)
+ {
+ total_items += value;
+ });
+ return total_items;
+}
+
+var gras_extract_throughput_delta = function(p0, p1, id)
+{
+ var d0 = p0.blocks[id];
+ var d1 = p1.blocks[id];
+ var t0 = d0.stats_time;
+ var t1 = d1.stats_time;
+ var tps = d0.tps;
+ var items0 = gras_extract_total_items(p0, id);
+ var items1 = gras_extract_total_items(p1, id);
+ return ((items1-items0)*tps)/(t1-t0);
+}
+
+var gras_extract_throughput = function(point, id)
+{
+ var block_data = point.blocks[id];
+ var start_time = block_data.start_time;
+ var stats_time = block_data.stats_time;
+ var tps = block_data.tps;
+ var total_items = gras_extract_total_items(point, id);
+ return (total_items*tps)/(stats_time-start_time);
+}
+
+var gras_extract_stat_time_delta = function(p0, p1)
+{
+ var t0 = p0.now;
+ var t1 = p1.now;
+ var tps = p0.tps;
+ return (t1-t0)/(tps);
+}
+
+var gras_extract_percent_times = function(point, id)
+{
+ var block_data = point.blocks[id];
+ var data = {
+ prep: block_data.total_time_prep,
+ work: block_data.total_time_work,
+ post: block_data.total_time_post,
+ input: block_data.total_time_input,
+ output: block_data.total_time_output,
+ };
+ var total = 0;
+ $.each(data, function(key, val)
+ {
+ total += val;
+ });
+ data['total'] = total;
+ return data;
+}
+
+var gras_animate_show_hide = function(elem, show)
+{
+ if (show) elem.slideDown("fast");
+ else elem.slideUp("fast");
+}
+
+var gras_error_dialog = function(error_title, error_text)
+{
+ $("#div-dialog-warning").text(error_text);
+ $("#div-dialog-warning").dialog({
+ title: error_title,
+ resizable: false,
+ height: 160,
+ modal: true,
+ buttons: {
+ "Ok" : function () {
+ $(this).dialog("close");
+ }
+ }
+ }).parent().addClass("ui-state-error");
+}
--
cgit