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 |