| OLD | NEW |
| (Empty) |
| 1 // sort object | |
| 2 | |
| 3 var manual = 0; // single stepping | |
| 4 var interval_time = 0; // setTimeout interval | |
| 5 var inner_loop_enabled = 1; // should the stepper iterate a little during each s
tep | |
| 6 | |
| 7 // number of elements | |
| 8 var size = 300; | |
| 9 var query = window.location.search.substring(1); | |
| 10 var params = query.split('&'); | |
| 11 for (var i = 0; i < params.length; i++) { | |
| 12 var pos = params[i].indexOf('='); | |
| 13 var key = params[i].substring(0, pos); | |
| 14 var val = params[i].substring(pos+1); | |
| 15 if (key == "size") { | |
| 16 var sz = parseInt(val); | |
| 17 size = Math.max(sz, 3); | |
| 18 size = Math.min(1000, size); | |
| 19 } | |
| 20 } | |
| 21 | |
| 22 var log; | |
| 23 function log(msg) { | |
| 24 if (window.console != undefined) { | |
| 25 window.console.log(msg); | |
| 26 } | |
| 27 } | |
| 28 | |
| 29 function Sort(name, func) { | |
| 30 this.name = name; | |
| 31 this.func = func; | |
| 32 this.size = size; | |
| 33 this.compare_x = null; | |
| 34 this.compare_y = null; | |
| 35 this.compares = 0; | |
| 36 this.swap_x = null; | |
| 37 this.swap_y = null; | |
| 38 this.swaps = 0; | |
| 39 this.start_time = 0; | |
| 40 this.stop_time = 0; | |
| 41 this.work_queue = new Array(); | |
| 42 this.timer = 0; | |
| 43 this.last_time = 0; | |
| 44 this.num_iterations = 0; | |
| 45 this.num_jobs = 0; | |
| 46 this.overhead_total = 0; | |
| 47 this.overhead_min = 1000000; | |
| 48 this.overhead_max = 0; | |
| 49 this.processing_total = 0; | |
| 50 this.processing_min = 1000000; | |
| 51 this.processing_max = 0; | |
| 52 this.step_min = 1000000; | |
| 53 this.step_max = 0; | |
| 54 | |
| 55 this.setup(); | |
| 56 } | |
| 57 | |
| 58 Sort.prototype.setup = function() { | |
| 59 this.size = size; | |
| 60 this.bars = new Array(this.size); | |
| 61 this.numbers = new Array(this.size); | |
| 62 for (i = 0; i < this.size; i++) { | |
| 63 this.numbers[i] = i + 1; | |
| 64 } | |
| 65 for (i = 0; i < this.size; i++) { | |
| 66 var r = Math.floor(Math.random() * this.numbers.length); | |
| 67 if (i != r) { | |
| 68 var tmp = this.numbers[i]; | |
| 69 this.numbers[i] = this.numbers[r]; | |
| 70 this.numbers[r] = tmp; | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 Sort.prototype.status = function(str) { | |
| 76 var label = document.getElementById(this.name + "_label"); | |
| 77 label.innerHTML = "<b>" + this.name + " Sort</b><br />" + str; | |
| 78 } | |
| 79 | |
| 80 Sort.prototype.stepper = function() { | |
| 81 if (!manual) { | |
| 82 var sort = this; | |
| 83 this.timer = setTimeout(function(){sort.stepper();},interval_time); | |
| 84 } | |
| 85 var t = new Date(); | |
| 86 var overhead = t - this.last_time; | |
| 87 this.overhead_total += overhead; | |
| 88 this.overhead_min = Math.min(this.overhead_min, overhead); | |
| 89 this.overhead_max = Math.max(this.overhead_max, overhead); | |
| 90 this.last_time = t; | |
| 91 | |
| 92 var elapsed = t - this.start_time; | |
| 93 var avg = | |
| 94 Math.floor((elapsed - this.processing_total) / this.num_iterations); | |
| 95 this.status("Overhead: " + avg + "ms"); | |
| 96 | |
| 97 var ops = 0; | |
| 98 for (;;) { | |
| 99 var count = this.work_queue.length; | |
| 100 if (count > 0) { | |
| 101 var func = this.work_queue.pop(); | |
| 102 if (func.status != undefined) { | |
| 103 //this.status(func.status); | |
| 104 } | |
| 105 ops++; | |
| 106 this.num_jobs++; | |
| 107 func(); | |
| 108 } else { | |
| 109 break; | |
| 110 } | |
| 111 if (manual || inner_loop_enabled == 0) { | |
| 112 break; | |
| 113 } | |
| 114 t = new Date(); | |
| 115 // If any measurable time has passed, we're good. | |
| 116 // Since the Date has a resolution of 15ms on Windows | |
| 117 // there's no way to differentiate accurately for anything | |
| 118 // less than that. We don't want to process for longer than | |
| 119 // the timer interval anyway (which is about 10ms), so this | |
| 120 // is fine. | |
| 121 // NOTE: on non-windows platforms, this actually does matter since | |
| 122 // their timer resolution is higher | |
| 123 // TODO(erikkay): make this a parameter | |
| 124 if (t - this.last_time > 10) { | |
| 125 break; | |
| 126 } | |
| 127 } | |
| 128 var processing = t - this.last_time; | |
| 129 this.processing_min = Math.min(this.processing_min, processing); | |
| 130 this.processing_max = Math.max(this.processing_max, processing); | |
| 131 this.processing_total += processing; | |
| 132 var step_time = processing + overhead; | |
| 133 this.step_min = Math.min(this.step_min, step_time); | |
| 134 this.step_max = Math.max(this.processing_max, step_time); | |
| 135 this.num_iterations++; | |
| 136 this.last_time = new Date(); | |
| 137 | |
| 138 if (ops == 0) { | |
| 139 this.finished(); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 Sort.prototype.add_work = function(work, name) { | |
| 144 if (name != undefined) { | |
| 145 work.status = name; | |
| 146 } | |
| 147 this.work_queue.push(work); | |
| 148 } | |
| 149 | |
| 150 Sort.prototype.init = function() { | |
| 151 this.print(); | |
| 152 this.status(""); | |
| 153 } | |
| 154 | |
| 155 Sort.prototype.reset = function() { | |
| 156 this.stop(); | |
| 157 this.start_time = 0; | |
| 158 this.stop_time = 0; | |
| 159 this.setup(); | |
| 160 this.print(); | |
| 161 } | |
| 162 | |
| 163 Sort.prototype.start = function() { | |
| 164 if (this.start_time > 0) { | |
| 165 if (this.stop_time > 0) { | |
| 166 this.shuffle(); | |
| 167 this.start_time = 0; | |
| 168 this.stop_time = 0; | |
| 169 this.status(""); | |
| 170 return; | |
| 171 } else if (manual) { | |
| 172 this.stepper(); | |
| 173 return; | |
| 174 } else { | |
| 175 this.finished(); | |
| 176 return; | |
| 177 } | |
| 178 } | |
| 179 if (!manual) { | |
| 180 var t = this; | |
| 181 this.timer = setTimeout(function(){t.stepper();},interval_time); | |
| 182 } | |
| 183 this.compares = 0; | |
| 184 this.swaps = 0; | |
| 185 this.start_time = (new Date()).getTime(); | |
| 186 this.last_time = this.start_time; | |
| 187 this.num_jobs = 0; | |
| 188 this.stop_time = 0; | |
| 189 this.overhead_total = 0; | |
| 190 this.overhead_min = 1000000; | |
| 191 this.overhead_max = 0; | |
| 192 this.processing_total = 0; | |
| 193 this.processing_min = 1000000; | |
| 194 this.processing_max = 0; | |
| 195 this.num_iterations = 0; | |
| 196 this.func(this); | |
| 197 } | |
| 198 | |
| 199 Sort.prototype.cleanup = function() { | |
| 200 if (this.compare_x) { | |
| 201 this.compare_x.style.borderColor = "black"; | |
| 202 this.compare_y.style.borderColor = "black"; | |
| 203 } | |
| 204 if (this.swap_x) { | |
| 205 this.swap_x.style.backgroundColor = "green"; | |
| 206 this.swap_y.style.backgroundColor = "green"; | |
| 207 } | |
| 208 this.work_queue = new Array(); | |
| 209 } | |
| 210 | |
| 211 Sort.prototype.stop = function() { | |
| 212 if (this.timer != 0) { | |
| 213 clearTimeout(this.timer); | |
| 214 this.timer = 0; | |
| 215 } | |
| 216 this.cleanup(); | |
| 217 } | |
| 218 | |
| 219 Sort.prototype.finished = function(err) { | |
| 220 this.stop(); | |
| 221 | |
| 222 this.stop_time = (new Date()).getTime(); | |
| 223 | |
| 224 var total = (this.stop_time - this.start_time); | |
| 225 if (err == null) { | |
| 226 var step_avg = Math.floor(total / this.num_iterations); | |
| 227 var overhead = total - this.processing_total; | |
| 228 var overhead_avg = Math.floor(overhead / this.num_iterations); | |
| 229 var processing_avg = Math.floor(this.processing_total / this.num_iterations)
; | |
| 230 var table = "<table><tr><td>Times(ms)</td><td>Total</td><td>Avg</td><td>Max<
/td></tr>" | |
| 231 + "<tr><td>Total</td><td>" + total + "</td><td>" + step_avg + "</td><td>"
+ this.step_max + "</tr>" | |
| 232 + "<tr><td>Work</td><td>" + this.processing_total + "</td><td>" + processi
ng_avg + "</td><td>" + this.processing_max + "</tr>" | |
| 233 + "<tr><td>Overhead</td><td>" + overhead + "</td><td>" + overhead_avg + "<
/td><td>" + this.overhead_max + "</tr>" | |
| 234 + "</table>"; | |
| 235 this.status(table); | |
| 236 } else { | |
| 237 this.status(err); | |
| 238 log("error: " + err); | |
| 239 } | |
| 240 log("finished in: " + total); | |
| 241 } | |
| 242 | |
| 243 Sort.prototype.shuffle = function() { | |
| 244 for (i = 0; i < this.size; i++) { | |
| 245 var r = Math.floor(Math.random() * this.size); | |
| 246 if (i != r) { | |
| 247 this.swap(i,r); | |
| 248 } | |
| 249 } | |
| 250 this.cleanup(); | |
| 251 } | |
| 252 | |
| 253 Sort.prototype.print = function() { | |
| 254 var graph = document.getElementById(this.name); | |
| 255 if (graph == undefined) { | |
| 256 alert("can't find " + this.name); | |
| 257 } | |
| 258 var text = "<div id='" + this.name + "_label' class='label'>" + this.name + "
Sort</div>"; | |
| 259 var len = this.numbers.length; | |
| 260 var height_multiple = (graph.clientHeight-20) / len; | |
| 261 var width = Math.max(1,Math.floor((graph.clientWidth-10) / len)); | |
| 262 if (width < 3) { | |
| 263 border = 0; | |
| 264 } else { | |
| 265 border = 1; | |
| 266 } | |
| 267 var left_offset = Math.round((graph.clientWidth - (width*len))/2); | |
| 268 for (i = 0; i < len; i++) { | |
| 269 var val = this.numbers[i]; | |
| 270 var height = Math.max(1, Math.floor(val * height_multiple)); | |
| 271 var left = left_offset + i * width; | |
| 272 text += "<li class='bar' style='border: " + border + "px solid black; height
:" + height + "px; left:" + left + "; width:" + width + "' id='" + this.name + v
al + "' value='" + val + "'></li>"; | |
| 273 } | |
| 274 graph.innerHTML = text; | |
| 275 var nodes = document.getElementsByTagName("li"); | |
| 276 var j = 0; | |
| 277 for (i = 0; i < nodes.length; i++) { | |
| 278 var name = nodes[i].id; | |
| 279 if (name.indexOf(this.name) == 0) { | |
| 280 this.bars[j] = nodes[i]; | |
| 281 j++; | |
| 282 } | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 Sort.prototype.compare = function(x, y) { | |
| 287 var bx = this.bars[x]; | |
| 288 var by = this.bars[y]; | |
| 289 //log("compare " + x + "(" + bx.value + ")," + y + "(" + by.value + ")"); | |
| 290 if (this.compare_x != bx) { | |
| 291 if (this.compare_x) { | |
| 292 this.compare_x.style.borderColor="black"; | |
| 293 } | |
| 294 bx.style.borderColor="yellow"; | |
| 295 this.compare_x = bx; | |
| 296 } | |
| 297 if (this.compare_y != by) { | |
| 298 if (this.compare_y) { | |
| 299 this.compare_y.style.borderColor="black"; | |
| 300 } | |
| 301 by.style.borderColor="white"; | |
| 302 this.compare_y = by; | |
| 303 } | |
| 304 this.compares++; | |
| 305 return bx.value - by.value; | |
| 306 } | |
| 307 | |
| 308 Sort.prototype.swap = function(x, y) { | |
| 309 var bx = this.bars[x]; | |
| 310 var by = this.bars[y]; | |
| 311 //log("swap " + x + "(" + bx.value + ")," + y + "(" + by.value + ")"); | |
| 312 if (this.swap_x != x) { | |
| 313 if (this.swap_x) { | |
| 314 this.swap_x.style.backgroundColor="green"; | |
| 315 } | |
| 316 bx.style.backgroundColor="blue"; | |
| 317 this.swap_x = bx; | |
| 318 } | |
| 319 if (this.swap_y != y) { | |
| 320 if (this.swap_y) { | |
| 321 this.swap_y.style.backgroundColor="green"; | |
| 322 } | |
| 323 by.style.backgroundColor="red"; | |
| 324 this.swap_y = by; | |
| 325 } | |
| 326 var tmp = bx.style.left; | |
| 327 bx.style.left = by.style.left; | |
| 328 by.style.left = tmp; | |
| 329 this.bars[x] = by; | |
| 330 this.bars[y] = bx; | |
| 331 this.swaps++; | |
| 332 } | |
| 333 | |
| 334 Sort.prototype.insert = function(from, to) { | |
| 335 var bf = this.bars[from]; | |
| 336 if (from > to) { | |
| 337 for (i = from; i > to; i--) { | |
| 338 var b1 = this.bars[i]; | |
| 339 var b2 = this.bars[i-1]; | |
| 340 b2.style.left = b1.style.left; | |
| 341 this.bars[i] = b2; | |
| 342 } | |
| 343 bf.style.left = this.bars[to].style.left; | |
| 344 this.bars[to] = bf; | |
| 345 } else { | |
| 346 // TODO | |
| 347 } | |
| 348 } | |
| OLD | NEW |