From 38b24b7ef6e3d82c1a14b93c4ffafadbc2f1ae9b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 26 Mar 2013 00:41:12 -0500 Subject: gras: rename stats to query --- grextras | 2 +- include/gras/top_block.hpp | 7 +- lib/CMakeLists.txt | 2 +- lib/top_block_query.cpp | 85 +++++++++++ lib/top_block_stats.cpp | 85 ----------- python/gras/CMakeLists.txt | 2 +- python/gras/GRAS_HierBlock.i | 4 +- python/gras/query/CMakeLists.txt | 26 ++++ python/gras/query/__init__.py | 52 +++++++ python/gras/query/chart_factory.js | 209 ++++++++++++++++++++++++++ python/gras/query/chart_handler_breakdown.js | 37 +++++ python/gras/query/chart_overall_throughput.js | 46 ++++++ python/gras/query/chart_overhead_compare.js | 37 +++++ python/gras/query/chart_total_io_counts.js | 62 ++++++++ python/gras/query/main.css | 161 ++++++++++++++++++++ python/gras/query/main.html | 49 ++++++ python/gras/query/main.js | 76 ++++++++++ python/gras/query/utils.js | 84 +++++++++++ python/gras/stats/CMakeLists.txt | 26 ---- python/gras/stats/__init__.py | 52 ------- python/gras/stats/chart_factory.js | 209 -------------------------- python/gras/stats/chart_handler_breakdown.js | 37 ----- python/gras/stats/chart_overall_throughput.js | 46 ------ python/gras/stats/chart_overhead_compare.js | 37 ----- python/gras/stats/chart_total_io_counts.js | 62 -------- python/gras/stats/main.css | 161 -------------------- python/gras/stats/main.html | 49 ------ python/gras/stats/main.js | 76 ---------- python/gras/stats/utils.js | 84 ----------- 29 files changed, 933 insertions(+), 932 deletions(-) create mode 100644 lib/top_block_query.cpp delete mode 100644 lib/top_block_stats.cpp create mode 100644 python/gras/query/CMakeLists.txt create mode 100644 python/gras/query/__init__.py create mode 100644 python/gras/query/chart_factory.js create mode 100644 python/gras/query/chart_handler_breakdown.js create mode 100644 python/gras/query/chart_overall_throughput.js create mode 100644 python/gras/query/chart_overhead_compare.js create mode 100644 python/gras/query/chart_total_io_counts.js create mode 100644 python/gras/query/main.css create mode 100644 python/gras/query/main.html create mode 100644 python/gras/query/main.js create mode 100644 python/gras/query/utils.js delete mode 100644 python/gras/stats/CMakeLists.txt delete mode 100644 python/gras/stats/__init__.py delete mode 100644 python/gras/stats/chart_factory.js delete mode 100644 python/gras/stats/chart_handler_breakdown.js delete mode 100644 python/gras/stats/chart_overall_throughput.js delete mode 100644 python/gras/stats/chart_overhead_compare.js delete mode 100644 python/gras/stats/chart_total_io_counts.js delete mode 100644 python/gras/stats/main.css delete mode 100644 python/gras/stats/main.html delete mode 100644 python/gras/stats/main.js delete mode 100644 python/gras/stats/utils.js diff --git a/grextras b/grextras index 31deb5e..a3b79c7 160000 --- a/grextras +++ b/grextras @@ -1 +1 @@ -Subproject commit 31deb5eb68c7b4cb36ae4773359a6ffbe3e6fc04 +Subproject commit a3b79c7c7f77436a2757afef053d55ed0405c67d diff --git a/include/gras/top_block.hpp b/include/gras/top_block.hpp index e288d95..f99d341 100644 --- a/include/gras/top_block.hpp +++ b/include/gras/top_block.hpp @@ -78,11 +78,12 @@ struct GRAS_API TopBlock : HierBlock virtual bool wait(const double timeout); /*! - * Get block usage statistics in some format. - * Args are used to set the query parameters. + * Query the flow graph for information. * An external app will visualize the data. + * \param args the input query args + * \return formatted result of the query */ - virtual std::string get_stats(const std::string &args); + virtual std::string query(const std::string &args); }; } //namespace gras diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e667570..fa15efa 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -55,7 +55,7 @@ list(APPEND GRAS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/output_handlers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hier_block.cpp ${CMAKE_CURRENT_SOURCE_DIR}/top_block.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/top_block_stats.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/top_block_query.cpp ${CMAKE_CURRENT_SOURCE_DIR}/register_messages.cpp ${CMAKE_CURRENT_SOURCE_DIR}/theron_allocator.cpp ) diff --git a/lib/top_block_query.cpp b/lib/top_block_query.cpp new file mode 100644 index 0000000..1a6376c --- /dev/null +++ b/lib/top_block_query.cpp @@ -0,0 +1,85 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#include "element_impl.hpp" +#include +#include +#include + +using namespace gras; + +struct GetStatsReceiver : Theron::Receiver +{ + GetStatsReceiver(void) + { + this->RegisterHandler(this, &GetStatsReceiver::handle_get_stats); + } + + void handle_get_stats(const GetStatsMessage &message, const Theron::Address) + { + this->messages.push_back(message); + } + + std::vector messages; +}; + +std::string TopBlock::query(const std::string &) +{ + //get stats with custom receiver and set high prio + GetStatsReceiver receiver; + size_t outstandingCount(0); + BOOST_FOREACH(Apology::Worker *worker, (*this)->executor->get_workers()) + { + dynamic_cast(worker)->highPrioPreNotify(); + worker->Push(GetStatsMessage(), receiver.GetAddress()); + outstandingCount++; + } + while (outstandingCount) outstandingCount -= receiver.Wait(outstandingCount); + + //now format the xml result + std::string xml; + xml += str(boost::format(" %llu\n") % time_now()); + xml += str(boost::format(" %llu\n") % time_tps()); + BOOST_FOREACH(const GetStatsMessage &message, receiver.messages) + { + const BlockStats &stats = message.stats; + std::string block_xml; + block_xml += str(boost::format(" %llu\n") % time_tps()); + block_xml += str(boost::format(" %llu\n") % message.stats_time); + block_xml += str(boost::format(" %llu\n") % stats.init_time); + block_xml += str(boost::format(" %llu\n") % stats.start_time); + block_xml += str(boost::format(" %llu\n") % stats.stop_time); + block_xml += str(boost::format(" %llu\n") % stats.work_count); + block_xml += str(boost::format(" %llu\n") % stats.time_last_work); + block_xml += str(boost::format(" %llu\n") % stats.total_time_prep); + block_xml += str(boost::format(" %llu\n") % stats.total_time_work); + block_xml += str(boost::format(" %llu\n") % stats.total_time_post); + block_xml += str(boost::format(" %llu\n") % stats.total_time_input); + block_xml += str(boost::format(" %llu\n") % stats.total_time_output); + for (size_t i = 0; i < stats.items_consumed.size(); i++) + { + block_xml += str(boost::format(" %llu\n") % stats.items_consumed[i]); + } + for (size_t i = 0; i < stats.tags_consumed.size(); i++) + { + block_xml += str(boost::format(" %llu\n") % stats.tags_consumed[i]); + } + for (size_t i = 0; i < stats.msgs_consumed.size(); i++) + { + block_xml += str(boost::format(" %llu\n") % stats.msgs_consumed[i]); + } + for (size_t i = 0; i < stats.items_produced.size(); i++) + { + block_xml += str(boost::format(" %llu\n") % stats.items_produced[i]); + } + for (size_t i = 0; i < stats.tags_produced.size(); i++) + { + block_xml += str(boost::format(" %llu\n") % stats.tags_produced[i]); + } + for (size_t i = 0; i < stats.msgs_produced.size(); i++) + { + block_xml += str(boost::format(" %llu\n") % stats.msgs_produced[i]); + } + xml += str(boost::format(" \n%s\n") % message.block_id % block_xml); + } + return str(boost::format("\n%s") % this->to_string() % xml); +} diff --git a/lib/top_block_stats.cpp b/lib/top_block_stats.cpp deleted file mode 100644 index 04fc7ae..0000000 --- a/lib/top_block_stats.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. - -#include "element_impl.hpp" -#include -#include -#include - -using namespace gras; - -struct GetStatsReceiver : Theron::Receiver -{ - GetStatsReceiver(void) - { - this->RegisterHandler(this, &GetStatsReceiver::handle_get_stats); - } - - void handle_get_stats(const GetStatsMessage &message, const Theron::Address) - { - this->messages.push_back(message); - } - - std::vector messages; -}; - -std::string TopBlock::get_stats(const std::string &) -{ - //get stats with custom receiver and set high prio - GetStatsReceiver receiver; - size_t outstandingCount(0); - BOOST_FOREACH(Apology::Worker *worker, (*this)->executor->get_workers()) - { - dynamic_cast(worker)->highPrioPreNotify(); - worker->Push(GetStatsMessage(), receiver.GetAddress()); - outstandingCount++; - } - while (outstandingCount) outstandingCount -= receiver.Wait(outstandingCount); - - //now format the xml result - std::string xml; - xml += str(boost::format(" %llu\n") % time_now()); - xml += str(boost::format(" %llu\n") % time_tps()); - BOOST_FOREACH(const GetStatsMessage &message, receiver.messages) - { - const BlockStats &stats = message.stats; - std::string block_xml; - block_xml += str(boost::format(" %llu\n") % time_tps()); - block_xml += str(boost::format(" %llu\n") % message.stats_time); - block_xml += str(boost::format(" %llu\n") % stats.init_time); - block_xml += str(boost::format(" %llu\n") % stats.start_time); - block_xml += str(boost::format(" %llu\n") % stats.stop_time); - block_xml += str(boost::format(" %llu\n") % stats.work_count); - block_xml += str(boost::format(" %llu\n") % stats.time_last_work); - block_xml += str(boost::format(" %llu\n") % stats.total_time_prep); - block_xml += str(boost::format(" %llu\n") % stats.total_time_work); - block_xml += str(boost::format(" %llu\n") % stats.total_time_post); - block_xml += str(boost::format(" %llu\n") % stats.total_time_input); - block_xml += str(boost::format(" %llu\n") % stats.total_time_output); - for (size_t i = 0; i < stats.items_consumed.size(); i++) - { - block_xml += str(boost::format(" %llu\n") % stats.items_consumed[i]); - } - for (size_t i = 0; i < stats.tags_consumed.size(); i++) - { - block_xml += str(boost::format(" %llu\n") % stats.tags_consumed[i]); - } - for (size_t i = 0; i < stats.msgs_consumed.size(); i++) - { - block_xml += str(boost::format(" %llu\n") % stats.msgs_consumed[i]); - } - for (size_t i = 0; i < stats.items_produced.size(); i++) - { - block_xml += str(boost::format(" %llu\n") % stats.items_produced[i]); - } - for (size_t i = 0; i < stats.tags_produced.size(); i++) - { - block_xml += str(boost::format(" %llu\n") % stats.tags_produced[i]); - } - for (size_t i = 0; i < stats.msgs_produced.size(); i++) - { - block_xml += str(boost::format(" %llu\n") % stats.msgs_produced[i]); - } - xml += str(boost::format(" \n%s\n") % message.block_id % block_xml); - } - return str(boost::format("\n%s") % this->to_string() % xml); -} diff --git a/python/gras/CMakeLists.txt b/python/gras/CMakeLists.txt index f3ef329..e91d8df 100644 --- a/python/gras/CMakeLists.txt +++ b/python/gras/CMakeLists.txt @@ -1,7 +1,7 @@ ######################################################################## # add subdirs ######################################################################## -add_subdirectory(stats) +add_subdirectory(query) ######################################################################## # Include swig generation macros diff --git a/python/gras/GRAS_HierBlock.i b/python/gras/GRAS_HierBlock.i index 32c823b..12a5952 100644 --- a/python/gras/GRAS_HierBlock.i +++ b/python/gras/GRAS_HierBlock.i @@ -75,10 +75,10 @@ struct TopBlockPython : TopBlock return TopBlock::wait(timeout); } - std::string get_stats(const std::string &args) + std::string query(const std::string &args) { PyTSPhondler phil; - return TopBlock::get_stats(args); + return TopBlock::query(args); } }; diff --git a/python/gras/query/CMakeLists.txt b/python/gras/query/CMakeLists.txt new file mode 100644 index 0000000..ab49532 --- /dev/null +++ b/python/gras/query/CMakeLists.txt @@ -0,0 +1,26 @@ +######################################################################## +# 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_total_io_counts.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 new file mode 100644 index 0000000..5789fab --- /dev/null +++ b/python/gras/query/__init__.py @@ -0,0 +1,52 @@ +import time +import BaseHTTPServer + +import os +__path__ = os.path.abspath(os.path.dirname(__file__)) + +server_registry = dict() + +class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): + + 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.""" + if s.path.endswith('.xml'): + s.send_response(200) + s.send_header("Content-type", "text/xml") + s.end_headers() + s.wfile.write(server_registry[s.server]['top_block'].query(s.path)) + return + path = s.path + if path.startswith('/'): path = path[1:] + if not path: path = 'main.html' + target = os.path.join(__path__, path) + 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()) + 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 new file mode 100644 index 0000000..3d2b0bc --- /dev/null +++ b/python/gras/query/chart_factory.js @@ -0,0 +1,209 @@ +/*********************************************************************** + * 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:'total_io_counts', name:'I/O port Totals', factory:GrasChartTotalIoCounts}, + ]; +} + +/*********************************************************************** + * One time setup + **********************************************************************/ +function gras_chart_factory_setup(registry, point) +{ + var id = $('gras_stats:first', point).attr('id'); + registry.top_id = id; + $('#top_name').append(' - ' + id); + $('block', point).each(function(index, block) + { + var id = $(block).attr('id'); + registry.block_ids.push(id); + var container = $('#chart_designer_blocks'); + var div = $('
'); + $(div).append(''); + var input = $('').attr({ + type: 'checkbox', + name: id + }); + input.attr('checked', false); + $(div).append(input); + $(container).append(div); + }); +} + +/*********************************************************************** + * 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(all_args)); +} + +function gras_chart_load(registry) +{ + if (typeof(Storage) === "undefined") return; + var chart_args = JSON.parse(localStorage.getItem(registry.top_id)); + if (!chart_args) return; + $.each(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 = $(''); + var th_title = $('
'); + tr.append(td); + + //call into the factory + args.panel = td.get(0); + try + { + var chart = new registry.chart_factories[args.chart_type](args); + } + catch(err) + { + return; + } + + //setup the title + var tr_title = $('
'); + tr_title.append(th_title); + th_title.text(chart.title); + + //register the chart + var chart_info = {chart:chart,args:args}; + 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); +} + +/*********************************************************************** + * 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) +{ + //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 = $('