summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/block_task.cpp19
-rw-r--r--lib/gras_impl/stats.hpp35
-rw-r--r--lib/input_handlers.cpp9
-rw-r--r--lib/output_handlers.cpp7
-rw-r--r--lib/top_block_stats.cpp5
-rw-r--r--python/gras/stats/charts.js91
-rw-r--r--python/gras/stats/main.css3
-rw-r--r--python/gras/stats/main.html5
-rw-r--r--python/gras/stats/main.js4
-rw-r--r--python/gras/stats/registry.js1
-rw-r--r--python/gras/stats/utils.js12
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('&nbsp;');
+}
+
+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('&nbsp;');
+ 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()),
+ };
+}