Skip to content

Instantly share code, notes, and snippets.

@msbarry
Last active March 21, 2017 19:18
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msbarry/5830888 to your computer and use it in GitHub Desktop.
Save msbarry/5830888 to your computer and use it in GitHub Desktop.
M/M/1 Queue Simulation
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>M/M/1 Queue</title>
<style type="text/css">
body {
font-size: 12px;
font-family: Arial;
width: 960px;
margin: 1em auto 0.3em auto;
}
.controls {
margin: 20px 0 0 20px;
}
#chart {
width: 100%;
margin-top: 10px;
}
#chart svg {
margin-top: 10px;
}
.notshown {
margin-left: 20px;
}
svg .bounds {
fill-opacity: 0;
stroke-opacity: 1;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div class="controls">
<p>Arrivals per second: <input type="number" step="0.1" value="1" id="arr"></input>
Seconds to service: <input type="number" step="0.1" value="0.5" id="ts"></input></p>
</div>
<div id="chart"></div>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var margin = {top: 1, right: 20, bottom: 1, left: 20},
outerWidth = 970,
outerHeight = 35,
w = outerWidth - margin.left - margin.right,
h = outerHeight - margin.top - margin.bottom;
var packetPadding = 3,
packetWidth = 30,
packetHeight = h - 2 * packetPadding,
limit = Math.floor(w / (packetWidth + packetPadding)) - 1;
var color = d3.scale.pow().exponent(4)
.domain([limit, 0])
.range(["red", "black"])
.interpolate(d3.interpolateLab);
d3.range(0, 5).forEach(function () {
var id = 0, queue = [];
var svg = d3.select("#chart")
.append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight)
.append("g")
.attr("transform", "translate(" + [margin.left, margin.top].join(",") + ")");
svg.append("rect")
.attr("class", "bounds")
.attr("width", packetWidth + packetPadding)
.attr("height", packetHeight + packetPadding)
.attr("x", w - packetWidth - packetPadding * 1.5)
.attr("y", 1);
function schedulePoisson(f, averageRatePerSecond) {
var delay = (1000 * -Math.log(Math.random()) / averageRatePerSecond) || 1000;
setTimeout(f, delay);
}
function packetArrival() {
queue.push(id++);
updateUI();
if (queue.length === 1) { schedulePoisson(servicePacket, 1 / averageServiceTimeInSeconds()); }
updateNotShown(queue);
schedulePoisson(packetArrival, arrivalRatePerSecond());
}
function servicePacket() {
queue.shift(1);
updateUI();
updateNotShown(queue);
if (queue.length > 0) { schedulePoisson(servicePacket, 1 / averageServiceTimeInSeconds()); }
}
function updateUI() {
var rects = svg.selectAll(".packet")
.data(queue.slice(0, limit + 1), function (d) { return d; });
// restyle existing packets
rects.transition()
.call(stylePacket);
// add new packets
rects.enter().append("rect")
.attr("class", "packet")
.attr("width", packetWidth)
.attr("height", packetHeight)
.attr("x", -packetWidth)
.attr("y", packetPadding)
.transition()
.call(stylePacket);
// get ride of old packets
rects.exit()
.transition()
.attr("x", w + 1000)
.remove();
}
var notShown = d3.select("#chart").append("p")
.html("&nbsp;")
.attr("class", "notshown");
function updateNotShown() {
if (queue.length > limit) {
notShown.text((queue.length - limit) + " not shown");
} else {
notShown.html("&nbsp;");
}
}
// start the simulation
schedulePoisson(packetArrival, arrivalRatePerSecond());
});
function stylePacket(packet) {
packet
.ease('cubic-out')
.attr("x", function (d, i) { return w - (packetWidth + packetPadding) * (i + 1); })
.attr("fill", function (d, i) { return i === 0 ? "blue" : color(i); });
};
function averageServiceTimeInSeconds() {
return +d3.select("#ts").node().value;
}
function arrivalRatePerSecond() {
return +d3.select("#arr").node().value;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment