Skip to content

Instantly share code, notes, and snippets.

@sente
Forked from mbostock/.block
Last active December 19, 2015 07:28
Show Gist options
  • Save sente/5918485 to your computer and use it in GitHub Desktop.
Save sente/5918485 to your computer and use it in GitHub Desktop.

This histogram shows the distribution of GitHub Gist API response times (in milliseconds) for a sample of 10,000 requests as observed by bl.ocks.org.

The distribution roughly follows a log-normal distribution, which is unsurprising for a complex process that has multiple independently-random sources of delay. The mode response time was in the range 120-140ms, while the median response time was 206ms. The middle 80% of requests were in the range 114-527ms. About 11% of requests took longer than 500ms, and 5% of requests took longer than one second. (The rightmost bin in the histogram includes these long requests.)

Since API endpoints vary dramatically in their computational cost, the distribution of response times is likely multimodal. In this dataset, 96% of requests were for a single gist (/gists/42), while the remaining 4% of requests were to list a user’s gist (/users/fred/gists). By separating the API requests for a single gist (shown in light blue) from listing a user’s gists (shown in dark blue), we see that the cause for the slow requests is not random but a function of the endpoint! The response time distribution to list a user’s gists is significantly slower than querying a single gist.

This data was collected by from the bl.ocks.org Heroku app via cube-logplex and queried via Cube.

x dx a b
20 20 202 202
40 20 410 410
60 20 355 355
80 20 225 225
100 20 236 236
120 20 260 260
140 20 233 233
160 20 209 209
180 20 182 182
200 20 155 155
220 20 145 145
240 20 215 215
260 20 145 145
280 20 195 195
300 20 242 242
320 20 172 172
340 20 181 181
360 20 133 133
380 20 138 138
400 20 159 159
420 20 137 137
440 20 184 184
460 20 111 111
480 20 129 129
500 20 154 154
520 20 172 172
540 20 138 138
560 20 199 199
580 20 166 166
600 20 116 116
620 20 130 130
640 20 151 151
660 20 157 157
680 20 222 222
700 20 174 174
720 20 150 150
740 20 105 105
760 20 94 94
780 20 194 194
800 20 129 129
820 20 123 123
840 20 132 132
860 20 147 147
880 20 123 123
900 20 122 122
920 20 111 111
940 20 137 137
960 20 169 169
980 20 150 150
1000 20 190 190
1020 20 136 136
1040 20 138 138
1060 20 168 168
1080 20 152 152
1100 20 131 131
1120 20 153 153
1140 20 117 117
1160 20 123 123
1180 20 158 158
1200 20 210 210
1220 20 234 234
1240 20 289 289
1260 20 339 339
1280 20 263 263
1300 20 226 226
1320 20 254 254
1340 20 256 256
1360 20 263 263
1380 20 204 204
1400 20 234 234
1420 20 252 252
1440 20 225 225
1460 20 279 279
1480 20 257 257
1500 20 241 241
1520 20 198 198
1540 20 207 207
1560 20 173 173
1580 20 182 182
1600 20 274 274
1620 20 251 251
1640 20 239 239
1660 20 309 309
1680 20 292 292
1700 20 245 245
1720 20 219 219
1740 20 227 227
1760 20 221 221
1780 20 245 245
1800 20 251 251
1820 20 263 263
1840 20 234 234
1860 20 279 279
1880 20 256 256
1900 20 235 235
1920 20 241 241
1940 20 198 198
1960 20 283 283
1980 20 224 224
2000 20 354 354
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.bar rect {
fill: #1f77b4;
shape-rendering: crispEdges;
}
.bar .a {
fill: #aec7e8;
}
.bar text {
text-anchor: end;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var formatPercent = d3.format(".1%");
var margin = {top: 10, right: 30, bottom: 30, left: 30},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([0, 1000])
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
d3.tsv("histogram.tsv", type, function(error, histogram) {
var n = d3.sum(histogram, function(d) { return d.y = d.a + d.b; });
y.domain([0, d3.max(histogram, function(d) { return d.y; })]);
var bar = svg.insert("g", ".axis")
.attr("class", "bar")
.selectAll("g")
.data(histogram)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x(d.x) + ",0)"; });
bar.append("rect")
.attr("class", "b")
.attr("x", 1)
.attr("y", function(d) { return y(d.b); })
.attr("width", x(histogram[0].dx) - 1)
.attr("height", function(d) { return height - y(d.b); });
bar.append("rect")
.attr("class", "a")
.attr("x", 1)
.attr("y", function(d) { return y(d.y); })
.attr("width", x(histogram[0].dx) - 1)
.attr("height", function(d) { return height - y(d.a); });
bar.filter(function(d) { return d.y / n >= .0095; }).append("text")
.attr("dy", ".35em")
.attr("transform", function(d) { return "translate(" + x(histogram[0].dx) / 2 + "," + (y(d.y) + 6) + ")rotate(-90)"; })
.text(function(d) { return formatPercent(d.y / n); });
});
function type(d) {
d.x = +d.x;
d.dx = +d.dx;
d.a = +d.a;
d.b = +d.b;
return d;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment