'last_month': graph.DataViewDescription(300, 60*60*24*30),
'last_year': graph.DataViewDescription(300, 60*60*24*365.25),
}
- def build_pool_rates(ds_name, ds_desc, dv_name, dv_desc, obj):
+ def build_desired_rates(ds_name, ds_desc, dv_name, dv_desc, obj):
if not obj:
last_bin_end = 0
bins = dv_desc.bin_count*[{}]
else:
- pool_rate = obj['pool_rate'][dv_name]
- pool_stale_rate = obj['pool_stale_rate'][dv_name]
- last_bin_end = max(pool_rate['last_bin_end'], pool_stale_rate['last_bin_end'])
- bins = dv_desc.bin_count*[{}]
- def get_value(obj, t):
- n = int((obj['last_bin_end'] - t)/dv_desc.bin_width)
+ pool_rates = obj['pool_rates'][dv_name]
+ desired_versions = obj['desired_versions'][dv_name]
+ def get_total_pool_rate(t):
+ n = int((pool_rates['last_bin_end'] - t)/dv_desc.bin_width)
if n < 0 or n >= dv_desc.bin_count:
- return None, 0
- total, count = obj['bins'][n].get('null', [0, 0])
+ return None
+ total = sum(x[0] for x in pool_rates['bins'][n].values())
+ count = math.mean(x[1] for x in pool_rates['bins'][n].values())
if count == 0:
- return None, 0
- return total/count, count
- def get_bin(t):
- total, total_count = get_value(pool_rate, t)
- bad, bad_count = get_value(pool_stale_rate, t)
- if total is None or bad is None:
- return {}
- count = int((total_count+bad_count)/2+1/2)
- return dict(good=[(total-bad)*count, count], bad=[bad*count, count], null=[0, count])
- bins = [get_bin(last_bin_end - (i+1/2)*dv_desc.bin_width) for i in xrange(dv_desc.bin_count)]
+ return None
+ return total/count
+ last_bin_end = desired_versions['last_bin_end']
+ bins = [dict((name, (total*get_total_pool_rate(last_bin_end - (i+1/2)*dv_desc.bin_width), count)) for name, (total, count) in desired_versions['bins'][i].iteritems()) for i in xrange(dv_desc.bin_count)]
return graph.DataView(dv_desc, ds_desc, last_bin_end, bins)
hd = graph.HistoryDatabase.from_obj({
'local_hash_rate': graph.DataStreamDescription(dataview_descriptions, is_gauge=False),
'local_share_hash_rate': graph.DataStreamDescription(dataview_descriptions, is_gauge=False),
'local_dead_share_hash_rate': graph.DataStreamDescription(dataview_descriptions, is_gauge=False),
'pool_rates': graph.DataStreamDescription(dataview_descriptions, multivalues=True,
- multivalue_undefined_means_0=True, default_func=build_pool_rates),
+ multivalue_undefined_means_0=True),
'current_payout': graph.DataStreamDescription(dataview_descriptions),
'current_payouts': graph.DataStreamDescription(dataview_descriptions, multivalues=True),
'incoming_peers': graph.DataStreamDescription(dataview_descriptions),
'miner_dead_hash_rates': graph.DataStreamDescription(dataview_descriptions, is_gauge=False, multivalues=True),
'desired_versions': graph.DataStreamDescription(dataview_descriptions, multivalues=True,
multivalue_undefined_means_0=True),
+ 'desired_version_rates': graph.DataStreamDescription(dataview_descriptions, multivalues=True,
+ multivalue_undefined_means_0=True, default_func=build_desired_rates),
'traffic_rate': graph.DataStreamDescription(dataview_descriptions, is_gauge=False, multivalues=True),
}, hd_obj)
task.LoopingCall(lambda: _atomic_write(hd_path, json.dumps(hd.to_obj()))).start(100)
lookbehind = min(node.net.CHAIN_LENGTH, 60*60//node.net.SHARE_PERIOD, node.tracker.get_height(node.best_share_var.value))
t = time.time()
- hd.datastreams['pool_rates'].add_datum(t, p2pool_data.get_stale_counts(node.tracker, node.best_share_var.value, lookbehind, rates=True))
+ pool_rates = p2pool_data.get_stale_counts(node.tracker, node.best_share_var.value, lookbehind, rates=True)
+ pool_total = sum(pool_rates.itervalues())
+ hd.datastreams['pool_rates'].add_datum(t, pool_rates)
current_txouts = node.get_current_txouts()
hd.datastreams['current_payout'].add_datum(t, current_txouts.get(bitcoin_data.pubkey_hash_to_script2(wb.my_pubkey_hash), 0)*1e-8)
vs = p2pool_data.get_desired_version_counts(node.tracker, node.best_share_var.value, lookbehind)
vs_total = sum(vs.itervalues())
hd.datastreams['desired_versions'].add_datum(t, dict((str(k), v/vs_total) for k, v in vs.iteritems()))
+ hd.datastreams['desired_version_rates'].add_datum(t, dict((str(k), v/vs_total*pool_total) for k, v in vs.iteritems()))
task.LoopingCall(add_point).start(5)
new_root.putChild('graph_data', WebInterface(lambda source, view: hd.datastreams[source].dataviews[view].get_data(time.time())))
<h2>Miners</h2>
<div id="miners"></div>
- <h2>Desired versions</h2>
- <svg id="desired_versions"></svg>
+ <h2>Desired version rates</h2>
+ <svg id="desired_version_rates"></svg>
<h2>Traffic rate</h2>
<svg id="traffic_rate"></svg>
d3.max(data, function(d) { return d3.max(d.data, function(d) { return d.y0 + d.y; }) })
]).range([h - margin_v, margin_v]);
+ var y_abs = d3.scale.linear().domain([0, 1]).range([h - margin_v, margin_v]);
+
g.selectAll().data(lines).enter().append("svg:path")
.attr("d", function(line){
return d3.svg.area()
})
.style("fill", function(line){return line.color})
.attr("stroke", function(line){return line.color})
- .attr("class", "plotline")
- .on("mouseover", function(line, i) {
- for(var j = 0; j < text_boxes.length; j++)
- text_boxes[j][1].attr("opacity", text_boxes[j][0] == i ? 1 : 0.3);
- });
+ .attr("class", "plotline");
- var text_boxes = [];
var total = 0;
var total_area = 0;
for(var i = 0; i < lines.length; ++i) {
var line = lines[i];
var stats = get_area_mean(line.data);
if(stats.mean != null) {
+ total += stats.mean;
+ total_area += stats.area;
+ }
+ }
+
+ for(var i = 0; i < lines.length; ++i) {
+ var line = lines[i];
+ var stats = get_area_mean(line.data);
+ if(stats.mean != null) {
var num = 0;
var denom = 0;
for(var j = 0; j < line.data.length; j++)
num += (d.y+1)*((d.y0 + d.y) + (d.y0))/2;
denom += (d.y+1);
}
- text_boxes.push([i, g.append("svg:text")
+ g.append("svg:line")
+ .style("stroke", line.color)
+ .attr("x1", w - margin_h + 3)
+ .attr("y1", y(num/denom))
+ .attr("x2", w - margin_h + 10)
+ .attr("y2", y_abs(i/lines.length));
+ g.append("svg:text")
.text(line.label + " (mean: " + d3.format(".3s")(stats.mean) + unit + ")")
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", line.color)
.attr("x", w - margin_h + 10)
- .attr("y", y(num/denom))]);
+ .attr("y", y_abs(i/lines.length));
if(total_unit != null)
- text_boxes.push([i, g.append("svg:text")
- .text("Area: " + d3.format(".3s")(stats.area) + total_unit)
+ g.append("svg:text")
+ .text("Area: " + d3.format(".3s")(stats.area) + total_unit + " (" + d3.format(".2p")(stats.area/total_area) + " total)")
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", line.color)
.attr("x", w - margin_h + 10)
- .attr("y", y(num/denom) + 12)]);
- total += stats.mean;
- total_area += stats.area;
+ .attr("y", y_abs(i/lines.length) + 12);
}
}
- text_boxes.push([i, g.append("svg:text")
- .text("- Total (mean: " + d3.format(".3s")(total) + unit + ")")
+ g.append("svg:line")
+ .style("stroke", "black")
+ .attr("x1", w - margin_h + 3)
+ .attr("y1", y(total))
+ .attr("x2", w - margin_h + 10)
+ .attr("y2", y_abs(1));
+ g.append("svg:text")
+ .text("Total (mean: " + d3.format(".3s")(total) + unit + ")")
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", "black")
- .attr("x", w - margin_h)
- .attr("y", y(total))]);
+ .attr("x", w - margin_h + 10)
+ .attr("y", y_abs(1));
if(total_unit != null)
- text_boxes.push([i, g.append("svg:text")
+ g.append("svg:text")
.text("Area: " + d3.format(".3s")(total_area) + total_unit)
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", "black")
.attr("x", w - margin_h + 10)
- .attr("y", y(total) + 12)]);
+ .attr("y", y_abs(1) + 12);
} else {
var y = d3.scale.linear().domain([
0,
(line.data)
})
.style("stroke", function(line) { return line.color })
- .attr("class", "plotline")
- .on("mouseover", function(line, i) {
- for(var j = 0; j < text_boxes.length; j++)
- text_boxes[j][1].attr("opacity", text_boxes[j][0] == i ? 1 : 0.3);
- });
+ .attr("class", "plotline");
- var text_boxes = [];
for(var i = 0; i < lines.length; ++i) {
var line = lines[i];
var stats = get_area_mean(line.data);
if(stats.mean != null) {
- text_boxes.push([i, g.append("svg:text")
+ g.append("svg:text")
.text(line.label)
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", line.color)
.attr("x", w - margin_h + 10)
- .attr("y", y(stats.mean) - 12)]);
- text_boxes.push([i, g.append("svg:text")
+ .attr("y", y(stats.mean) - 12);
+ g.append("svg:text")
.text("-Mean: " + d3.format(".3s")(stats.mean) + unit)
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", line.color)
.attr("x", w - margin_h)
- .attr("y", y(stats.mean))]);
+ .attr("y", y(stats.mean));
if(total_unit != null)
- text_boxes.push([i, g.append("svg:text")
+ g.append("svg:text")
.text("Area: " + d3.format(".3s")(stats.area) + total_unit)
.attr("text-anchor", "start")
.attr("dominant-baseline", "central")
.attr("fill", line.color)
.attr("x", w - margin_h + 10)
- .attr("y", y(stats.mean) + 12)]);
+ .attr("y", y(stats.mean) + 12);
}
}
}
{"url": "/web/graph_data/current_payout/last_" + lowerperiod, "color": "#0000FF"}
]);
d3.json("/web/graph_data/pool_rates/last_" + lowerperiod, function(data) {
- plot(d3.select('#pool'), 'H/s', null, data_to_lines(data), true);
+ plot(d3.select('#pool'), 'H/s', 'H', data_to_lines(data), true);
});
plot_later(d3.select("#peers"), "", null, [
{"url": "/web/graph_data/outgoing_peers/last_" + lowerperiod, "color": "#FF0000", "label": "Outgoing"},
});
});
- d3.json("/web/graph_data/desired_versions/last_" + lowerperiod, function(data) {
- plot(d3.select('#desired_versions'), '', null, data_to_lines(data, function(line){ return parseInt(line.label) }), true);
+ d3.json("/web/graph_data/desired_version_rates/last_" + lowerperiod, function(data) {
+ plot(d3.select('#desired_version_rates'), 'H/s', 'H', data_to_lines(data, function(line){ return parseInt(line.label) }), true);
});
d3.json("/web/graph_data/traffic_rate/last_" + lowerperiod, function(data) {