Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 //
2 // NBody adapted from Intel's nbody benchmark.
3 //
5 load(libdir + "util.js");
6 load(libdir + "seedrandom.js");
8 var NBody = {
9 Constant: {
10 "deltaTime": 1, // 0.005 in their code.
11 "epsSqr": 50, // softening factor, when they compute, set to 50.
12 "initialVelocity": 8 // set to 0 to turn off
13 },
15 init: function init(mode, numBodies) {
16 var initPos = new Array(numBodies);
17 var initVel = new Array(numBodies);
19 // initialization of inputs
20 for (var i = 0; i < numBodies; i++) {
21 // [x,y,z]
22 initPos[i] = [Math.floor((Math.random()) * 40000),
23 Math.floor((Math.random()) * 20000),
24 Math.floor((Math.random() - .25) * 50000)];
26 // [x,y,z,x,y,z]
27 initVel[i] = [(Math.random() - 0.5) * NBody.Constant.initialVelocity,
28 (Math.random() - 0.5) * NBody.Constant.initialVelocity,
29 (Math.random()) * NBody.Constant.initialVelocity + 10,
31 (Math.random() - 0.5) * NBody.Constant.initialVelocity,
32 (Math.random() - 0.5) * NBody.Constant.initialVelocity,
33 (Math.random()) * NBody.Constant.initialVelocity];
34 }
36 NBody.private = {};
38 if (mode === "par") {
39 NBody.private.pos = new ParallelArray(initPos);
40 NBody.private.vel = new ParallelArray(initVel);
41 } else {
42 NBody.private.pos = initPos;
43 NBody.private.vel = initVel;
44 }
46 NBody.numBodies = numBodies;
47 NBody.time = 0;
48 },
50 // Parallel
52 tickPar: function tickPar() {
53 NBody.private.vel = new ParallelArray([NBody.numBodies], NBody.velocityPar);
54 NBody.private.pos = new ParallelArray([NBody.numBodies], NBody.positionPar);
55 NBody.time++;
56 },
58 velocityPar: function velocityPar(index) {
59 var pos = NBody.private.pos;
60 var vel = NBody.private.vel;
62 var deltaTime = NBody.Constant.deltaTime;
63 var epsSqr = NBody.Constant.epsSqr;
64 var time = NBody.time;
66 var shape = vel.shape[0];
68 var newVel;
69 var newX, newY, newZ;
70 var newX2, newY2, newZ2;
72 var cX = Math.cos(time / 22) * -4200;
73 var cY = Math.sin(time / 14) * 9200;
74 var cZ = Math.sin(time / 27) * 6000;
76 // pull to center
77 var maxDistance = 3400;
78 var pullStrength = .042;
80 var speedLimit = 8;
82 // zones
83 var zone = 400;
84 var repel = 100;
85 var align = 300;
86 var attract = 100;
88 if (time < 500) {
89 speedLimit = 2000;
90 var attractPower = 100.9;
91 } else {
92 speedLimit = .2;
93 attractPower = 20.9;
94 }
96 var zoneSqrd = zone * zone + zone * zone + zone * zone;
98 var accX = 0, accY = 0, accZ = 0;
99 var accX2 = 0, accY2 = 0, accZ2 = 0;
100 var i;
102 // define particle 1 center distance
103 var dirToCenterX = cX - pos.get(index)[0];
104 var dirToCenterY = cY - pos.get(index)[1];
105 var dirToCenterZ = cZ - pos.get(index)[2];
107 var distanceSquaredTo = dirToCenterX * dirToCenterX + dirToCenterY * dirToCenterY + dirToCenterZ * dirToCenterZ;
108 var distToCenter = Math.sqrt(distanceSquaredTo);
110 // orient to center
111 if (distToCenter > maxDistance) {
112 var velc = (distToCenter - maxDistance) * pullStrength;
113 if (time < 200)
114 velc = .2;
115 else velc = (distToCenter - maxDistance) * pullStrength;
117 accX += (dirToCenterX / distToCenter) * velc;
118 accY += (dirToCenterY / distToCenter) * velc;
119 accZ += (dirToCenterZ / distToCenter) * velc;
120 }
122 for (i = 0; i < shape; i = i + 1) {
123 var rx = pos.get(i)[0] - pos.get(index)[0];
124 var ry = pos.get(i)[1] - pos.get(index)[1];
125 var rz = pos.get(i)[2] - pos.get(index)[2];
127 // make sure we are not testing the particle against its own position
128 var areSame = 0;
129 if (pos.get(i)[0] == pos.get(index)[0] && pos.get(i)[1] == pos.get(index)[1] && pos.get(i)[2] == pos.get(index)[2])
130 areSame += 1;
132 var distSqrd = rx * rx + ry * ry + rz * rz;
134 // cant use eqals to test, only <= or >= WTF
135 if (distSqrd < zoneSqrd && areSame <= 0) {
136 var length = Math.sqrt(distSqrd);
137 var percent = distSqrd / zoneSqrd;
139 if (distSqrd < repel) {
140 var F = (repel / percent - 1) * .025;
142 var normalRx = (rx / length) * F;
143 var normalRy = (ry / length) * F;
144 var normalRz = (rz / length) * F;
146 accX = accX + normalRx;
147 accY = accY + normalRy;
148 accZ = accZ + normalRz;
150 accX2 = accX2 - normalRx;
151 accY2 = accY2 - normalRy;
152 accZ2 = accZ2 - normalRz;
153 } else if (distSqrd < align) { //align
154 var threshDelta = align - repel;
155 var adjustedPercent = (percent - repel) / threshDelta;
156 var Q = (.5 - Math.cos(adjustedPercent * 3.14159265 * 2) * .5 + .5) * 100.9;
158 // get velocity 2
159 var velX2 = vel.get(i)[4];
160 var velY2 = vel.get(i)[5];
161 var velZ2 = vel.get(i)[6];
163 var velLength2 = Math.sqrt(velX2 * velX2 + velY2 * velY2 + velZ2 * velZ2);
165 // normalize vel2 and multiply by factor
166 velX2 = (velX2 / velLength2) * Q;
167 velY2 = (velY2 / velLength2) * Q;
168 velZ2 = (velZ2 / velLength2) * Q;
170 // get own velocity
171 var velX = vel.get(i)[0];
172 var velY = vel.get(i)[1];
173 var velZ = vel.get(i)[2];
175 var velLength = Math.sqrt(velX * velX + velY * velY + velZ * velZ);
177 // normalize own velocity
178 velX = (velX / velLength) * Q;
179 velY = (velY / velLength) * Q;
180 velZ = (velZ / velLength) * Q;
182 accX += velX2;
183 accY += velY2;
184 accZ += velZ2;
186 accX2 += velX;
187 accY2 += velY;
188 accZ2 += velZ;
189 }
191 if (distSqrd > attract) { // attract
192 var threshDelta2 = 1 - attract;
193 var adjustedPercent2 = (percent - attract) / threshDelta2;
194 var C = (1 - (Math.cos(adjustedPercent2 * 3.14159265 * 2) * 0.5 + 0.5)) * attractPower;
196 // normalize the distance vector
197 var dx = (rx / (length)) * C;
198 var dy = (ry / (length)) * C;
199 var dz = (rz / (length)) * C;
201 accX += dx;
202 accY += dy;
203 accZ += dz;
205 accX2 -= dx;
206 accY2 -= dy;
207 accZ2 -= dz;
208 }
209 }
210 }
212 // Speed limits
213 if (time > 500) {
214 var accSquared = accX * accX + accY * accY + accZ * accZ;
215 if (accSquared > speedLimit) {
216 accX = accX * .015;
217 accY = accY * .015;
218 accZ = accZ * .015;
219 }
221 var accSquared2 = accX2 * accX2 + accY2 * accY2 + accZ2 * accZ2;
222 if (accSquared2 > speedLimit) {
223 accX2 = accX2 * .015;
224 accY2 = accY2 * .015;
225 accZ2 = accZ2 * .015;
226 }
227 }
229 // Caclulate new velocity
230 newX = (vel.get(index)[0]) + accX;
231 newY = (vel.get(index)[1]) + accY;
232 newZ = (vel.get(index)[2]) + accZ;
234 newX2 = (vel.get(index)[3]) + accX2;
235 newY2 = (vel.get(index)[4]) + accY2;
236 newZ2 = (vel.get(index)[5]) + accZ2;
238 if (time < 500) {
239 var acs = newX2 * newX2 + newY2 * newY2 + newZ2 * newZ2;
240 if (acs > speedLimit) {
241 newX2 = newX2 * .15;
242 newY2 = newY2 * .15;
243 newZ2 = newZ2 * .15;
244 }
246 var acs2 = newX * newX + newY * newY + newZ * newZ;
247 if (acs2 > speedLimit) {
248 newX = newX * .15;
249 newY = newY * .15;
250 newZ = newZ * .15;
251 }
252 }
254 return [newX, newY, newZ, newX2, newY2, newZ2];
255 },
257 positionPar: function positionPar(index) {
258 var vel = NBody.private.vel;
259 var pos = NBody.private.pos;
261 var x = 0;
262 var y = 0;
263 var z = 0;
265 var velX = vel.get(index)[0];
266 var velY = vel.get(index)[1];
267 var velZ = vel.get(index)[2];
269 var velX2 = vel.get(index)[3];
270 var velY2 = vel.get(index)[4];
271 var velZ2 = vel.get(index)[5];
273 var netVelX = (velX - velX2);
274 var netVelY = (velY - velY2);
275 var netVelZ = (velZ - velZ2);
277 x = pos.get(index)[0] + (netVelX);
278 y = pos.get(index)[1] + (netVelY);
279 z = pos.get(index)[2] + (netVelZ);
281 return [x, y, z];
282 },
284 // Sequential
286 tickSeq: function tickSeq() {
287 var numBodies = NBody.numBodies;
288 var newVel = new Array(numBodies);
289 var newPos = new Array(numBodies);
291 for (var i = 0; i < numBodies; i++)
292 newVel[i] = NBody.velocitySeq(i);
294 for (var i = 0; i < numBodies; i++)
295 newPos[i] = NBody.positionSeq(i);
297 NBody.private.vel = newVel;
298 NBody.private.pos = newPos;
300 NBody.time++;
301 },
303 velocitySeq: function velocitySeq(index) {
304 var vel = NBody.private.vel;
305 var pos = NBody.private.pos;
307 var deltaTime = NBody.Constant.deltaTime;
308 var epsSqr = NBody.Constant.epsSqr;
309 var time = NBody.time;
311 var shape = pos.length;
313 var newVel;
314 var newX, newY, newZ;
315 var newX2, newY2, newZ2;
317 var cX = Math.cos(time / 22) * -4200;
318 var cY = Math.sin(time / 14) * 9200;
319 var cZ = Math.sin(time / 27) * 6000;
321 // pull to center
322 var maxDistance = 3400;
323 var pullStrength = .042;
325 var speedLimit = 8;
327 // zones
328 var zone = 400;
329 var repel = 100;
330 var align = 300;
331 var attract = 100;
334 if (time < 500) {
335 speedLimit = 2000;
336 var attractPower = 100.9;
337 } else {
338 speedLimit = .2;
339 attractPower = 20.9;
340 }
342 var zoneSqrd = zone * zone + zone * zone + zone * zone;
344 var accX = 0, accY = 0, accZ = 0;
345 var accX2 = 0, accY2 = 0, accZ2 = 0;
346 var i;
348 // define particle 1 center distance
349 var dirToCenterX = cX - pos[index][0];
350 var dirToCenterY = cY - pos[index][1];
351 var dirToCenterZ = cZ - pos[index][2];
353 var distanceSquaredTo = dirToCenterX * dirToCenterX + dirToCenterY * dirToCenterY + dirToCenterZ * dirToCenterZ;
354 var distToCenter = Math.sqrt(distanceSquaredTo);
356 // orient to center
357 if (distToCenter > maxDistance) {
358 var velc = (distToCenter - maxDistance) * pullStrength;
359 if (time < 200)
360 velc = .2;
361 else velc = (distToCenter - maxDistance) * pullStrength;
363 accX += (dirToCenterX / distToCenter) * velc;
364 accY += (dirToCenterY / distToCenter) * velc;
365 accZ += (dirToCenterZ / distToCenter) * velc;
366 }
368 for (i = 0; i < shape; i = i + 1) {
369 var rx = pos[i][0] - pos[index][0];
370 var ry = pos[i][1] - pos[index][1];
371 var rz = pos[i][2] - pos[index][2];
373 var areSame = 0;
374 if (pos[i][0] == pos[index][0] && pos[i][1] == pos[index][1] && pos[i][2] == pos[index][2])
375 areSame += 1;
377 var distSqrd = rx * rx + ry * ry + rz * rz;
379 // cant use eqals to test, only <= or >= WTF
380 if (distSqrd < zoneSqrd && areSame <= 0) {
381 var length = Math.sqrt(distSqrd);
382 var percent = distSqrd / zoneSqrd;
385 if (distSqrd < repel) {
386 var F = (repel / percent - 1) * .025;
388 var normalRx = (rx / length) * F;
389 var normalRy = (ry / length) * F;
390 var normalRz = (rz / length) * F;
392 accX = accX + normalRx;
393 accY = accY + normalRy;
394 accZ = accZ + normalRz;
396 accX2 = accX2 - normalRx;
397 accY2 = accY2 - normalRy;
398 accZ2 = accZ2 - normalRz;
399 } else if (distSqrd < align) { //align
400 var threshDelta = align - repel;
401 var adjustedPercent = (percent - repel) / threshDelta;
402 var Q = (.5 - Math.cos(adjustedPercent * 3.14159265 * 2) * .5 + .5) * 100;
404 // get velocity 2
405 var velX2 = vel[i][3];
406 var velY2 = vel[i][4];
407 var velZ2 = vel[i][5];
409 var velLength2 = Math.sqrt(velX2 * velX2 + velY2 * velY2 + velZ2 * velZ2);
411 // normalize vel2 and multiply by factor
412 velX2 = (velX2 / velLength2) * Q;
413 velY2 = (velY2 / velLength2) * Q;
414 velZ2 = (velZ2 / velLength2) * Q;
416 // get own velocity
417 var velX = vel[i][0];
418 var velY = vel[i][1];
419 var velZ = vel[i][2];
421 var velLength = Math.sqrt(velX * velX + velY * velY + velZ * velZ);
423 // normalize own velocity
424 velX = (velX / velLength) * Q;
425 velY = (velY / velLength) * Q;
426 velZ = (velZ / velLength) * Q;
428 accX += velX2;
429 accY += velY2;
430 accZ += velZ2;
432 accX2 += velX;
433 accY2 += velY;
434 accZ2 += velZ;
435 }
437 if (distSqrd > attract) { //attract
438 var threshDelta2 = 1 - align;
439 var adjustedPercent2 = (percent - align) / threshDelta2;
440 var C = (1 - (Math.cos(adjustedPercent2 * 3.14159265 * 2) * 0.5 + 0.5)) * attractPower;
442 // normalize the distance vector
443 var dx = (rx / (length)) * C;
444 var dy = (ry / (length)) * C;
445 var dz = (rz / (length)) * C;
447 debug = 1.1;
449 accX += dx;
450 accY += dy;
451 accZ += dz;
453 accX2 -= dx;
454 accY2 -= dy;
455 accZ2 -= dz;
456 }
457 }
458 }
460 // enforce speed limits
461 if (time > 500) {
462 var accSquared = accX * accX + accY * accY + accZ * accZ;
463 if (accSquared > speedLimit) {
464 accX = accX * .015;
465 accY = accY * .015;
466 accZ = accZ * .015;
467 }
469 var accSquared2 = accX2 * accX2 + accY2 * accY2 + accZ2 * accZ2;
470 if (accSquared2 > speedLimit) {
471 accX2 = accX2 * .015;
472 accY2 = accY2 * .015;
473 accZ2 = accZ2 * .015;
474 }
475 }
477 // Caclulate new velocity
478 newX = vel[index][0] + accX;
479 newY = vel[index][1] + accY;
480 newZ = vel[index][2] + accZ;
482 newX2 = vel[index][3] + accX2;
483 newY2 = vel[index][4] + accY2;
484 newZ2 = vel[index][5] + accZ2;
486 if (time < 500) {
487 var acs = newX2 * newX2 + newY2 * newY2 + newZ2 * newZ2;
488 if (acs > speedLimit) {
489 newX2 = newX2 * .15;
490 newY2 = newY2 * .15;
491 newZ2 = newZ2 * .15;
492 }
494 var acs2 = newX * newX + newY * newY + newZ * newZ;
495 if (acs2 > speedLimit) {
496 newX = newX * .15;
497 newY = newY * .15;
498 newZ = newZ * .15;
499 }
500 }
502 return [newX, newY, newZ, newX2, newY2, newZ2];
503 },
505 positionSeq: function positionSeq(index) {
506 var vel = NBody.private.vel;
507 var pos = NBody.private.pos;
509 var x = 0;
510 var y = 0;
511 var z = 0;
513 var velX = vel[index][0];
514 var velY = vel[index][1];
515 var velZ = vel[index][2];
517 var velX2 = vel[index][3];
518 var velY2 = vel[index][4];
519 var velZ2 = vel[index][5];
521 var netX = (velX - velX2);
522 var netY = (velY - velY2);
523 var netZ = (velZ - velZ2);
525 x = pos[index][0] + netX;
526 y = pos[index][1] + netY;
527 z = pos[index][2] + netZ;
529 return [x, y, z];
530 }
531 };
533 function emulateNBody(mode, numBodies, ticks) {
534 NBody.init(mode, numBodies);
535 for (var i = 0; i < ticks; i++) {
536 var start = Date.now();
537 if (mode === "par")
538 NBody.tickPar();
539 else
540 NBody.tickSeq();
541 //print(NBody.private.pos);
542 print(mode + " bodies=" + numBodies + " tick=" + (i+1) + "/" + ticks + ": " + (Date.now() - start) + " ms");
543 }
544 }
546 // Using 4000 bodies going off Rick's comment as 4000 being a typical workload.
547 const NUMBODIES = 4000;
548 const TICKS = 10;
550 Math.seedrandom("seed");
552 benchmark("NBODY", 1, DEFAULT_MEASURE,
553 function () { emulateNBody("seq", NUMBODIES, TICKS); },
554 function () { emulateNBody("par", NUMBODIES, TICKS); });