├── README ├── ftree.js ├── index.html ├── lib ├── d3.js └── jquery.js └── style.css /README: -------------------------------------------------------------------------------- 1 | A fat tree visualizer in Javascript. 2 | -------------------------------------------------------------------------------- /ftree.js: -------------------------------------------------------------------------------- 1 | $(document).ready(docMain); 2 | 3 | var conf = new Object(); 4 | conf['depth'] = 3; 5 | conf['width'] = 8; 6 | 7 | var controlVisible = true; 8 | 9 | function docMain() { 10 | formInit(); 11 | redraw(); 12 | $(document).keypress(kpress); 13 | } 14 | 15 | function kpress(e) { 16 | if (e.which == 104) { // 'h' 17 | if (controlVisible) { 18 | controlVisible = false; 19 | $("div.control").hide(); 20 | } else { 21 | controlVisible = true; 22 | $("div.control").show(); 23 | } 24 | } 25 | } 26 | 27 | function redraw() { 28 | drawFatTree(conf['depth'], conf['width']); 29 | } 30 | 31 | function drawFatTree(depth, width) { 32 | var k = Math.floor(width / 2); 33 | var padg = 13; 34 | var padi = 12; 35 | var hline = 70; 36 | var hhost = 50; 37 | 38 | var podw = 8; 39 | var podh = 8; 40 | var hostr = 2; 41 | 42 | var kexp = function (n) { return Math.pow(k, n); }; 43 | 44 | d3.select("svg.main").remove(); 45 | if (kexp(depth - 1) > 1500 || depth <= 0 || k <= 0) { 46 | return; 47 | } 48 | 49 | var w = kexp(depth - 1) * padg + 200; 50 | var h = (2 * depth) * hline; 51 | 52 | var svg = d3.select("body").append("svg") 53 | .attr("width", w) 54 | .attr("height", h) 55 | .attr("class", "main") 56 | .append("g") 57 | .attr("transform", "translate(" + w/2 + "," + h/2 + ")"); 58 | 59 | var linePositions = []; 60 | 61 | function podPositions(d) { 62 | var ret = []; 63 | 64 | var ngroup = kexp(d); 65 | var pergroup = kexp(depth - 1 - d); 66 | 67 | var wgroup = pergroup * padg; 68 | var wgroups = wgroup * (ngroup - 1); 69 | var offset = -wgroups/2; 70 | 71 | for (var i = 0; i < ngroup; i++) { 72 | var wpods = pergroup * padi; 73 | var goffset = wgroup * i - wpods/2; 74 | 75 | for (var j = 0; j < pergroup; j++) { 76 | ret.push(offset + goffset + padi * j); 77 | } 78 | } 79 | 80 | return ret 81 | } 82 | 83 | for (var i = 0; i < depth; i++) { 84 | linePositions[i] = podPositions(i); 85 | } 86 | 87 | function drawPods(list, y) { 88 | for (var j = 0, n = list.length; j < n; j++) { 89 | svg.append("rect") 90 | .attr("class", "pod") 91 | .attr("width", podw) 92 | .attr("height", podh) 93 | .attr("x", list[j] - podw/2) 94 | .attr("y", y - podh/2); 95 | } 96 | } 97 | 98 | function drawHost(x, y, dy, dx) { 99 | svg.append("line") 100 | .attr("class", "cable") 101 | .attr("x1", x) 102 | .attr("y1", y) 103 | .attr("x2", x + dx) 104 | .attr("y2", y + dy); 105 | 106 | svg.append("circle") 107 | .attr("class", "host") 108 | .attr("cx", x + dx) 109 | .attr("cy", y + dy) 110 | .attr("r", hostr); 111 | } 112 | 113 | function drawHosts(list, y, direction) { 114 | for (var i = 0; i < list.length; i++) { 115 | if (k == 1) { 116 | drawHost(list[i], y, hhost * direction, 0); 117 | } else if (k == 2) { 118 | drawHost(list[i], y, hhost * direction, -2); 119 | drawHost(list[i], y, hhost * direction, +2); 120 | } else if (k == 3) { 121 | drawHost(list[i], y, hhost * direction, -4); 122 | drawHost(list[i], y, hhost * direction, 0); 123 | drawHost(list[i], y, hhost * direction, +4); 124 | } else { 125 | drawHost(list[i], y, hhost * direction, -4); 126 | drawHost(list[i], y, hhost * direction, 0); 127 | drawHost(list[i], y, hhost * direction, +4); 128 | } 129 | } 130 | } 131 | 132 | function linePods(d, list1, list2, y1, y2) { 133 | var pergroup = kexp(depth - 1 - d); 134 | var ngroup = kexp(d); 135 | 136 | var perbundle = pergroup / k; 137 | 138 | for (var i = 0; i < ngroup; i++) { 139 | var offset = pergroup * i; 140 | for (var j = 0; j < k; j++) { 141 | var boffset = perbundle * j; 142 | for (var t = 0; t < perbundle; t++) { 143 | var ichild = offset + boffset + t; 144 | for (var d = 0; d < k; d++) { 145 | var ifather = offset + perbundle * d + t; 146 | svg.append("line") 147 | .attr("class", "cable") 148 | .attr("x1", list1[ifather]) 149 | .attr("y1", y1) 150 | .attr("x2", list2[ichild]) 151 | .attr("y2", y2); 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | for (var i = 0; i < depth - 1; i++) { 159 | linePods(i, linePositions[i], linePositions[i + 1], i * hline, (i + 1) * hline); 160 | linePods(i, linePositions[i], linePositions[i + 1], -i * hline, -(i + 1) * hline); 161 | } 162 | 163 | drawHosts(linePositions[depth - 1], (depth - 1) * hline, 1); 164 | drawHosts(linePositions[depth - 1], -(depth - 1) * hline, -1); 165 | 166 | for (var i = 0; i < depth; i++) { 167 | if (i == 0) { 168 | drawPods(linePositions[0], 0); 169 | } else { 170 | drawPods(linePositions[i], i * hline); 171 | drawPods(linePositions[i], -i * hline); 172 | } 173 | } 174 | } 175 | 176 | function updateStat() { 177 | var w = Math.floor(conf['width'] / 2); 178 | var d = conf['depth']; 179 | if (d == 0 || w == 0) { 180 | d3.select("#nhost").html(" "); 181 | d3.select("#nswitch").html(" "); 182 | d3.select("#ncable").html(" "); 183 | d3.select("#ntx").html(" "); 184 | d3.select("#nswtx").html(" "); 185 | return; 186 | } 187 | 188 | var line = Math.pow(w, d - 1); 189 | 190 | var nhost = 2 * line * w; 191 | var nswitch = (2 * d - 1) * line; 192 | var ncable = (2 * d) * w * line; 193 | var ntx = 2 * (2 * d) * w * line; 194 | var nswtx = ntx - nhost; 195 | 196 | d3.select("#nhost").html(formatNum(nhost)); 197 | d3.select("#nswitch").html(formatNum(nswitch)); 198 | d3.select("#ncable").html(formatNum(ncable)); 199 | d3.select("#ntx").html(formatNum(ntx)); 200 | d3.select("#nswtx").html(formatNum(nswtx)); 201 | } 202 | 203 | function formatNum(x) { 204 | x = x.toString(); 205 | var pattern = /(-?\d+)(\d{3})/; 206 | while (pattern.test(x)) 207 | x = x.replace(pattern, "$1,$2"); 208 | return x; 209 | } 210 | 211 | function formInit() { 212 | var form = d3.select("form"); 213 | 214 | function confInt() { 215 | conf[this.name] = parseInt(this.value); 216 | updateStat(); 217 | redraw(); 218 | } 219 | 220 | function hook(name, func) { 221 | var fields = form.selectAll("[name=" + name + "]"); 222 | fields.on("change", func); 223 | fields.each(func); 224 | } 225 | 226 | hook("depth", confInt); 227 | hook("width", confInt); 228 | } 229 | 230 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
by He "Lonnie" Liu