//= require lib/_highcharts
var SerfSimulator = {
// Defaults
graphSettings: {
chart: {
type: 'spline'
},
title: {
text: null
},
xAxis: {
title: {
text: "Time (sec)",
style: {
color: "#B03C44",
},
}
},
yAxis: {
title: {
text: 'Convergence %',
style: {
color: "#B03C44",
},
},
min: 0.0,
max: 100.0
},
tooltip: {
formatter: function() {
return ''+ (Math.round(this.y*1000.0)/1000.0) +'%
'
}
},
legend: {
enabled: false
},
series: [
{
name: 'Convergence Rate',
data: [],
color: "#B03C44",
}
]
},
maxConverge: 0.9999,
interval: 0.2,
fanout : 3,
nodes: 30,
packetLoss: 0,
nodeFail: 0,
// init does all the stuff after the body is loaded
init: function() {
// Do not init if the graph is not present
if (!$("#graph").length) {
return
}
this.$graph = $("#graph");
this.$graph.highcharts(this.graphSettings);
this.$graphed = this.$graph.highcharts();
this.$interval = $("#interval");
this.$fanout = $("#fanout");
this.$nodes = $("#nodes");
this.$loss = $("#packetloss");
this.$failed = $("#failed");
this.$bytes = $("#bytes");
simulator = this;
// Draw initial
this.draw();
this.$interval.on("change", function() {
var interval = Number(this.value);
if (isNaN(interval) || interval <= 0) {
alert("Gossip interval must be a positive value!");
return;
}
simulator.interval = interval;
simulator.draw();
});
this.$fanout.on("change", function() {
var fanout = Number(this.value);
if (isNaN(fanout) || fanout <= 0) {
alert("Gossip fanout must be a positive value!");
return;
}
simulator.fanout = fanout;
simulator.draw();
});
this.$nodes.on("change", function() {
var nodes = Number(this.value);
if (isNaN(nodes) || nodes <= 1) {
alert("Must have at least one node!");
return;
}
simulator.nodes = nodes;
simulator.draw();
});
this.$loss.on("change", function() {
var pkt = Number(this.value);
if (isNaN(pkt) || pkt < 0 || pkt >= 100) {
alert("Packet loss must be greater or equal to 0 and less than 100");
return;
}
simulator.packetLoss = (pkt / 100.0);
simulator.draw();
});
this.$failed.on("change", function() {
var failed = Number(this.value);
if (isNaN(failed) || failed < 0 || failed >= 100) {
alert("Failure rate must be greater or equal to 0 and less than 100");
return;
}
simulator.nodeFail = (failed / 100.0);
simulator.draw();
});
},
draw: function() {
var data = this.seriesData();
this.$graphed.series[0].setData(data, false)/
this.$graphed.redraw();
var kilobits = this.bytesUsed() * 8;
var used = Math.round((kilobits / 1024) * 10) / 10;
this.$bytes.html("" + used);
},
convergenceAtRound: function(x) {
var contact = (this.fanout / this.nodes) * (1 - this.packetLoss) * (1 - this.nodeFail) * 0.5
var numInf = this.nodes / (1 + (this.nodes+1) * Math.pow(Math.E, -1*contact*this.nodes*x))
return numInf / this.nodes
},
roundLength: function() {
return this.interval
},
seriesData: function() {
var data = []
var lastVal = 0
var round = 0
var roundLength = this.roundLength()
while (lastVal < this.maxConverge && round < 100) {
lastVal = this.convergenceAtRound(round)
data.push([round * roundLength, lastVal*100.0])
round++
}
return data
},
bytesUsed: function() {
var roundLength = this.roundLength()
var roundsPerSec = 1 / roundLength
var packetSize = 1400
var send = packetSize * this.fanout * roundsPerSec
return send * 2
},
}
// Handle document ready function and the turbolinks load.
$(document).on("turbolinks:load", function() {
SerfSimulator.init()
});