diff options
-rw-r--r-- | lib/block_task.cpp | 19 | ||||
-rw-r--r-- | lib/gras_impl/stats.hpp | 35 | ||||
-rw-r--r-- | lib/input_handlers.cpp | 9 | ||||
-rw-r--r-- | lib/output_handlers.cpp | 7 | ||||
-rw-r--r-- | lib/top_block_stats.cpp | 5 | ||||
-rw-r--r-- | python/gras/stats/charts.js | 91 | ||||
-rw-r--r-- | python/gras/stats/main.css | 3 | ||||
-rw-r--r-- | python/gras/stats/main.html | 5 | ||||
-rw-r--r-- | python/gras/stats/main.js | 4 | ||||
-rw-r--r-- | python/gras/stats/registry.js | 1 | ||||
-rw-r--r-- | python/gras/stats/utils.js | 12 |
11 files changed, 158 insertions, 33 deletions
diff --git a/lib/block_task.cpp b/lib/block_task.cpp index 2509925..a3342a6 100644 --- a/lib/block_task.cpp +++ b/lib/block_task.cpp @@ -99,7 +99,8 @@ void BlockActor::output_fail(const size_t i) void BlockActor::handle_task(void) { - const time_ticks_t task_start = time_now(); + TimerAccumulate ta_prep(this->stats.total_time_prep); + //------------------------------------------------------------------ //-- Decide if its possible to continue any processing: //-- Handle task may get called for incoming buffers, @@ -181,16 +182,20 @@ void BlockActor::handle_task(void) //------------------------------------------------------------------ //-- the work //------------------------------------------------------------------ - const time_ticks_t work_start = time_now(); + ta_prep.done(); + this->stats.work_count++; if GRAS_UNLIKELY(this->interruptible_thread) { + TimerAccumulate ta_work(this->stats.total_time_work); this->interruptible_thread->call(); } else { + TimerAccumulate ta_work(this->stats.total_time_work); this->task_work(); } - const time_ticks_t work_stop = time_now(); + this->stats.time_last_work = time_now(); + TimerAccumulate ta_post(this->stats.total_time_post); //------------------------------------------------------------------ //-- Flush output buffers downstream @@ -214,14 +219,6 @@ void BlockActor::handle_task(void) //still have IO ready? kick off another task this->task_kicker(); - - //save stats - const time_ticks_t task_time = time_now() - task_start; - const time_ticks_t work_time = work_stop - work_start; - this->stats.work_count++; - this->stats.total_time_work += work_time; - this->stats.total_time_work_other += task_time - work_time; - this->stats.time_last_work = work_stop; } void BlockActor::consume(const size_t i, const size_t items) diff --git a/lib/gras_impl/stats.hpp b/lib/gras_impl/stats.hpp index 9c9c8e1..0514f90 100644 --- a/lib/gras_impl/stats.hpp +++ b/lib/gras_impl/stats.hpp @@ -11,6 +11,19 @@ namespace gras struct BlockStats { + BlockStats(void) + { + start_time = 0; + stop_time = 0; + work_count = 0; + time_last_work = 0; + total_time_prep = 0; + total_time_work = 0; + total_time_post = 0; + total_time_input = 0; + total_time_output = 0; + } + time_ticks_t start_time; time_ticks_t stop_time; @@ -21,8 +34,28 @@ struct BlockStats item_index_t work_count; time_ticks_t time_last_work; + time_ticks_t total_time_prep; time_ticks_t total_time_work; - time_ticks_t total_time_work_other; + time_ticks_t total_time_post; + time_ticks_t total_time_input; + time_ticks_t total_time_output; +}; + +struct TimerAccumulate +{ + TimerAccumulate(time_ticks_t &accum): + accum(accum), t0(time_now()){} + ~TimerAccumulate(void) + { + if (t0) this->done(); + } + void done(void) + { + accum += (time_now()-t0); + t0 = 0; + } + time_ticks_t &accum; + time_ticks_t t0; }; } //namespace gras diff --git a/lib/input_handlers.cpp b/lib/input_handlers.cpp index e51808b..56ead46 100644 --- a/lib/input_handlers.cpp +++ b/lib/input_handlers.cpp @@ -7,6 +7,7 @@ using namespace gras; void BlockActor::handle_input_tag(const InputTagMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_input); MESSAGE_TRACER(); const size_t index = message.index; @@ -17,11 +18,13 @@ void BlockActor::handle_input_tag(const InputTagMessage &message, const Theron:: //because tags are being used for message passing, or this is just the first tag in a stream. this->input_tags_changed[index] = this->input_tags_changed[index] or message.tag.offset != 0; this->inputs_available.set(index); + ta.done(); this->handle_task(); } void BlockActor::handle_input_buffer(const InputBufferMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_input); MESSAGE_TRACER(); const size_t index = message.index; @@ -29,11 +32,13 @@ void BlockActor::handle_input_buffer(const InputBufferMessage &message, const Th if (this->block_state == BLOCK_STATE_DONE) return; this->input_queues.push(index, message.buffer); this->inputs_available.set(index); + ta.done(); this->handle_task(); } void BlockActor::handle_input_token(const InputTokenMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_input); MESSAGE_TRACER(); ASSERT(message.index < this->get_num_inputs()); @@ -43,6 +48,7 @@ void BlockActor::handle_input_token(const InputTokenMessage &message, const Ther void BlockActor::handle_input_check(const InputCheckMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_input); MESSAGE_TRACER(); const size_t index = message.index; @@ -55,12 +61,14 @@ void BlockActor::handle_input_check(const InputCheckMessage &message, const Ther //or re-enter handle task so fail logic can mark done else { + ta.done(); this->handle_task(); } } void BlockActor::handle_input_alloc(const InputAllocMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_input); MESSAGE_TRACER(); const size_t index = message.index; @@ -72,6 +80,7 @@ void BlockActor::handle_input_alloc(const InputAllocMessage &message, const Ther void BlockActor::handle_input_update(const InputUpdateMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_input); MESSAGE_TRACER(); const size_t i = message.index; diff --git a/lib/output_handlers.cpp b/lib/output_handlers.cpp index 3ab78fa..d8064f6 100644 --- a/lib/output_handlers.cpp +++ b/lib/output_handlers.cpp @@ -8,6 +8,7 @@ using namespace gras; void BlockActor::handle_output_buffer(const OutputBufferMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_output); MESSAGE_TRACER(); const size_t index = message.index; @@ -15,11 +16,13 @@ void BlockActor::handle_output_buffer(const OutputBufferMessage &message, const //(all interested consumers have finished with it) if (this->block_state == BLOCK_STATE_DONE) return; this->output_queues.push(index, message.buffer); + ta.done(); this->handle_task(); } void BlockActor::handle_output_token(const OutputTokenMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_output); MESSAGE_TRACER(); ASSERT(message.index < this->get_num_outputs()); @@ -29,6 +32,7 @@ void BlockActor::handle_output_token(const OutputTokenMessage &message, const Th void BlockActor::handle_output_check(const OutputCheckMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_output); MESSAGE_TRACER(); const size_t index = message.index; @@ -42,6 +46,7 @@ void BlockActor::handle_output_check(const OutputCheckMessage &message, const Th void BlockActor::handle_output_hint(const OutputHintMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_output); MESSAGE_TRACER(); const size_t index = message.index; @@ -66,6 +71,7 @@ void BlockActor::handle_output_hint(const OutputHintMessage &message, const Ther void BlockActor::handle_output_alloc(const OutputAllocMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_output); MESSAGE_TRACER(); const size_t index = message.index; @@ -75,6 +81,7 @@ void BlockActor::handle_output_alloc(const OutputAllocMessage &message, const Th void BlockActor::handle_output_update(const OutputUpdateMessage &message, const Theron::Address) { + TimerAccumulate ta(this->stats.total_time_output); MESSAGE_TRACER(); const size_t i = message.index; diff --git a/lib/top_block_stats.cpp b/lib/top_block_stats.cpp index a6559e1..3cadfcb 100644 --- a/lib/top_block_stats.cpp +++ b/lib/top_block_stats.cpp @@ -39,8 +39,11 @@ std::string TopBlock::get_stats(const std::string &) block_xml += str(boost::format(" <stop_time>%llu</stop_time>\n") % stats.stop_time); block_xml += str(boost::format(" <work_count>%llu</work_count>\n") % stats.work_count); block_xml += str(boost::format(" <time_last_work>%llu</time_last_work>\n") % stats.time_last_work); + block_xml += str(boost::format(" <total_time_prep>%llu</total_time_prep>\n") % stats.total_time_prep); block_xml += str(boost::format(" <total_time_work>%llu</total_time_work>\n") % stats.total_time_work); - block_xml += str(boost::format(" <total_time_work_other>%llu</total_time_work_other>\n") % stats.total_time_work_other); + block_xml += str(boost::format(" <total_time_post>%llu</total_time_post>\n") % stats.total_time_post); + block_xml += str(boost::format(" <total_time_input>%llu</total_time_input>\n") % stats.total_time_input); + block_xml += str(boost::format(" <total_time_output>%llu</total_time_output>\n") % stats.total_time_output); for (size_t i = 0; i < stats.items_consumed.size(); i++) { block_xml += str(boost::format(" <items_consumed>%llu</items_consumed>\n") % stats.items_consumed[i]); diff --git a/python/gras/stats/charts.js b/python/gras/stats/charts.js index acb07d7..1af39bb 100644 --- a/python/gras/stats/charts.js +++ b/python/gras/stats/charts.js @@ -2,6 +2,12 @@ * charts and visualization stuff **********************************************************************/ +var gras_animate_show_hide = function(elem, show) +{ + if (show) elem.slideDown("fast"); + else elem.slideUp("fast"); +} + var gras_setup_overall_chart = function(registry) { var div = $('#overall_chart:first'); @@ -10,6 +16,41 @@ var gras_setup_overall_chart = function(registry) registry.overall_chart = chart; } +var gras_setup_per_block_enable_checkbox = function(elem, id, registry) +{ + $(elem).append('<label>' + id + '</label>'); + var input = $('<input />').attr({ + type: 'checkbox', + name: id + }); + registry.block_enables[id] = true; + input.attr('checked', registry.block_enables[id]); + input.change(function() + { + registry.block_enables[id] = input.is(':checked'); + gras_update_throughput_chart(registry); + var div = $('#per_block_charts'); + gras_animate_show_hide($('table[name="' + id + '"]', div), registry.block_enables[id]); + }); + $(elem).append(input); + $(elem).append(' '); +} + +var gras_setup_per_block_charts = function(id, registry) +{ + var div = $('#per_block_charts'); + var table = $('<table />'); + table.attr('name', id); + div.append(table); + table.append('<tr><th></th></tr>'); + $('th:last', table).text(id); + table.append('<tr><td></td></tr>'); + var td = $('td:last', table); + var chart = new google.visualization.PieChart(td.get(0)); + registry.block_charts[id] = chart; + +} + var gras_setup_individual_charts = function(registry) { var point = registry.history[0]; @@ -18,20 +59,8 @@ var gras_setup_individual_charts = function(registry) var count = 0; $.each(registry.getBlockIds(), function(index, id) { - $(config).append('<label>' + id + '</label>'); - var input = $('<input />').attr({ - type: 'checkbox', - name: id - }); - registry.block_enables[id] = true; - input.attr('checked', registry.block_enables[id]); - input.change(function() - { - registry.block_enables[id] = input.is(':checked'); - gras_update_throughput_chart(registry); - }); - $(config).append(input); - $(config).append(' '); + gras_setup_per_block_enable_checkbox(config, id, registry); + gras_setup_per_block_charts(id, registry); count++; if (count == Math.round(registry.getBlockIds().length/2)) { @@ -43,6 +72,36 @@ var gras_setup_individual_charts = function(registry) } +var gras_update_per_block_chart = function(id, registry) +{ + var point = registry.history[registry.history.length-1]; + var percents = gras_extract_percent_times(point, 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 = { + width:$('#page').width()/5, + chartArea:{left:5,top:0,right:5,bottom:0,width:"100%",height:"100%"}, + }; + + var chart = registry.block_charts[id]; + chart.draw(data, options); +} + +var gras_update_per_block_charts = function(registry) +{ + if (registry.history.length == 0) return; + $.each(registry.getBlockIds(), function(index, id) + { + gras_update_per_block_chart(id, registry); + }); +} var gras_update_throughput_chart = function(registry) { @@ -76,9 +135,9 @@ var gras_update_throughput_chart = function(registry) var chart_data = google.visualization.arrayToDataTable(data_set); var options = { width:$('#page').width()*0.9, - height:'300', + height:'250', chartArea:{left:0,top:0,right:0,bottom:0,width:"100%",height:"85%"}, - legend: {'position': 'bottom'} + legend: {'position': 'bottom'}, }; registry.overall_chart.draw(chart_data, options); diff --git a/python/gras/stats/main.css b/python/gras/stats/main.css index bfa15d9..84023fe 100644 --- a/python/gras/stats/main.css +++ b/python/gras/stats/main.css @@ -10,8 +10,9 @@ color:black; background-color:white; } -#overall_charts +#per_block_charts table { +float:left; } #overall_config diff --git a/python/gras/stats/main.html b/python/gras/stats/main.html index 02496a5..4032d79 100644 --- a/python/gras/stats/main.html +++ b/python/gras/stats/main.html @@ -21,7 +21,7 @@ <h1>GRAS Status Monitor</h1> <div id="overall_config"> <table> - <tr><th colspan="2">Overall chart config</th></tr> + <tr><th colspan="2">Throughput options</th></tr> <tr> <td colspan="2">Updates/sec: <input type="number" name="rate" min="1" max="10" size="4" /></td> </tr> @@ -46,6 +46,9 @@ </tr> </table> </div> + <div id="per_block_charts"> + + </div> </body> </html> diff --git a/python/gras/stats/main.js b/python/gras/stats/main.js index c12b8e7..35287cc 100644 --- a/python/gras/stats/main.js +++ b/python/gras/stats/main.js @@ -16,6 +16,7 @@ var gras_query_stats = function(registry) { registry.appendPoint(xml); gras_update_throughput_chart(registry); + gras_update_per_block_charts(registry); } var onceHandle = window.setTimeout(function() @@ -59,8 +60,7 @@ var gras_stats_main = function() overall_show.change(function() { var chart = $('#overall_chart'); - if (overall_show.is(':checked')) chart.slideDown("slow"); - else chart.slideUp("slow"); + gras_animate_show_hide(chart, overall_show.is(':checked')); }); gras_setup_overall_chart(registry); diff --git a/python/gras/stats/registry.js b/python/gras/stats/registry.js index 04e74b7..e663583 100644 --- a/python/gras/stats/registry.js +++ b/python/gras/stats/registry.js @@ -9,6 +9,7 @@ var GrasStatsRegistry = function() this.block_enables = new Array(); this.overall_rate = 2.0; this.overall_active = true; + this.block_charts = new Array(); } GrasStatsRegistry.prototype.appendPoint = function(point) diff --git a/python/gras/stats/utils.js b/python/gras/stats/utils.js index 952e76b..de123ff 100644 --- a/python/gras/stats/utils.js +++ b/python/gras/stats/utils.js @@ -33,3 +33,15 @@ var gras_extract_throughput = function(point, id) var total_items = gras_extract_total_items(point, id); return (total_items*tps)/(stats_time-start_time); } + +var gras_extract_percent_times = function(point, id) +{ + var block_data = $('block[id="' + id + '"]', point); + return { + prep: parseInt($('total_time_prep', block_data).text()), + work: parseInt($('total_time_work', block_data).text()), + post: parseInt($('total_time_post', block_data).text()), + input: parseInt($('total_time_input', block_data).text()), + output: parseInt($('total_time_output', block_data).text()), + }; +} |